1 <?php
2 /**
3 * Part of the Joomla Framework Registry Package
4 *
5 * @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
6 * @license GNU General Public License version 2 or later; see LICENSE
7 */
8
9 namespace Joomla\Registry\Format;
10
11 use Joomla\Registry\AbstractRegistryFormat;
12 use SimpleXMLElement;
13 use stdClass;
14
15 /**
16 * XML format handler for Registry.
17 *
18 * @since 1.0
19 */
20 class Xml extends AbstractRegistryFormat
21 {
22 /**
23 * Converts an object into an XML formatted string.
24 * - If more than two levels of nested groups are necessary, since INI is not
25 * useful, XML or another format should be used.
26 *
27 * @param object $object Data source object.
28 * @param array $options Options used by the formatter.
29 *
30 * @return string XML formatted string.
31 *
32 * @since 1.0
33 */
34 public function objectToString($object, $options = array())
35 {
36 $rootName = (isset($options['name'])) ? $options['name'] : 'registry';
37 $nodeName = (isset($options['nodeName'])) ? $options['nodeName'] : 'node';
38
39 // Create the root node.
40 $root = simplexml_load_string('<' . $rootName . ' />');
41
42 // Iterate over the object members.
43 $this->getXmlChildren($root, $object, $nodeName);
44
45 return $root->asXML();
46 }
47
48 /**
49 * Parse a XML formatted string and convert it into an object.
50 *
51 * @param string $data XML formatted string to convert.
52 * @param array $options Options used by the formatter.
53 *
54 * @return object Data object.
55 *
56 * @since 1.0
57 */
58 public function stringToObject($data, array $options = array())
59 {
60 $obj = new stdClass;
61
62 // Parse the XML string.
63 $xml = simplexml_load_string($data);
64
65 foreach ($xml->children() as $node)
66 {
67 $obj->{$node['name']} = $this->getValueFromNode($node);
68 }
69
70 return $obj;
71 }
72
73 /**
74 * Method to get a PHP native value for a SimpleXMLElement object. -- called recursively
75 *
76 * @param object $node SimpleXMLElement object for which to get the native value.
77 *
78 * @return mixed Native value of the SimpleXMLElement object.
79 *
80 * @since 1.0
81 */
82 protected function getValueFromNode($node)
83 {
84 switch ($node['type'])
85 {
86 case 'integer':
87 $value = (string) $node;
88
89 return (int) $value;
90 break;
91
92 case 'string':
93 return (string) $node;
94 break;
95
96 case 'boolean':
97 $value = (string) $node;
98
99 return (bool) $value;
100 break;
101
102 case 'double':
103 $value = (string) $node;
104
105 return (float) $value;
106 break;
107
108 case 'array':
109 $value = array();
110
111 foreach ($node->children() as $child)
112 {
113 $value[(string) $child['name']] = $this->getValueFromNode($child);
114 }
115
116 break;
117
118 default:
119 $value = new stdClass;
120
121 foreach ($node->children() as $child)
122 {
123 $value->{$child['name']} = $this->getValueFromNode($child);
124 }
125
126 break;
127 }
128
129 return $value;
130 }
131
132 /**
133 * Method to build a level of the XML string -- called recursively
134 *
135 * @param SimpleXMLElement $node SimpleXMLElement object to attach children.
136 * @param object $var Object that represents a node of the XML document.
137 * @param string $nodeName The name to use for node elements.
138 *
139 * @return void
140 *
141 * @since 1.0
142 */
143 protected function getXmlChildren(SimpleXMLElement $node, $var, $nodeName)
144 {
145 // Iterate over the object members.
146 foreach ((array) $var as $k => $v)
147 {
148 if (is_scalar($v))
149 {
150 $n = $node->addChild($nodeName, $v);
151 $n->addAttribute('name', $k);
152 $n->addAttribute('type', gettype($v));
153 }
154 else
155 {
156 $n = $node->addChild($nodeName);
157 $n->addAttribute('name', $k);
158 $n->addAttribute('type', gettype($v));
159
160 $this->getXmlChildren($n, $v, $nodeName);
161 }
162 }
163 }
164 }
165