contains() 在 XPath 中是什么作用?

4

我有两个几乎相同的表格,唯一的区别是第一个表格中有一个输入标签:

表格 #1

  <table>
    <tbody>
      <tr>
        <td>
          <div>
            <input type="text" name="" value=""/>
          </div>
        </td>
      </tr>
    </tbody>
  </table>

表格 #2

  <table>
    <tbody>
      <tr>
        <td>
          <div></div>
        </td>
      </tr>
    </tbody>
  </table>
</body>

当我使用这个XPath //table//tbody//tr[position()=1 and contains(.,input)] 时,它返回了两个表格的第一行,而不仅仅是我期望的第一个表格的第一行。
然而,这个XPath //table//tbody//tr[position()=1]//input 返回了第一个表格中的input
那么,我做错了什么?为什么同一个input与两个表格相关联?我是否在这里错误地使用了.
2个回答

7
由于函数名称选择不当1,许多人错误地将XPath中的contains()函数的目的误解为:
  • XPath contains()不会检查元素的包含。
  • XPath contains()检查的是子字符串的包含。
注释1:原文为 "Due to an unfortunate choice in function names","unfortunate "在此处表示遗憾的、不幸的。
因此,tr[contains(.,input)]并不是你想要的。它实际上选择的是string-value包含与第一个直接子节点input元素的字符串值相等的子字符串的tr元素;有关详细信息,请参见此答案。(有趣的是,这样的谓词会简化为true,因为字符串值的层次结构性质意味着父元素和子元素之间存在子字符串包含关系)无论如何,显然这不是你的意图。
要检查后代元素的包含关系,请改用.//input。如果要选择tr元素,则可以将其作为第一个XPath的谓词放置。
//table//tbody//tr[position()=1 and .//input]

如果你想选择包含 input 后代元素的 table 元素,可以参考 @Andersson 的示例(如此显示)。

//table[.//input]

为什么XPath的contains()应该被命名为string-contains()

1在XML的背景下,它极大地基于层次结构的概念,自然而然地会认为contains是指层次包含。在原始的XPath规范中,单词contains出现了24次,其中19次表示层次结构的节点包含,只有5次表示子字符串包含。难怪会出现关于contains()的混淆。XPath子字符串的contains()函数应该被命名为string-contains()


@MichaelKay:关于 tr[contains(.,input)] 的作用,我认为谓词将始终评估为 true。你同意吗? - kjhughes
如果你的“always”是指“当child::input不存在时”,那么是的。 - Michael Kay
@MichaelKay:在这里,“always”指的是无论 child::input 出现 0 次、1 次还是多次,tr[contains(.,input)] 的谓词都必然为真,因为 tr 的字符串值必然包含空字符串(0 情况)、它唯一的 child::input 的字符串值(1 情况)或其第一个 child::input 的字符串值(多情况)。 - kjhughes
1
正确 - 因为输入元素具有零长度字符串值。但在XSLT 2.0中,如果存在多个“input”子元素,则contains(。,input)会出错。 - Michael Kay

3

您应该尝试

//table[.//input]

获取包含“input”后代的“table”节点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接