@@ -94,26 +94,27 @@ public function decode($data, $format, array $context = array())
9494 }
9595 }
9696
97- $ xml = simplexml_import_dom ( $ dom) ;
97+ $ rootNode = $ dom-> firstChild ;
9898
99- if ($ error = libxml_get_last_error ()) {
100- throw new UnexpectedValueException ($ error ->message );
99+ // todo: throw an exception if the root node name is not correctly configured (bc)
100+
101+ if ($ rootNode ->hasChildNodes ()) {
102+ return $ this ->parseXml ($ rootNode );
101103 }
102104
103- if (!$ xml ->count ()) {
104- if (!$ xml ->attributes ()) {
105- return (string ) $ xml ;
106- }
107- $ data = array ();
108- foreach ($ xml ->attributes () as $ attrkey => $ attr ) {
109- $ data ['@ ' .$ attrkey ] = (string ) $ attr ;
110- }
111- $ data ['# ' ] = (string ) $ xml ;
105+ if (!$ rootNode ->hasAttributes ()) {
106+ return $ rootNode ->nodeValue ;
107+ }
112108
113- return $ data ;
109+ $ data = array ();
110+
111+ foreach ($ rootNode ->attributes as $ attrKey => $ attr ) {
112+ $ data ['@ ' .$ attrKey ] = $ attr ->nodeValue ;
114113 }
115114
116- return $ this ->parseXml ($ xml );
115+ $ data ['# ' ] = $ rootNode ->nodeValue ;
116+
117+ return $ data ;
117118 }
118119
119120 /**
@@ -230,54 +231,107 @@ final protected function isElementNameValid($name)
230231 }
231232
232233 /**
233- * Parse the input SimpleXmlElement into an array.
234+ * Parse the input DOMNode into an array.
234235 *
235- * @param \SimpleXmlElement $node xml to parse
236+ * @param \DOMNode $node xml to parse
236237 *
237238 * @return array
238239 */
239- private function parseXml (\SimpleXmlElement $ node )
240+ private function parseXml (\DOMNode $ node )
240241 {
241- $ data = array ();
242- if ($ node ->attributes ()) {
243- foreach ($ node ->attributes () as $ attrkey => $ attr ) {
244- $ data ['@ ' .$ attrkey ] = (string ) $ attr ;
245- }
242+ $ data = $ this ->parseXmlAttributes ($ node );
243+
244+ $ value = $ this ->parseXmlValue ($ node );
245+
246+ if (!count ($ data )) {
247+ return $ value ;
246248 }
247- foreach ($ node ->children () as $ key => $ subnode ) {
248- if ($ subnode ->count ()) {
249- $ value = $ this ->parseXml ($ subnode );
250- } elseif ($ subnode ->attributes ()) {
251- $ value = array ();
252- foreach ($ subnode ->attributes () as $ attrkey => $ attr ) {
253- $ value ['@ ' .$ attrkey ] = (string ) $ attr ;
254- }
255- $ value ['# ' ] = (string ) $ subnode ;
249+
250+ if (!is_array ($ value )) {
251+ $ data ['# ' ] = $ value ;
252+
253+ return $ data ;
254+ }
255+
256+ if (1 === count ($ value ) && key ($ value )) {
257+ $ data [key ($ value )] = current ($ value );
258+
259+ return $ data ;
260+ }
261+
262+ foreach ($ value as $ key => $ val ) {
263+ $ data [$ key ] = $ val ;
264+ }
265+
266+ return $ data ;
267+ }
268+
269+ /**
270+ * Parse the input DOMNode attributes into an array
271+ *
272+ * @param \DOMNode $node xml to parse
273+ *
274+ * @return array
275+ */
276+ private function parseXmlAttributes (\DOMNode $ node )
277+ {
278+ if (!$ node ->hasAttributes ()) {
279+ return array ();
280+ }
281+
282+ $ data = array ();
283+
284+ foreach ($ node ->attributes as $ attrkey => $ attr ) {
285+ if (ctype_digit ($ attr ->nodeValue )) {
286+ $ data ['@ ' .$ attrkey ] = (int ) $ attr ->nodeValue ;
256287 } else {
257- $ value = ( string ) $ subnode ;
288+ $ data [ ' @ ' . $ attrkey ] = $ attr -> nodeValue ;
258289 }
290+ }
259291
260- if ($ key === 'item ' ) {
261- if (isset ($ value ['@key ' ])) {
262- if (isset ($ value ['# ' ])) {
263- $ data [$ value ['@key ' ]] = $ value ['# ' ];
264- } else {
265- $ data [$ value ['@key ' ]] = $ value ;
266- }
292+ return $ data ;
293+ }
294+
295+ /**
296+ * Parse the input DOMNode value (content and children) into an array or a string
297+ *
298+ * @param \DOMNode $node xml to parse
299+ *
300+ * @return array|string
301+ */
302+ private function parseXmlValue (\DOMNode $ node )
303+ {
304+ if (!$ node ->hasChildNodes ()) {
305+ return $ node ->nodeValue ;
306+ }
307+
308+ if (1 === $ node ->childNodes ->length && XML_TEXT_NODE === $ node ->firstChild ->nodeType ) {
309+ return $ node ->firstChild ->nodeValue ;
310+ }
311+
312+ $ value = array ();
313+
314+ foreach ($ node ->childNodes as $ subnode ) {
315+ $ val = $ this ->parseXml ($ subnode );
316+
317+ if ('item ' === $ subnode ->nodeName && isset ($ val ['@key ' ])) {
318+ if (isset ($ val ['# ' ])) {
319+ $ value [$ val ['@key ' ]] = $ val ['# ' ];
267320 } else {
268- $ data [ ' item ' ][ ] = $ value ;
321+ $ value [ $ val [ ' @key ' ] ] = $ val ;
269322 }
270- } elseif (array_key_exists ($ key , $ data ) || $ key == "entry " ) {
271- if ((false === is_array ($ data [$ key ])) || (false === isset ($ data [$ key ][0 ]))) {
272- $ data [$ key ] = array ($ data [$ key ]);
273- }
274- $ data [$ key ][] = $ value ;
275323 } else {
276- $ data [ $ key ] = $ value ;
324+ $ value [ $ subnode -> nodeName ][] = $ val ;
277325 }
278326 }
279327
280- return $ data ;
328+ foreach ($ value as $ key => $ val ) {
329+ if (is_array ($ val ) && 1 === count ($ val )) {
330+ $ value [$ key ] = current ($ val );
331+ }
332+ }
333+
334+ return $ value ;
281335 }
282336
283337 /**
0 commit comments