Skip to content

Commit 1abe03c

Browse files
committed
[Serializer] Refactored XmlEncoder to remove dependency to SimpleXml
1 parent 9c16937 commit 1abe03c

File tree

1 file changed

+101
-47
lines changed

1 file changed

+101
-47
lines changed

Encoder/XmlEncoder.php

Lines changed: 101 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)