【发布时间】:2010-09-30 23:46:48
【问题描述】:
如何使用 XPATH 找到两个 H3 之间的所有节点?
【问题讨论】:
标签: xpath
如何使用 XPATH 找到两个 H3 之间的所有节点?
【问题讨论】:
标签: xpath
在 XPath 1.0 中,一种方法是使用 Kayessian 方法进行节点集交集:
$ns1[count(.|$ns2) = count($ns2)]
上面的表达式恰好选择同时属于节点集 $ns1 和节点集 $ns2 的节点。
将此应用于特定问题——假设我们需要选择以下 XML 文档中第二个和第三个 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/>
二。 XPath 2.0 解决方案:
使用intersect 运算符:
/*/h3[2]/following-sibling::node()
intersect
/*/h3[3]/preceding-sibling::node()
【讨论】:
"/*/h3[2]/following-sibling::node()[not(/*/h3[3])] |
$startInd、$endInd,并在您的“循环”中用必要的值声明它们。此外,将表达式“2”替换为$startInd,将“3”替换为$endInd。 XPath 2.0 表达式甚至可以是这样的:for $i in 1 to count(/*/h3) -1 return /*/h3[$i]/following-sibling::node() intersect /*/h3[$i+1]/preceding-sibling::node()
当您知道两个标记是相同元素时的其他 XPath 1.0 解决方案(本例为 h3):
/html/body/h3[2]/following-sibling::node()
[not(self::h3)]
[count(preceding-sibling::h3)=2]
【讨论】:
一个更通用的解决方案 - 在 XPath 2.0 中 - 假设您想要两个 h3 元素之间所有树深度的节点,这不一定是兄弟。
/path/to/first/h3/following::node()[. << /path/to/second/h3]
【讨论】:
基于dimitre-novatchev 出色的答案,我可以采用以下解决方案,而不是为不同的 H3 硬编码 [2] 和 [3],我只给出第一项标题的内容。
//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。
【讨论】:
假设您的 <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>分组
【讨论】: