选择多个子项的XPath中//和/ descendant之间的差异

时间:2015-11-25 13:40:58

标签: xpath parent-child

在XPath中选择基本元素的多个子元素时,我无法清楚地理解使用//element/descendant::element之间的区别。

鉴于此HTML代码段

<html>
<body>
<div class="popupContent">
  <table>
    <tr class="aclass"><td> Hello </td> <td> <input type="text" value="FIRST" /> </td></tr>
    <tr class="aclass"><td> Goodbye </td> <td> <input type="text" value="SECOND" /> </td></tr>
  </table>
</div>
</body>
</html>

我需要根据其在表格中的位置来选择每个input//div[@class='popupContent']//input[1]这会选择第一个输入 //div[@class='popupContent']//input[2]这会产生错误 //div[@class='popupContent']/descendant::input[1]这再次选择第一个输入 //div[@class='popupContent']/descendant::input[2]这会选择第二个输入

使用/descendant::input做我需要的:抓住所有输入并让我按位置选择 //有何不同?为什么它只返回第一个元素而不是之后的元素?

我知道this other question,但答案基本上是说他们是别名并指向文档,我无法理解,缺乏具体的例子。

2 个答案:

答案 0 :(得分:10)

根据XPath 1.0, §2.5 Abbreviated Syntax

  

///descendant-or-self::node()/

的缩写

所以div[@class='popupContent']//input[1](与div[@class='popupContent']/descendant-or-self::node()/child::input[1]相同)将:

  1. 使用“popupContent”类转到div s的所有后代(孩子,孩子的孩子等),
  2. 然后寻找<input>个孩子
  3. 并最终选择其父级的第一个子级([1]谓词)
  4. div[@class='popupContent']//input[2]非常相似,但最后一件事是选择第二个孩子。 <input> s中没有一个是他们父母的第二个孩子。

    另一方面,

    div[@class='popupContent']/descendant::input[2]将:

    1. 转到该班级div的所有后代
    2. 仅选择<input>元素,并从中构建节点集
    3. 最后按文档顺序选择该节点集中的第二个元素
    4. 您可以在§2.4 Predicates中阅读谓词和轴。相关部分:

        

      (...)祖先,祖先或自我,前面和前面的兄弟轴是反向轴; 所有其他轴都是前轴

      [因此descendant是前轴。]

        

      节点集的成员相对于轴的接近位置被定义为按文档顺序排序的节点集中节点的位置(如果轴)是前轴(...)。第一个位置是1.

           

      谓词过滤相对于轴的节点集以生成新的节点集。对于要过滤的节点集中的每个节点,使用该节点作为上下文节点评估PredicateExpr,其中节点集中的节点数作为上下文大小,具有接近度节点集中节点相对于轴的位置作为上下文位置;

答案 1 :(得分:1)

//X/descendant::X之间的唯一区别是X包含位置谓词,例如//x[1] vs /descendant::x[1]。在这种情况下,//x[1]会选择作为其父元素的第一个x子元素的每个x元素,而/descendant::x[1]会选择整个第一个后代x。您可以通过记住//x[1]/descendant-or-self::node()/child::x[1]

的简称来解决这个问题