Я думаю, что следующее исправление имеет значение только в необычных случаях, когда разные префиксы используются для одних и тех же пространств имен или разных пространств имен для одного и того же префикса среди родственных элементов в документе.Однако в таком вводе нет ничего теоретически неправильного, и это может быть распространено в определенных видах сгенерированного XML.
В любом случае следующий ответ исправляет этот случай (скопировано и изменено из ответа @ Kirill):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no" />
<xsl:template match="*[not(*)]">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="concat('/', name())"/>
<!-- Suggestions on how to refactor the repetition of long XPath
expression parts are welcome. -->
<xsl:if test="count(../*[local-name() = local-name(current())
and namespace-uri(.) = namespace-uri(current())]) > 1">
<xsl:value-of select="concat('[', count(
preceding-sibling::*[local-name() = local-name(current())
and namespace-uri(.) = namespace-uri(current())]) + 1, ']')"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>
Это также решает проблему в других ответах, где элементам, которые являются первыми в ряду родных братьев и сестер, не хватает предиката позиции.
Например, для ввода
<root>
<item1>value1</item1>
<subitem>
<a:item xmlns:a="uri">value2</a:item>
<b:item xmlns:b="uri">value3</b:item>
</subitem>
</root>
thisОтвет дает
/root/item1
/root/subitem/a:item[1]
/root/subitem/b:item[2]
, что является правильным.
Однако, как и все выражения XPath, они будут работать, только если среда, в которой они используются, задает правильные привязки для используемых префиксов пространства имен.В теории может быть больше патологических документов, для которых приведенный выше ответ генерирует выражения XPath, которые никогда не могут работать (по крайней мере в XPath 1.0) независимо от привязки префикса.Например, этот ввод:
<root>
<item1>value1</item1>
<a:subitem xmlns:a="differentURI">
<a:item xmlns:a="uri">value2</a:item>
<b:item xmlns:b="uri">value3</b:item>
</a:subitem>
</root>
производит вывод
/root/item1
/root/a:subitem/a:item[1]
/root/a:subitem/b:item[2]
Но второе выражение XPath здесь не может работать, так как префикс a
относится к двум различным пространствам имен в одном и том же выражении..