【问题标题】:How to select the first element with a specific attribute using XPath如何使用 XPath 选择具有特定属性的第一个元素
【发布时间】:2010-11-03 15:00:51
【问题描述】:

XPath bookstore/book[1] 选择bookstore 下的第一个书节点。

如何选择第一个匹配更复杂条件的节点,例如第一个匹配/bookstore/book[@location='US']的节点

【问题讨论】:

    标签: xpath


    【解决方案1】:

    用途:

    (/bookstore/book[@location='US'])[1]
    

    这将首先获取 location 属性等于“US”的 book 元素。然后它将从该集合中选择第一个节点。请注意括号的使用,这是某些实现所必需的。

    注意,这与/bookstore/book[1][@location='US'] 不同,除非第一个元素也恰好具有该位置属性。

    【讨论】:

    • 我怎样才能为 //bookstore/book[@location='US'] 做同样的事情?
    • 这将获得来自“美国”的所有书籍。 (/bookstore/book[@location='US'])[1] 将获得第一个。
    • @KevinDriedger /bookstore/book[@location='US'][1] 不会返回来自“美国”的所有书籍。我已经在不同语言的 xpath 实现下对其进行了多次测试。 /bookstore/book[@location='US'][1] 返回书店下的第一本“美国”书。如果有多个书店,那么它将返回每个书店的第一个。这是 OP 要求的(书店下的第一个节点)。您的版本仅返回所有书店中的一本书(第一场比赛)。
    • @JonathanFingland 你误解了 - 再次阅读 KevinDriedger 的回答,以及 AlexanderV.Ilyin 问题的上下文。你们俩的意思是一样的。
    【解决方案2】:

    作为对 Jonathan Fingland 回答的解释:

    • 同一谓词 ([position()=1 and @location='US']) 中的多个条件必须为真作为一个整体
    • 连续谓词 ([position()=1][@location='US']) 中的多个条件必须为真一个接一个
    • 这意味着[position()=1][@location='US'] != [@location='US'][position()=1]
      [position()=1 and @location='US'] == [@location='US' and position()=1]
    • 提示:一个单独的[position()=1]可以缩写为[1]

    您可以使用布尔运算符“and”和“or”以及布尔 XPath 函数 not()true()false() 在谓词中构建复杂的表达式。另外,您可以将子表达式括在括号中。

    【讨论】:

    • 是否可以在不使用多个“and”运算符的情况下拥有一组位置(如 [1,3,5:7,9])?
    • @M.HosseinRahimi 在 XPath 1.0 中,没有。在 XPath 2.0 中,序列和 = 运算符可以解决问题:[position() = (1,3,5,6,7,9)]
    【解决方案3】:

    /bookstore/book[@location='US'][1] 仅适用于简单结构。

    添加更多结构,事情就会中断。

    有-

    <bookstore>
     <category>
      <book location="US">A1</book>
      <book location="FIN">A2</book>
     </category>
     <category>
      <book location="FIN">B1</book>
      <book location="US">B2</book>
     </category>
    </bookstore> 
    

    /bookstore/category/book[@location='US'][1] 产量

    <book location="US">A1</book>
    <book location="US">B2</book>
    

    不是“匹配更复杂条件的第一个节点”。 /bookstore/category/book[@location='US'][2] 不返回任何内容。

    使用括号,您可以获得原始问题的结果:

    (/bookstore/category/book[@location='US'])[1] 给了

    <book location="US">A1</book>
    

    (/bookstore/category/book[@location='US'])[2] 按预期工作。

    【讨论】:

    • 此处接受的答案的作者。 OP 的问题是/bookstore/book[1] 而不是(/bookstore/book)[1]。您提供的案例与 OP 要求的案例不同。据推测,OP 接受了我的回答,因为它符合他的预期(和要求)。
    • 提供的这个答案帮助我解决了这个特殊情况。有人可以解释为什么它不能处理“更复杂的情况”吗?因为基本上它确实找到了一个包含两个项目的列表,所以 [2] 应该把它捡起来(在我的世界里)
    • 我还发现这个答案比选择的答案更正确,因为在我的情况下,我也有一个更复杂的结构,只需添加 [1] 即可返回多个节点。谢谢!
    • 括号有效!您还可以在 (..)[1] 之后添加更多路径,例如:'(//div[text() = "'+ name +'"])[1]/following-sibling::*/div/text()'。如果有很多节点匹配name
    • 我正在改变我的看法。经过一段距离后,我得到了这个答案的意思,如果我没有看到 OP 的例子,我会投票给这个。我想我是对这个答案的语气做出反应;如果@tkurki 解释了更多关于将条件与第一个节点的选择分开的信息,我会立即看到它。 JonFingland 或许也是如此。
    【解决方案4】:

    找到第一个英文书节点(在整个文档中)的最简单方法,考虑到更复杂的结构化 xml 文件,例如:

    <bookstore>
     <category>
      <book location="US">A1</book>
      <book location="FIN">A2</book>
     </category>
     <category>
      <book location="FIN">B1</book>
      <book location="US">B2</book>
     </category>
    </bookstore> 
    

    是 xpath 表达式:

    /descendant::book[@location='US'][1]
    

    【讨论】:

    • 我不知道您为什么将“类别”添加到(假定的)xml 中。我对此投了反对票,因为它回答了 OP 没有提出的问题。
    【解决方案5】:
        <bookstore>
         <book location="US">A1</book>
         <category>
          <book location="US">B1</book>
          <book location="FIN">B2</book>
         </category>
         <section>
          <book location="FIN">C1</book>
          <book location="US">C2</book>
         </section>
        </bookstore> 
    

    鉴于以上情况;你可以选择第一本书

    (//book[@location='US'])[1]
    

    这将在任何具有美国位置的地方找到第一个。 [A1]

    //book[@location='US']
    

    将返回包含位置为 US 的所有书籍的节点集。 [A1,B1,C2]

    (//category/book[@location='US'])[1]
    

    将返回存在于文档任何位置的类别中的第一个图书位置 US。 [B1]

    (/bookstore//book[@location='US'])[1]
    

    将返回存在于根元素 bookstore 下任何位置的第一本位置为 US 的书;确实使 /bookstore 部分变得多余。 [A1]

    直接回答:

    /bookstore/book[@location='US'][1]
    

    将为您返回位于书店 [A1] 下的位置为 US 的 book 元素的第一个节点

    顺便说一句,如果你想,在这个例子中找到第一本不是书店直系子的美国书:

    (/bookstore/*//book[@location='US'])[1]
    

    【讨论】:

    • 我不知道您为什么将“类别”添加到(假定的)xml 中。我对此投了反对票,因为它回答了 OP 没有提出的问题。
    • @samwyse 因为 OP 没有提供更多关于源数据中其他信息的上下文。因此,您根据您认为他们的数据可能是什么样的回答,并提供更广泛的背景,以便 OP 和为相同和类似问题找到此问题的人们可以使用实际示例了解更多信息。你会注意到我在书店下有一本书。与您的其他复制粘贴响应答案不同。
    【解决方案6】:

    例如。

    <input b="demo">
    

    (input[@b='demo'])[1]
    

    【讨论】:

      【解决方案7】:

      在在线 xpath tester 的帮助下,我正在写这个答案...
      为此:

      <table id="t2"><tbody>
      <tr><td>123</td><td>other</td></tr>
      <tr><td>foo</td><td>columns</td></tr>
      <tr><td>bar</td><td>are</td></tr>
      <tr><td>xyz</td><td>ignored</td></tr>
      </tbody></table>
      

      以下xpath:

      id("t2") / tbody / tr / td[1]
      

      输出:

      123
      foo
      bar
      xyz
      

      由于 1 表示选择所有 td 元素,它们是其直接父级的第一个子元素。
      但是下面的xpath:

      (id("t2") / tbody / tr / td)[1]
      

      输出:

      123
      

      【讨论】:

        【解决方案8】:

        如果 xpath 复杂或存在多个具有相同 xpath 的节点,则使用索引获取所需的节点。

        例如:

        (//bookstore[@location = 'US'])[index]
        

        你可以给你想要的节点编号。

        【讨论】:

          【解决方案9】:

          如果给定的 xml 上提供了命名空间,最好使用它。

          (/*[local-name() ='bookstore']/*[local-name()='book'][@location='US'])[1]
          

          【讨论】:

            猜你喜欢
            • 2012-11-30
            • 1970-01-01
            • 2011-10-31
            • 1970-01-01
            • 1970-01-01
            • 2022-01-03
            • 2015-07-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多