3030use function is_iterable ;
3131use function is_numeric ;
3232use function is_object ;
33- use function Koded \Stdlib \{json_serialize , json_unserialize };
33+ use function Koded \Stdlib \json_serialize ;
34+ use function Koded \Stdlib \json_unserialize ;
3435use function key ;
3536use function preg_match ;
3637use function str_contains ;
@@ -84,7 +85,7 @@ public function serialize(mixed $data): string|null
8485 $ document ->createAttributeNS ('http://www.w3.org/2001/XMLSchema-instance ' , 'xsi: ' . $ this ->root );
8586 $ this ->buildXml ($ document , $ root , $ data );
8687 } else {
87- $ this ->appendNode ($ document , $ document , $ data , $ this ->root );
88+ $ this ->appendNode ($ document , $ document , $ data , $ this ->root , null );
8889 }
8990 return $ document ->saveXML ();
9091 }
@@ -120,38 +121,38 @@ private function buildXml(
120121 DOMNode $ parent ,
121122 iterable $ data ): void
122123 {
123- foreach ($ data as $ key => $ data ) {
124+ foreach ($ data as $ key => $ val ) {
124125 $ isKeyNumeric = is_numeric ($ key );
125126 if (str_starts_with ($ key , '@ ' ) && $ name = substr ($ key , 1 )) {
126127 // node attribute
127- $ parent ->setAttribute ($ name , $ data );
128+ $ parent ->setAttribute ($ name , $ val );
128129 } elseif ($ this ->val === $ key ) {
129130 // node value
130- $ parent ->nodeValue = $ data ;
131- } elseif (false === $ isKeyNumeric && is_array ($ data )) {
131+ $ parent ->nodeValue = $ val ;
132+ } elseif (false === $ isKeyNumeric && is_array ($ val )) {
132133 /*
133134 * If the data is an associative array (with numeric keys)
134135 * the structure is transformed to "item" nodes:
135136 * <item key="0">$key0</item>
136137 * <item key="1">$key1</item>
137138 * by appending it to the parent node (if any)
138139 */
139- if (array_is_list ($ data )) {
140- foreach ($ data as $ d ) {
141- $ this ->appendNode ($ document , $ parent , $ d , $ key );
140+ if (array_is_list ($ val )) {
141+ foreach ($ val as $ d ) {
142+ $ this ->appendNode ($ document , $ parent , $ d , $ key, null );
142143 }
143144 } else {
144- $ this ->appendNode ($ document , $ parent , $ data , $ key );
145+ $ this ->appendNode ($ document , $ parent , $ val , $ key, null );
145146 }
146147 } elseif ($ isKeyNumeric || false === $ this ->hasValidName ($ key )) {
147148 /* If the key is not a valid XML tag name,
148149 * transform the key to "item" node:
149150 * <item key="$key">$value</item>
150151 * by appending it to the parent node (if any)
151152 */
152- $ this ->appendNode ($ document , $ parent , $ data , 'item ' , $ key );
153+ $ this ->appendNode ($ document , $ parent , $ val , 'item ' , $ key );
153154 } else {
154- $ this ->appendNode ($ document , $ parent , $ data , $ key );
155+ $ this ->appendNode ($ document , $ parent , $ val , $ key, null );
155156 }
156157 }
157158 }
@@ -207,19 +208,7 @@ private function parseXmlValue(DOMNode $node): mixed
207208 if ($ child ->nodeType === XML_CDATA_SECTION_NODE ) {
208209 return $ child ->wholeText ;
209210 }
210- foreach ($ node ->childNodes as $ child ) {
211- if ($ child ->nodeType === XML_COMMENT_NODE ) {
212- continue ;
213- }
214- $ v = $ this ->parseXml ($ child );
215- if ('item ' === $ child ->nodeName && isset ($ v ['@key ' ])) {
216- $ k = $ v ['@key ' ];
217- $ value [$ k ] = $ this ->getValueByType ($ v );
218- unset($ value [$ k ]['@key ' ]);
219- } else {
220- $ value [$ child ->nodeName ][] = $ this ->getValueByType ($ v );
221- }
222- }
211+ $ this ->extractValuesFromChildNodes ($ node , $ value );
223212 }
224213 foreach ($ value as $ k => $ v ) {
225214 if (is_array ($ v ) && 1 === count ($ v )) {
@@ -244,7 +233,7 @@ private function appendNode(
244233 DOMNode $ parent ,
245234 mixed $ data ,
246235 string $ name ,
247- string $ key = null ): void
236+ ? string $ key ): void
248237 {
249238 $ element = $ document ->createElement ($ name );
250239 if (null !== $ key ) {
@@ -325,4 +314,21 @@ private function hasValidName(int|string $key): bool
325314 !str_contains ($ key , ' ' ) &&
326315 preg_match ('~^[\pL_][\pL0-9._:-]*$~ui ' , $ key );
327316 }
317+
318+ private function extractValuesFromChildNodes (DOMNode $ node , array &$ value ): void
319+ {
320+ foreach ($ node ->childNodes as $ child ) {
321+ if ($ child ->nodeType === XML_COMMENT_NODE ) {
322+ continue ;
323+ }
324+ $ v = $ this ->parseXml ($ child );
325+ if ('item ' === $ child ->nodeName && isset ($ v ['@key ' ])) {
326+ $ k = $ v ['@key ' ];
327+ $ value [$ k ] = $ this ->getValueByType ($ v );
328+ unset($ value [$ k ]['@key ' ]);
329+ } else {
330+ $ value [$ child ->nodeName ][] = $ this ->getValueByType ($ v );
331+ }
332+ }
333+ }
328334}
0 commit comments