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');