XPATH中的第n个元素(兄弟或祖先)

时间:2015-05-22 09:49:16

标签: javascript html xpath

说我的标记是:

<html>
<body>

<div>
 <div>blbaba</div>
 <p>a</p>
 <p>b</p>
 <p>c</p>
 <p>d</p>
 <div id="a1">blbaba</div>
 <p>e</p>
 <p>f</p>
 <p>g</p>
 <p>h</p> 
 <div>blbaba</div>
</div>

</body>
</html>

如何选择相对于特定元素的元素,即之前的n个节点(在文档中可以是之前的父节点或兄弟节点)。

示例:

我想在div <p>之前选择第二个@id ="a1"元素,因此我的预期元素为<p>c</p>

2 个答案:

答案 0 :(得分:3)

preceding::ancestor::不相交,因此在一般情况下,您将无法选择所需元素,除非您使用所选元素通过这两个轴。

引用 W3C XPath 1.0 Specification

  

•前一轴包含与文档相同的所有节点   在文档顺序中的上下文节点之前的上下文节点,   排除任何祖先并排除属性节点和命名空间   节点

使用

(//p[@id='a1']/ancestor::div | //p[@id='a1']/preceding::div) 
                                                        [last() -$n +1]

这将选择属于div元素div元素的前一个和祖先p元素的并集的第n个id元素(按文档顺序向后) } attribute的值是字符串&#34; a1&#34;。这里我们假设id属性唯一地标识它所属的元素。

例如,如果我们有这个XML文档(我使示例更加真实,因为div可以嵌套,而p不能):

<html>
    <body>
       <div>
          <p>a</p>
          <p>b</p>
          <p>c</p>
          <div id="y">
             <p>d</p>
             <div>blbaba</div>
             <p id="a1">e</p>
             <p>f</p>
             <p>g</p>
             <p>h</p>
             <div>blbaba</div>
          </div>
       </div>
    </body>
</html>

我们希望在div p&#34; id&#34;之前(以文档顺序)获得第二个a1然后此XPath表达式选择所需的div元素:

(//p[@id='a1']/ancestor::div | //p[@id='a1']/preceding::div)
                                                        [last() -1]

这个简短的XSLT转换证明上面的XPath表达式精确地选择了想要的div元素(通过评估XPath表达式并复制整个选定的div元素):

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <xsl:copy-of select=
     "(//p[@id='a1']/ancestor::div | //p[@id='a1']/preceding::div)
                                                        [last() -1]"/>
  </xsl:template>
</xsl:stylesheet>

当上述转换应用于上述源XML文档时,它会选择所需的div元素并将其复制到输出

<div id="y">
   <p>d</p>
   <div>blbaba</div>
   <p id="a1">e</p>
   <p>f</p>
   <p>g</p>
   <p>h</p>
   <div>blbaba</div>
</div>

答案 1 :(得分:0)

两者都不能在Chrome中工作(例如),你可以先检查它是否有兄弟,如果它是null,那么通过第二个XPath获得祖先。

or的此行为的解释是here

<html><head><script>
function doTest() {
    testElement('a1');
    testElement('a2');
  }

  function testElement(id) {
      var ancestor = getPath("//div[@id='" + id +"']/ancestor::*[2]");
      alert('ancestor ' + ancestor);

      var sibling = getPath("//div[@id='" + id + "']/preceding-sibling::*[2]");
      alert('sibling ' + sibling);

      var both = getPath("//div[@id='" + id + "']/preceding-sibling::*[2]|//div[@id='" + id +"']/ancestor::*[2]");
      alert('both ' + both);
  }

  function getPath(path) {
      return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  }
  </script></head>
<body onload='doTest()'>
<div>
 <div id='a1'>blbaba</div>
 <p>a</p>
 <p>b</p>
 <p id='me'>c</p>
 <p>d</p>
 <div id="a2">blbaba</div>
 <p>e</p>
 <p>f</p>
 <p>g</p>
 <p>h</p> 
 <div>blbaba</div>
</div>
</body>