diff --git a/src/XmlNode.php b/src/XmlNode.php index e8554b0..84b921c 100644 --- a/src/XmlNode.php +++ b/src/XmlNode.php @@ -263,34 +263,50 @@ public function removeTagName(string $tagName): bool public function toArray(Closure $func = null): array { - return $this->_toArray($this->DOMNode(), $func); + $sxml = simplexml_import_dom($this->DOMNode()); + return [$sxml->getName() => $this->_toArray($sxml)]; } - protected function _toArray(SimpleXMLElement|DOMNode|array $arr, Closure|null $func): array + protected function _toArray(SimpleXMLElement $node): array|string { - if ($arr instanceof SimpleXMLElement) { - return $this->_toArray((array) $arr, $func); + $hasAttributes = (count($node->attributes()) > 0); + $hasChildren = (count($node->children()) > 0); + $textValue = trim((string)$node); + $hasText = (strlen($textValue) > 0); + + if (!$hasAttributes && !$hasChildren) { + return $textValue; } - if ($arr instanceof DOMNode) { - return $this->_toArray((array) simplexml_import_dom($arr), $func); + $output = []; + + if ($hasAttributes) { + foreach ($node->attributes() as $attrName => $attrValue) { + $output['@attributes'][$attrName] = (string)$attrValue; + } } - $newArr = array(); - if (!empty($arr)) { - foreach ($arr as $key => $value) { - $newArr[$key] = - ( - is_array($value) - || ($value instanceof DOMNode) - || ($value instanceof SimpleXMLElement) - ? $this->_toArray($value, $func) - : (!empty($func) ? $func($value) : $value) - ); + if ($hasChildren) { + foreach ($node->children() as $child) { + $childName = $child->getName(); + $childData = $this->_toArray($child); + + if (isset($output[$childName])) { + if (!is_array($output[$childName]) || !isset($output[$childName][0])) { + $output[$childName] = [$output[$childName]]; + } + $output[$childName][] = $childData; + } else { + $output[$childName] = $childData; + } } } - return $newArr; + if ($hasText) { + $output['@value'] = $textValue; + } + + return $output; } /** diff --git a/tests/XmlUtilTest.php b/tests/XmlUtilTest.php index f36c071..43cc3ac 100644 --- a/tests/XmlUtilTest.php +++ b/tests/XmlUtilTest.php @@ -310,23 +310,71 @@ public function testRemoveNode(): void } - public function testXml2Array1(): void + public function testXml2Array(): void { $file = new File(__DIR__ . '/buggy.xml'); $xml = new XmlDocument($file, preserveWhiteSpace: false); $array = $xml->toArray(); - $this->assertEquals([ "node" => [ "subnode" => "value"]], $array); + $this->assertEquals(['root' => [ "node" => [ "subnode" => "value"]]], $array); } - public function testXml2Array2(): void + public function testXmlToArrayWithAttributeAndNoText(): void + { + $xml = new XmlDocument(''); + $array = $xml->toArray(); + + $expected = [ + 'root' => [ + 'node' => [ + '@attributes' => ['param' => 'pval'] + ] + ] + ]; + + $this->assertEquals($expected, $array); + } + + public function testXmlToArrayWithAttributeAndText(): void { $xml = new XmlDocument('value'); + $array = $xml->toArray(); + $expected = [ + 'root' => [ + 'node' => [ + '@attributes' => ['param' => 'pval'], + '@value' => 'value' + ] + ] + ]; + + $this->assertEquals($expected, $array); + } + + public function testXmlToArrayWithMixedContent(): void + { + $xmlString = 'valuevalue'; + $xml = new XmlDocument($xmlString); $array = $xml->toArray(); - $this->assertEquals([ "node" => "value"], $array); + + $expected = [ + 'root' => [ + 'node' => [ + '@attributes' => ['param' => 'pval'], + '@value' => 'value', + 'other' => 'value', + 'node2' => [ + '@attributes' => ['a' => '2'] + ] + ] + ] + ]; + + $this->assertEquals($expected, $array); } + public function testSelectNodesNamespace(): void { $file = new File(__DIR__ . '/feed-atom.txt');