Вот общее решение, которое работает на любом узле, принадлежащем к любому набору узлов в одном и том же документе :
Я использую XSLT для реализации решения, но в итоге получаю одно выражение XPath, которое можно использовать с любым другим языком хостинга.
Пусть $vNodeSet
будет набором узлов, а $vNode
будет узлом в этом наборе узлов, положение которого мы хотим найти.
Тогда пусть $vPrecNodes
содержит все узлы в документе XML, предшествующие $vNode
.
Тогда пусть $vAncNodes
содержит все узлы в документе XML, которые являются предками $vNode
.
Набор узлов в $vNodeSet
, которые предшествуют $vNode
в порядке документов, состоит из всех узлов в наборе узлов, которые также принадлежат $vPrecNodes
, и всех узлов в наборе узлов, которые также принадлежат $vAncNodes
.
Я буду использовать известную формулу Кайса для пересечения двух наборов узлов:
$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
Do note : Это решение не зависит от XSLT (используется только в иллюстративных целях). Вы можете собрать одно выражение XPath, подставляя переменные с их определением, пока не останется больше переменных для замены.