这是一个通用解决方案,适用于属于同一文档中任何节点集的任何节点:
我正在使用 XSLT 来实现该解决方案,但最终获得了可以与任何其他托管语言一起使用的单个 XPath 表达式。
设$vNodeSet 为节点集,$vNode 为该节点集中我们要查找其位置的节点。
然后,让$vPrecNodes包含$vNode之前的XML文档中的所有节点。
然后,让$vAncNodes 包含 XML 文档中所有作为 $vNode 祖先的节点。
$vNodeSet 中按文档顺序排在$vNode 之前的节点集包括节点集中所有也属于$vPrecNodes 的节点,以及节点集中也属于$vAncNodes 的所有节点。
我将使用著名的 Kaysian 公式计算两个节点集的交集:
$ns1[count(.|$ns2) = count($ns2)]
恰好包含$ns1 与$ns2 的交集处的节点。
基于所有这些,让$vPrecInNodeSet 是$vNodeSet 中在文档顺序中位于$vNode 之前的节点集。下面的 XPath 表达式定义了$vPrecInNodeSet:
$vNodeSet
[count(.|$vPrecNodes) = count($vPrecNodes)
or
count(.|$vAncNodes) = count($vAncNodes)
]
最后,想要的职位是:count($vPrecInNodeSet) +1
这一切是如何协同工作的:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="vNodeSet" select="/*/a/b"/>
<xsl:variable name="vNode" select="$vNodeSet[. = 'tsr'][1]"/>
<xsl:variable name="vPrecNodes" select="$vNode/preceding::node()"/>
<xsl:variable name="vAncNodes" select="$vNode/ancestor::node()"/>
<xsl:variable name="vPrecInNodeSet" select=
"$vNodeSet
[count(.|$vPrecNodes) = count($vPrecNodes)
or
count(.|$vAncNodes) = count($vAncNodes)
]
"/>
<xsl:template match="/">
<xsl:value-of select="count($vPrecInNodeSet) +1"/>
</xsl:template>
</xsl:stylesheet>
在提供的 XML 文档上应用上述转换时:
<root>
<a>
<b>zyx</b>
</a>
<a>
<b>wvu</b>
</a>
<a>
<b>tsr</b>
</a>
<a>
<b>qpo</b>
</a>
</root>
产生正确的结果:
3
注意:此解决方案不依赖于 XSLT(仅用于说明目的)。您可以组装一个 XPath 表达式,用它们的定义替换变量,直到没有更多的变量可以替换。