你如何使用XPATH找到两个H3之间的所有节点?

时间:2010-09-30 23:46:48

标签: xpath

你如何使用XPATH找到两个H3之间的所有节点?

5 个答案:

答案 0 :(得分:27)

在XPath 1.0中,一种方法是使用Kayessian方法进行节点集交集

$ns1[count(.|$ns2) = count($ns2)]

上面的表达式精确选择了属于节点集$ns1和节点集$ns2的节点。

将此问题应用于特定问题 - 假设我们需要选择以下XML文档中第2个和第3个h3元素之间的所有节点:

<html>
  <h3>Title T31</h3>
    <a31/>
    <b31/>
  <h3>Title T32</h3>
    <a32/>
    <b32/>
  <h3>Title T33</h3>
    <a33/>
    <b33/>
  <h3>Title T34</h3>
    <a34/>
    <b34/>
  <h3>Title T35</h3>
</html>

我们必须将$ns1替换为

/*/h3[2]/following-sibling::node()

并将$ns2替换为

/*/h3[3]/preceding-sibling::node()

因此,完整的XPath表达式是

/*/h3[2]/following-sibling::node()
             [count(.|/*/h3[3]/preceding-sibling::node())
             =
              count(/*/h3[3]/preceding-sibling::node())
             ]

我们可以验证这是正确的XPath表达式:

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

 <xsl:template match="/">
  <xsl:copy-of select=
   "/*/h3[2]/following-sibling::node()
             [count(.|/*/h3[3]/preceding-sibling::node())
             =
              count(/*/h3[3]/preceding-sibling::node())
             ]
   "/>
 </xsl:template>
</xsl:stylesheet>

在上面显示的XML文档中应用此转换时,会生成所需的正确结果

<a32/>

<b32/>

<强> II。 XPath 2.0解决方案:

使用intersect运算符

   /*/h3[2]/following-sibling::node()
intersect
   /*/h3[3]/preceding-sibling::node()

答案 1 :(得分:7)

当您知道两个标记是相同的元素时,其他XPath 1.0解决方案(本例h3):

/html/body/h3[2]/following-sibling::node()
                           [not(self::h3)]
                           [count(preceding-sibling::h3)=2]

答案 2 :(得分:2)

一个更通用的解决方案 - 在XPath 2.0中 - 假设你想要两个h3元素之间所有树深处的节点,这些节点不一定是兄弟节点。

/path/to/first/h3/following::node()[. << /path/to/second/h3]

答案 3 :(得分:1)

基于dimitre-novatchev出色的答案,我可以使用以下解决方案,而不是硬编码[2]和[3]用于不同的H3s我只是给出第一项的标题的内容。

//h3[text()="Main Page Section Heading"]/following-sibling::node()
 [  count(.|//h3[text()="Main Page Section Heading"]/following-sibling::h3[1]/preceding-sibling::node()) =  
    count(//h3[text()="Main Page Section Heading"]/following-sibling::h3[1]/preceding-sibling::node())  ]

我想要更进一步,但是当我正在查看最后一个H3时,能够处理这个场景,并且在它之后得到所有内容,在上面的情况下,我无法得到最后一个H3。

答案 4 :(得分:0)

使用密钥还有另一个很棒的通用解决方案,假设您的<h3>代码具有唯一属性(例如其文本或id属性):

<xsl:key name="siblings_of_h3" match="*[not(self::h3)]" use="preceding-sibling::h3[1]/text()"/>

<xsl:template match="h3">
  <!-- now select all tags belonging to the current h3 -->
  <xsl:apply-templates select="key('siblings_of_h3', text())"/>
</xsl:template>

它按照前面的<h3>

对所有代码进行分组