我使用XPather进行了不同的XPath查询(仅适用于较旧的firefox版本)并注意到以下查询的结果之间存在差异
这个显示了一些结果
//div[descendant::table/descendant::td[4]]
这个列出空列表
//div[//table//td[4]]
由于某些规则它们是否不同,或者只是XPath解释器的特定实现的不当行为? (看起来像是从FF引擎中使用,XPather只是一个非常简单的用于查询的GUI)
答案 0 :(得分:8)
使用XPath 1.0 //
是/descendant-or-self::node()/
的缩写,因此第一条路径为/descendant-or-self::node()/div[descendant::table/descendant::td[4]]
,而第二条路径与/descendant-or-self::node()/div[/descendant-or-self::node()/table/descendant-or-self::node()/td[4]]
完全不同。因此,主要区别在于,在第一个谓词中,您会查看相对于div
元素的后代,而在第二个谓词中,您会查看来自根节点/
(也称为文档节点)的后代。
您可能希望//div[.//table//td[4]]
使第二个路径表达式更接近第一个路径表达式。
[编辑] 这是一个示例:
<html>
<body>
<div>
<table>
<tbody>
<tr>
<td>1</td>
</tr>
<tr>
<td>2</td>
</tr>
<tr>
<td>3</td>
</tr>
<tr>
<td>4</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
使用该示例,路径//div[descendant::table/descendant::td[4]]
会选择div
元素,因为它有一个table
子项,其中有第四个td
后代。
然而,对于//div[.//table//td[4]]
,我们会查找//div[./descendant-or-self::node()/table/descendant-or-self::node()/td[4]]
,它是//div[./descendant-or-self::node()/table/descendant-or-self::node()/child::td[4]]
的缩写,并且没有元素具有第四个td
子元素。
我希望这能解释不同之处,如果您使用//div[.//table/descendant::td[4]]
,那么您应该得到与原始表单相同的结果。
答案 1 :(得分:4)
关于XPath的W3C文档中有一个重要的注释:
XML Path Language (XPath) Version 1.0
2 Location Paths
2.5 Abbreviated Syntax注意:位置路径
//para[1]
与位置路径/descendant::para[1]
的含义不同。后者选择第一个后代para
元素;前者选择所有后代para
元素,这些元素是他们父母的第一个孩子。
这意味着路径中的双斜杠不仅是/descendant-or-self::node()/
的快捷方式,而且是XML树迭代的下一级的起点,这意味着//
右侧的步骤表达式在当前上下文节点的每个后代上重新运行。
所以这条路径中谓词的确切含义
//div[ descendant::table/descendant::td[4] ]
是:
<table>
个节点后代到当前<div>
,<table>
构建,所有后代<td>
元素的序列和将它们连接成一个序列,最后,路径返回文档中的所有<div>
元素,这些元素在其所有嵌套表中至少有四个数据单元格。由于文档中有4个单元格或更多单元格(当然包括嵌套表格中的单元格),因此整个表达式选择各自的<div>
祖先。
另一方面,
中的谓词//div[ //table//td[4] ]
表示:
<table>
元素(更准确地说,测试根节点和每个根的后代,如果它有<table>
子元素),<td>
子元素的元素(即测试该表或其任何后代是否至少有四个<td>
个子元素。)请注意,谓词子表达式不依赖于上下文节点。它是一个全局路径,解析为某些节点序列(可能为空),因此谓词布尔值仅取决于文档的结构。如果为真,则整个路径返回文档中所有<div>
元素的序列,否则返回空序列。
如果任何表中有一个元素,有4个(至少)数据单元格,那么谓词将 true 。
并且据我所知,所有<tr>
行包含两个或三个单元格 - 没有包含4个或更多<td>
子元素的元素,因此谓词子表达式返回空序列,谓词为 false 并且整个路径被过滤掉。结果是:没有(空序列)。