为什么在子元素上调用SimpleXMLElement::xpath方法时得到的是父元素?

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

为什么在子元素上调用 SimpleXMLElement::xpath() 方法时得到父元素?

示例:

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

此处 $node->xpath('//tag') returns 文档的所有 <tag> xml 标签,在每次迭代时,而不是只返回 <tag> 的子元素<node> 标签。

在 XPath 中,当您使用 // 时,您表示的是相对于当前节点的任意位置的节点。对于 XPath,这还包括文档中较高的节点以及包含在该元素中的节点。

在这个特定场景下有几种方法可以解决...

参考What's the difference between //node and /descendant::node in xpath?,可以使用后代轴...

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

仅使用基节点内的节点(在本例中 $node)。

或者,如果您的文档中的层次结构与您在文档中的层次结构完全相同,则更简单的方法是使用 SimpleXML 对象表示法(用一个循环来显示每个层次结构)...

foreach ($nodeList as $node) {
    // For each enclosed tag
    foreach ( $node->tag as $tag )  {
        // Echo the v attribute
        echo $tag['v'].PHP_EOL;
    }
}

//tag.//tag//descendent::tag 之间的差异:

  • //tag 检索文档中任意位置的所有 tag 元素。

  • .//tag 检索上下文节点处或下方的所有 tag 元素。

  • descendant::tag 检索上下文节点下的所有 tag 元素。

另见