phi*_*red 5 xml xpath nodesets position
玩弄后position()白白我周围的Googling的解决方案,并来到这个旧的计算器问题这几乎描述了我的问题.
区别在于我希望其中的位置是动态的,而不是文档的连续部分.
为了说明我将修改链接问题中的示例以符合我的要求.请注意,每个<b>元素都在不同的<a>元素中.这是关键的一点.
<root>
<a>
<b>zyx</b>
</a>
<a>
<b>wvu</b>
</a>
<a>
<b>tsr</b>
</a>
<a>
<b>qpo</b>
</a>
</root>
Run Code Online (Sandbox Code Playgroud)
现在,如果我查询,使用XPath,a/b我将得到四个<b>节点的节点集.然后我想找到包含该字符串的节点的该节点集内的位置'tsr'.另一篇文章中的解决方案在这里分解:count(a/b[.='tsr']/preceding-sibling::*)+1返回1因为preceding-sibling导航文档而不是上下文节点集.
是否可以在上下文节点集中工作?
这是一个通用解决方案,适用于属于同一文档中任何节点集的任何节点:
我正在使用 XSLT 来实现该解决方案,但最终获得了一个可以与任何其他托管语言一起使用的 XPath 表达式。
让$vNodeSet成为节点集,并$vNode成为这个节点集中我们想要找到其位置的节点。
然后, let$vPrecNodes包含前面的 XML 文档中的所有节点$vNode。
然后, let$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)
]
Run Code Online (Sandbox Code Playgroud)
最后,想要的位置是: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>
Run Code Online (Sandbox Code Playgroud)
当上述转换应用于提供的 XML 文档时:
<root>
<a>
<b>zyx</b>
</a>
<a>
<b>wvu</b>
</a>
<a>
<b>tsr</b>
</a>
<a>
<b>qpo</b>
</a>
</root>
Run Code Online (Sandbox Code Playgroud)
产生正确的结果:
3
请注意:此解决方案不依赖于 XSLT(仅用于说明目的)。您可以组合一个 XPath 表达式,用它们的定义替换变量,直到没有更多的变量可以替换。
你得到 1 的原因与上下文和文档无关,而是因为你只计算b一个a节点内的节点(所以你总是得到 0 的计数,因为从来没有任何前面的“b”节点。
相反,您需要找到包含“a”的“b”之前前面“a”节点的计数。
就像是:
count(a[b[.='tsr']]/preceding-sibling::a)
Run Code Online (Sandbox Code Playgroud)