7

我使用 XPather 处理了不同的 XPath 查询(仅适用于较旧的 firefox 版本),并注意到以下查询的结果之间存在差异

这显示了一些结果

//div[descendant::table/descendant::td[4]] 

这个列出了空列表

//div[//table//td[4]]

它们是由于某些规则而不同,还是只是 XPath 解释器的特定实现的不当行为?(看起来像是从 FF 引擎中使用的,XPather 只是一个出色的简单 GUI 用于查询)

4

2 回答 2

10

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]]which 的缩写,//div[./descendant-or-self::node()/table/descendant-or-self::node()/child::td[4]]并且没有具有第四td个子元素的元素。

我希望能解释差异,如果你使用,//div[.//table/descendant::td[4]]那么你应该得到与原始表格相同的结果。

于 2012-04-07T11:15:48.767 回答
4

W3C 文档中有一条关于 XPath 1.0 的重要说明(W3C 建议 1999 年 11 月 16 日):

XML 路径语言 (XPath) 版本 1.0
    2 位置路径
        2.5 缩写语法

注意:位置路径与位置路径//para[1]的含义不同/descendant::para[1]。后者选择第一个后代para元素;前者选择作为其父母para的第一个孩子的所有后代元素。para

XPath 3.1 文档中的类似说明(W3C 建议 2017 年 3 月 21 日)

XML 路径语言 (XPath) 3.1
    3 表达式
        3.3 路径表达式
            3.3.5 缩写语法

注意:路径表达式与路径表达式//para[1]的含义不同/descendant::para[1]。后者选择第一个后代para元素;前者选择作为其各自父母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 个(至少)数据单元格,则谓词为真。 据我所知,所有行都包含两个或三个单元格 - 没有具有 4 个或更多子级的元素,因此谓词子表达式返回一个空序列,谓词为,整个路径被过滤掉。结果是:没有(空序列)。
<tr><td>

于 2014-02-28T23:45:43.570 回答