From c1549e41c4b32517c4cd974c3a2f3e022885a5b8 Mon Sep 17 00:00:00 2001 From: leomunsa Date: Tue, 1 Jul 2025 16:12:57 -0300 Subject: [PATCH 1/3] fix the toArray function to start the array at the root node xml --- src/XmlNode.php | 4 +++- tests/XmlUtilTest.php | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/XmlNode.php b/src/XmlNode.php index e8554b0..ca469cd 100644 --- a/src/XmlNode.php +++ b/src/XmlNode.php @@ -263,7 +263,9 @@ 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, $func)]; } protected function _toArray(SimpleXMLElement|DOMNode|array $arr, Closure|null $func): array diff --git a/tests/XmlUtilTest.php b/tests/XmlUtilTest.php index f36c071..76995cf 100644 --- a/tests/XmlUtilTest.php +++ b/tests/XmlUtilTest.php @@ -316,7 +316,7 @@ public function testXml2Array1(): void $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 @@ -324,7 +324,7 @@ public function testXml2Array2(): void $xml = new XmlDocument('value'); $array = $xml->toArray(); - $this->assertEquals([ "node" => "value"], $array); + $this->assertEquals(['root' => [ "node" => "value"]], $array); } public function testSelectNodesNamespace(): void From f57e7bec25af1ef649ebea10dc315083af7fdd67 Mon Sep 17 00:00:00 2001 From: leomunsa Date: Tue, 1 Jul 2025 18:52:37 -0300 Subject: [PATCH 2/3] fix the logic to keep attributes and text of all kinds of xml --- src/XmlNode.php | 48 ++++++++++++++++++++++++++----------------- tests/XmlUtilTest.php | 33 +++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/XmlNode.php b/src/XmlNode.php index ca469cd..20a2d7c 100644 --- a/src/XmlNode.php +++ b/src/XmlNode.php @@ -264,35 +264,45 @@ public function removeTagName(string $tagName): bool public function toArray(Closure $func = null): array { $sxml = simplexml_import_dom($this->DOMNode()); - - return [$sxml->getName() => $this->_toArray($sxml, $func)]; + 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); + $output = []; + + foreach ($node->attributes() as $attrName => $attrValue) { + $output['@attributes'][$attrName] = (string)$attrValue; } - if ($arr instanceof DOMNode) { - return $this->_toArray((array) simplexml_import_dom($arr), $func); + 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; + } } - $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) - ); + $text = trim((string)$node); + if (strlen($text) > 0) { + if (!empty($output)) { + $output['@value'] = $text; + } else { + $output = $text; } } - return $newArr; + if (is_array($output) && empty($output)) { + return ''; + } + + return $output; } /** diff --git a/tests/XmlUtilTest.php b/tests/XmlUtilTest.php index 76995cf..2f0e802 100644 --- a/tests/XmlUtilTest.php +++ b/tests/XmlUtilTest.php @@ -310,7 +310,7 @@ public function testRemoveNode(): void } - public function testXml2Array1(): void + public function testXml2Array(): void { $file = new File(__DIR__ . '/buggy.xml'); $xml = new XmlDocument($file, preserveWhiteSpace: false); @@ -319,12 +319,37 @@ public function testXml2Array1(): void $this->assertEquals(['root' => [ "node" => [ "subnode" => "value"]]], $array); } - public function testXml2Array2(): void + public function testXmlToArrayWithAttributeAndNoText(): void { - $xml = new XmlDocument('value'); + $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(); - $this->assertEquals(['root' => [ "node" => "value"]], $array); + + $expected = [ + 'root' => [ + 'node' => [ + '@attributes' => ['param' => 'pval'], + '@value' => 'value' + ] + ] + ]; + + $this->assertEquals($expected, $array); } public function testSelectNodesNamespace(): void From 55a0ff4ae19c6120819e2afdead0bd9fdfbf63c3 Mon Sep 17 00:00:00 2001 From: leomunsa Date: Wed, 2 Jul 2025 10:59:29 -0300 Subject: [PATCH 3/3] Change the logic of toArray function and add test case --- src/XmlNode.php | 46 +++++++++++++++++++++++-------------------- tests/XmlUtilTest.php | 23 ++++++++++++++++++++++ 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/XmlNode.php b/src/XmlNode.php index 20a2d7c..84b921c 100644 --- a/src/XmlNode.php +++ b/src/XmlNode.php @@ -269,37 +269,41 @@ public function toArray(Closure $func = null): array protected function _toArray(SimpleXMLElement $node): array|string { - $output = []; + $hasAttributes = (count($node->attributes()) > 0); + $hasChildren = (count($node->children()) > 0); + $textValue = trim((string)$node); + $hasText = (strlen($textValue) > 0); - foreach ($node->attributes() as $attrName => $attrValue) { - $output['@attributes'][$attrName] = (string)$attrValue; + if (!$hasAttributes && !$hasChildren) { + return $textValue; } - foreach ($node->children() as $child) { - $childName = $child->getName(); - $childData = $this->_toArray($child); + $output = []; - if (isset($output[$childName])) { - if (!is_array($output[$childName]) || !isset($output[$childName][0])) { - $output[$childName] = [$output[$childName]]; - } - $output[$childName][] = $childData; - } else { - $output[$childName] = $childData; + if ($hasAttributes) { + foreach ($node->attributes() as $attrName => $attrValue) { + $output['@attributes'][$attrName] = (string)$attrValue; } } - $text = trim((string)$node); - if (strlen($text) > 0) { - if (!empty($output)) { - $output['@value'] = $text; - } else { - $output = $text; + 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; + } } } - if (is_array($output) && empty($output)) { - return ''; + if ($hasText) { + $output['@value'] = $textValue; } return $output; diff --git a/tests/XmlUtilTest.php b/tests/XmlUtilTest.php index 2f0e802..43cc3ac 100644 --- a/tests/XmlUtilTest.php +++ b/tests/XmlUtilTest.php @@ -352,6 +352,29 @@ public function testXmlToArrayWithAttributeAndText(): void $this->assertEquals($expected, $array); } + public function testXmlToArrayWithMixedContent(): void + { + $xmlString = 'valuevalue'; + $xml = new XmlDocument($xmlString); + $array = $xml->toArray(); + + $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');