Published on 6 Dec 2010. Tagged with php, algorithmicadvent.
/**
* Transforms the contents of a DOMNode to an associative array
*
* XML node names become array keys, attributes will be discarded. If $node
* doesn't contain child nodes, a string will be returned.
*
* For more information about DOMNode and related classes see the documentation
* of DOMDocument <http://php.net/manual/en/class.domdocument.php>.
*
* @param DOMNode $node DOMDocument node
* @return string|array Associative array or string with node content
*/
function domNodeToArray(DOMNode $node)
{
$ret = '';
if ($node->hasChildNodes()) {
if ($node->firstChild === $node->lastChild
&& $node->firstChild->nodeType === XML_TEXT_NODE
) {
// Node contains nothing but a text node, return its value
$ret = trim($node->nodeValue);
} else {
// Otherwise, do recursion
$ret = array();
foreach ($node->childNodes as $child) {
if ($child->nodeType !== XML_TEXT_NODE) {
// If there's more than one node with this node name on the
// current level, create an array
if (isset($ret[$child->nodeName])) {
if (!is_array($ret[$child->nodeName])
|| !isset($ret[$child->nodeName][0])
) {
$tmp = $ret[$child->nodeName];
$ret[$child->nodeName] = array();
$ret[$child->nodeName][] = $tmp;
}
$ret[$child->nodeName][] = domNodeToArray($child);
} else {
$ret[$child->nodeName] = domNodeToArray($child);
}
}
}
}
}
return $ret;
}
Usage example:
$xmlCode = <<<EOT
<?xml version="1.0" encoding="utf-8"?>
<characters>
<character>
<name>Steve</name>
<role>King</role>
<stats>
<age>52</age>
<weight>85</weight>
</stats>
</character>
<character>
<name>Johnny</name>
<role>Knight</role>
<role>Jester</role>
</character>
</characters>
EOT;
$dom = new DOMDocument();
$dom->loadXML($xmlCode);
$array = array();
$xpath = new DOMXPath($dom);
foreach ($xpath->query('/characters', $dom) as $node) {
$array = domNodeToArray($node);
}
echo '<pre>';
print_r($array);
This will return the following array structure:
Array
(
[character] => Array
(
[0] => Array
(
[name] => Steve
[role] => King
[stats] => Array
(
[age] => 52
[weight] => 85
)
)
[1] => Array
(
[name] => Johnny
[role] => Array
(
[0] => Knight
[1] => Jester
)
)
)
)