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