Html 使用XPath为节点的每个子节点获取第一个子节点

Html 使用XPath为节点的每个子节点获取第一个子节点,html,xpath,Html,Xpath,我试图用以下结构解析一些HTML,如何使用xpath提取每个元素的第一个元素 <ul> <li> <a> <span> <a> </li> <li> <a> <span> <a> </li> ... </ul>

我试图用以下结构解析一些HTML,如何使用xpath提取每个
  • 元素的第一个
    元素

    <ul>
        <li>
            <a>
            <span>
            <a>
        </li>
        <li>
            <a>
            <span>
            <a>
        </li>
        ...
    </ul>
    
    • ...

    我认为实现这一点的XPath应该是
    //ul/li/a[position()=1]

    说明:

    我之所以将其全部拼写为
    //ul/li/a
    ,是因为当您使用xpath时,如果出现错误,堆栈跟踪将准确显示定位器指向的内容,并且不那么模糊。但是,如果你不在乎的话,你显然可以用速记:
    //a

    使用position子句,您可以执行
    =1
    >1
    等操作。我会选择使用
    [position()=1]
    而不是使用
    [1]
    ,因为Xpath不使用基于0的数组,这可能会让其他查看定位器的人感到困惑。我的意思是
    position=0
    ,从逻辑上讲,意味着空值,对吗

    我用
    开始我的定位器,因为就我个人而言,有时我喜欢将定位器组合在一起。您实际上不需要以点字符开头,但由于我在本例中使用了
    /
    通配符,因此它实际上与没有点的开头相同,但具有链接的附加功能

    测试答案


    @马西亚斯:你说得对,我道歉//li/a[1]不起作用,因为它不是直接的子对象(中间有一个article标记,为了简单起见,我省略了它)

    然后,让我将此作为一个解决方案发布,并进行更多解释

    如前所述,如果
    //li/a[1]
    没有返回任何内容,而
    (//li//a)[1]
    没有返回任何内容,则显示的HTML示例不能代表实际文档。那么,
    a
    将是
    li
    的后代,而不是它的直系子代

    在这种情况下,正确的XPath表达式是

    //li//a[1]
    
    但仅当嵌套级别不同时才使用它,即如果在
    li
    a
    之间可能嵌套其他元素:

    <li>
      <article>
        <other>
          <a/>
    
    这避免了计算成本高于
    /
    /

    最后,如果您知道您感兴趣的
    a
    元素始终是
    li
    元素的孙子,并且如果它们之间始终是
    文章
    元素,请使用

    //li/article/a[1]
    

    当我将表达式更正为//li/article/a[1]”时,我得到第一个li的第一个a`

    //li/article/a[1]
    如果有多个
    a
    元素是
    article
    的子元素和
    li
    的孙子元素,则返回多个结果。如果这只返回一个结果

    • 在只需要一个结果的上下文中调用此XPath表达式,例如,如果在编程语言或应用程序中使用XPath库
    • 输入文档的结构更加复杂

    请显示您尝试过但未给出正确结果的XPath表达式。@Mathias我尝试过:
    //li//code>-它返回所有
    节点,
    (//li//a)[1]
    -它返回第一个“
  • ”节点的第一个
    (//li)[1]//a
    -返回第一个
  • 的所有
    节点,以及
    //li/a[1]
    -没有返回任何内容。如果
    //li/a[1]
    没有返回任何内容,而
    (//li//a)[1]
    没有返回任何内容,则显示的HTML示例不能代表实际文档。那么,
    a
    将是
    li
    的后代,而不是它的直系子代。请出示一个更完整的样品。@Mathias:你说得对,我道歉
    //li/a[1]
    不起作用,因为它不是直接的子对象(中间有一个
    文章
    标记,为了简单起见,我省略了该标记)。当我将表达式更正为
    //li/article/a[1]
    时,对于第一个
    li
    ,我得到了第一个
    a
    。这会让事情变得更清楚吗?不,在这种情况下,不需要用
    启动XPath表达式,如果上下文节点不是文档节点,它甚至是有害的
    (../ul/li/a)[position()=1]
    返回0或1个结果节点,在我看来,这显然不是OP想要的。他们想选择每个
    li
    的第一个
    a
    元素,这是一个以上的结果。@MathiasMüller Yep,你完全正确。我的定位器错了。我想我已经修好了。谢谢你编辑了你的答案,但我仍然不明白为什么以
    开头的表达式会有助于链接。你能举例说明一下吗?以
    /
    开头的路径表达式可以很容易地附加到另一个路径表达式。在使用Selenium的上下文中进行链接。
    //li/article/a[1]