Reputation: 360
Every example of xml iteration I've found online (including PHP docs, W3Schools, and a stackoverflow search) presumes that we know the structure ahead of time. I would like to create a loop that iterates as deep as it can go in every branch and simply returns the node names and values that it finds. For example:
<za-lord>
<orderid>dresden1234</orderid>
<customer>toot-toot</customer>
<pizza>
<sauce>marinara</sauce>
<crust>thin</crust>
<toppings>
<cheese>extra</cheese>
<veg>
<onions>yes</onions>
<peppers>extra</peppers>
<olives>no</olives>
</veg>
<meat>
<groundbeef>yes</groundbeef>
<ham>no</ham>
<sausage>no</sausage>
</meat>
</toppings>
</pizza>
</za-lord>
What I'm looking for, then, is:
orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
groundbeef = yes
ham = no
sausage = no
I've spent a couple hours now writing code examples, testing different variations on foreach, and the short version is that nothing is getting me what I want. Not knowing the structure ahead of time, is it possible to recursively iterate the xml above and return node names and values using SimpleXML, and if so, how?
Upvotes: 0
Views: 625
Reputation: 147166
You can use a SimpleXMLIterator
object and recurse over it to get all the node values:
function list_nodes($sxi) {
for($sxi->rewind(); $sxi->valid(); $sxi->next() ) {
if ($sxi->hasChildren()) {
list_nodes($sxi->current());
}
else {
echo $sxi->key() . " = " . $sxi->current() . "\n";
}
}
}
$sxi = new SimpleXMLIterator($xmlstr);
list_nodes($sxi);
Output:
orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
groundbeef = yes
ham = no
sausage = no
Update
If your xml can have namespaces, you have to take a more complicated approach, checking each node for children in each of the namespaces in the document:
function list_children($node, $names) {
$children = false;
foreach ($names as $name) {
if (count($node->children($name))) {
$children = true;
foreach ($node->children($name) as $child) {
list_children($child, $names);
}
}
}
if (!$children) {
echo $node->getName() . " = $node\n";
}
}
$xml = new SimpleXMLElement($xmlstr);
list_children($xml, array_merge(array(''), $xml->getNamespaces(true)));
Output (for the demo xml, same as the question but with namespaces added):
orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
ham = no
sausage = no
groundbeef = yes
Upvotes: 1