Это не может быть сделано (только) в чистом XPath 1.0.
Решение XPath 2.0 :
if(not($vStart intersect $vTarget/ancestor::*))
then ()
else
for $vPath in
string-join
((for $x in
$vTarget
/ancestor-or-self::*[. >> $vStart]
/concat(name(.),
for $n in name(.),
$cn in count(../*[name(.) eq $n])
return
if($cn ge 2)
then concat('[',
count((preceding-sibling::*
[name() eq $n]) +1,
']')
else (),
'/'
)
return $x),
''
)
return string-join((concat(name($vStart), '/'),$vPath), '')
Когда это выражение XPath 2.0 сравнивается со следующим XML-документом :
<table>
<tr>
<td><b>11</b></td>
<td><i>12</i></td>
</tr>
<tr>
<td><p><b>21</b></p></td>
<td><p><b>221</b></p><p><b><i>222</i></b></p></td>
</tr>
<tr>
<td><b>31</b></td>
<td><i>32</i></td>
</tr>
</table>
и если два параметра определены как :
<xsl:variable name="vStart" select="/*"/>
<xsl:variable name="vTarget" select="/*/tr[2]/td[2]/p[2]/b/i"/>
тогда результат вычисления выражения XPath 2.0 выше:
table/tr[2]/td[2]/p[2]/b/i/