PageRenderTime 41ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FluentDOM/Loader/StringJSON.php

http://github.com/ThomasWeinert/FluentDOM
PHP | 133 lines | 77 code | 8 blank | 48 comment | 10 complexity | 6ed882c1983f66816e853e99a713eb14 MD5 | raw file
  1. <?php
  2. /**
  3. * Load FluentDOM from JSON encoded string
  4. *
  5. * @version $Id$
  6. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  7. * @copyright Copyright (c) 2009 Bastian Feder, Thomas Weinert
  8. *
  9. * @package FluentDOM
  10. * @subpackage Loaders
  11. */
  12. /**
  13. * include interface
  14. */
  15. require_once(dirname(__FILE__).'/../Loader.php');
  16. /**
  17. * Load FluentDOM from JSON encoded string
  18. *
  19. * @example json/jsonToXml.php Usage Example: FluentDOMLoaderStringJSON
  20. * @package FluentDOM
  21. * @subpackage Loaders
  22. */
  23. class FluentDOMLoaderStringJSON implements FluentDOMLoader {
  24. /**
  25. * JSON errors
  26. * @var array $jsonErrors
  27. */
  28. private $jsonErrors = array(
  29. -1 => 'Unknown error has occurred',
  30. 0 => 'No error has occurred',
  31. 1 => 'The maximum stack depth has been exceeded',
  32. 3 => 'Control character error, possibly incorrectly encoded',
  33. 4 => 'Syntax error',
  34. );
  35. /**
  36. * Add variable type attributes to the element nodes
  37. * @var string
  38. */
  39. public $typeAttributes = FALSE;
  40. /**
  41. * Load DOMDocument from local XML file
  42. *
  43. * @param string $source json encoded content
  44. * @param string $contentType
  45. * @return DOMNode|NULL
  46. */
  47. public function load($source, &$contentType) {
  48. if (is_string($source)) {
  49. $firstChar = substr(trim($source), 0, 1);
  50. if (in_array($firstChar, array('{', '['))) {
  51. $contentType = 'text/xml';
  52. $json = json_decode($source);
  53. if ($json) {
  54. $dom = new DOMDocument();
  55. $documentElement = $dom->createElement('json');
  56. $dom->appendChild($documentElement);
  57. $this->_toDom($documentElement, $json);
  58. return $documentElement;
  59. } else {
  60. $code = is_callable('json_last_error') ? json_last_error() : -1;
  61. throw new UnexpectedValueException($this->jsonErrors[$code]);
  62. }
  63. }
  64. }
  65. return NULL;
  66. }
  67. /**
  68. * Convert a JSON object structure to a DOMDocument
  69. *
  70. * @param DOMElement $parentNode
  71. * @param mixed $current
  72. * @param integer $maxDepth simple recursion protection
  73. */
  74. private function _toDom($parentNode, $current, $maxDepth = 100) {
  75. if (is_array($current) && $maxDepth > 0) {
  76. foreach ($current as $index => $child) {
  77. $childNode = $this->_addElement($parentNode, $parentNode->tagName.'-child');
  78. $this->_toDom($childNode, $child, $maxDepth - 1);
  79. }
  80. } elseif (is_object($current) && $maxDepth > 0) {
  81. foreach (get_object_vars($current) as $index => $child) {
  82. $childNode = $this->_addElement($parentNode, $index);
  83. $this->_toDom($childNode, $child, $maxDepth - 1);
  84. }
  85. } elseif (is_bool($current)) {
  86. $parentNode->appendChild(
  87. $parentNode->ownerDocument->createTextNode($current ? '1' : '0')
  88. );
  89. } elseif (!empty($current)) {
  90. $parentNode->appendChild(
  91. $parentNode->ownerDocument->createTextNode((string)$current)
  92. );
  93. }
  94. if ($this->typeAttributes) {
  95. $parentNode->setAttribute('type', gettype($current));
  96. }
  97. }
  98. /**
  99. * Add new element, sanitize tag name if nessesary
  100. *
  101. * @param DOMElement $parentNode
  102. * @param string $tagName
  103. */
  104. private function _addElement($parentNode, $tagName) {
  105. $nameStartChar =
  106. 'A-Z_a-z'.
  107. '\\x{C0}-\\x{D6}\\x{D8}-\\x{F6}\\x{F8}-\\x{2FF}\\x{370}-\\x{37D}'.
  108. '\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}'.
  109. '\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}'.
  110. '\\x{FDF0}-\\x{FFFD}\\x{10000}-\\x{EFFFF}';
  111. $nameChar =
  112. $nameStartChar.
  113. '\\.\\d\\x{B7}\\x{300}-\\x{36F}\\x{203F}-\\x{2040}';
  114. $tagNameNormalized = preg_replace(
  115. '((^[^'.$nameStartChar.'])|[^'.$nameChar.'])u', '-', $tagName
  116. );
  117. $childNode = $parentNode->ownerDocument->createElement($tagNameNormalized);
  118. if ($tagNameNormalized != $tagName) {
  119. $childNode->setAttribute('name', $tagName);
  120. }
  121. $parentNode->appendChild($childNode);
  122. return $childNode;
  123. }
  124. }
  125. ?>