Skip to content
Advertisement

Why do I get parent elements when I call the SimpleXMLElement::xpath method on a child element?

Why do I get parent elements when I call the SimpleXMLElement::xpath() method on a child element?

Example:

$xml = '<root>
  <node>
    <tag v="foo"/>
    <tag v="bar"/>
  </node>
  <node>
    <tag v="foo"/>
  </node>
  <node>
    <tag v="foo"/>
    <tag v="bar"/>
  </node>
</root>';

$simpleXML = new SimpleXMLElement($xml);

$nodeList = $simpleXML->xpath('//node');

foreach ($nodeList as $node) {
    $node->xpath('//tag');
}

Here $node->xpath('//tag') returns all the <tag> xml tags of the document, at each iteration, instead of returning only the child <tag> elements of the <node> tag.

Advertisement

Answer

In XPath, when you use //, you are saying a node in any position relative to the current node. With XPath this also includes nodes higher in the document as well as enclosed in this element.

There are several ways to solve it in this particular scenario…

With reference to What’s the difference between //node and /descendant::node in xpath?, you can use the descendant axis…

foreach ($nodeList as $node) {
    $node->xpath('descendant::tag');
}

which only uses nodes inside the base node (in this case $node).

Or if the hierarchy in your document is exactly as you have in your document, a simpler way is to use SimpleXML object notation (with a loop to show each one)…

foreach ($nodeList as $node) {
    // For each enclosed tag
    foreach ( $node->tag as $tag )  {
        // Echo the v attribute
        echo $tag['v'].PHP_EOL;
    }
}
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement