Skip to content

Commit 5d9eaa6

Browse files
committed
- bugfix: invalid key values are transformed as items
- optimization: attempt to reduce the code complexity
1 parent 1edf7f0 commit 5d9eaa6

File tree

1 file changed

+32
-26
lines changed

1 file changed

+32
-26
lines changed

Serializer/XmlSerializer.php

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
use function is_iterable;
3131
use function is_numeric;
3232
use 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;
3435
use function key;
3536
use function preg_match;
3637
use 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

Comments
 (0)