繁体   English   中英

相同的XPath-不同的结果

[英]The same XPaths - different results

$str = '
<body>
<table><tr><td><b class="1">1</b></td></tr></table>
<table><tr><td><b class="2">1</b></td></tr></table>
<p>some text</p>
</body>';

$dom = new DOMDocument();
$dom->loadHTML($str);
$xpath = new DOMXpath($dom);

foreach($xpath->query('//table[//b[contains(@class, "2")]]') as $i) 
   print_r($i);

echo "------------------------------------------\n";

foreach($xpath->query('//table//b[contains(@class, "2")]/ancestor::table') as $i) 
   print_r($i);

第一个XPath选择两个表,而第二个仅获取目标(第二个)表。 为什么?

评估

接受的答案可以纠正错误,但不能真正解释原始路径表达式为什么出错。

您的第一个表达式如下:

//table[//b[contains(@class, "2")]]

它有两个谓词 ,一个嵌套在另一个中:

//table[//b[contains(@class, "2")]]
           ^---------------------^       inner predicate
       ^--------------------------^      outer predicate

将谓词视为应用于谓词左侧上下文的过滤器。 在极端情况下,此类谓词不会丢弃任何中间结果节点,也不会丢弃所有中间结果节点。

每个中间结果节点只有在其右边的谓词评估为true才会保留。 对于内部谓词:

//b[contains(@class, "2")]

//b产生一组中间的b元素节点(整个文档中的所有b元素节点),然后由谓词[contains(@class, "2")]过滤。 给定您输入的XML文档,谓词内部的表达式仅对b元素之一返回true

但是//b[contains(@class, "2")]依次充当外部谓词的内容:

//table[outer predicate]

现在, //table选择整个文档中所有table元素节点作为中间结果,并对每个谓词检查谓词内部的表达式。

重要的是,外部谓词//b[contains(@class, "2")]对于两个 table元素将返回true 这是因为对于他们两个来说,在整个文档中某处确实存在一个b元素,其class属性包含2

您真正想做的是:从每个table元素的角度评估外部谓词表达式-接受的答案显示了如何执行此操作。 即,在谓词中使用.//代替//

XPath谓词[//b...]有一个错误。 它应该是[.//b...]

说明: [...]是谓词,它们仅充当过滤器。 a[b] ,选择所有满足谓词[b] a节点。 如果ab是元素,它会,从当前上下文节点,选择所有a包含一个元素b元件作为子元素。

  • //bAbbreviatedAbsoluteLocationPath并选择整个文档中的所有b元素节点。 两个表都在带有b元素的文档中,因此谓词[//b]对于您的文档始终为true,无论您在哪里应用它。
  • .//bAbbreviatedRelativeLocationPath并选择作为后代的所有b元素节点(子代及其子代,递归)。 谓词[.//b]仅适用于具有后代元素b table元素。

如果步骤路径表达式选择的节点集不为空,则像//b.//b这样的步骤路径表达式在用作[//b][.//b]类的谓词时为true

由于//b而不是.//b ,因此应用的谓词没有任何改变: //b[contains(@class, "2")]选择整个文档中所有包含“ 2”的元素在其class属性中。 您基本上是在检查文档,而不是对所需table元素下方的树进行检查,并且两个table元素都满足该文档检查的要求,因为这两个检查都在文档中,该文档的class属性中包含一个b元素带有“ 2”的元素。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM