Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions src/XmlNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
56 changes: 52 additions & 4 deletions tests/XmlUtilTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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('<root><node param="pval"/></root>');
$array = $xml->toArray();

$expected = [
'root' => [
'node' => [
'@attributes' => ['param' => 'pval']
]
]
];

$this->assertEquals($expected, $array);
}

public function testXmlToArrayWithAttributeAndText(): void
{
$xml = new XmlDocument('<root><node param="pval">value</node></root>');
Comment thread
leonardomunsa marked this conversation as resolved.
$array = $xml->toArray();

$expected = [
'root' => [
'node' => [
'@attributes' => ['param' => 'pval'],
'@value' => 'value'
]
]
];

$this->assertEquals($expected, $array);
}

public function testXmlToArrayWithMixedContent(): void
{
$xmlString = '<root><node param="pval">value<other>value</other><node2 a="2"></node2></node></root>';
$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');
Expand Down