This code is supposed to print the full path to all elements and attributes in the data.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" expand-text="yes">
<xsl:output method="text"/>
<xsl:template match="text()"/>
<xsl:template match="*">
{ancestor-or-self::*/concat(node-name(),'/')}<xsl:apply-templates select="@*|*"/>
</xsl:template>
<xsl:template match="@*">{'@' || node-name() || ','}</xsl:template>
</xsl:stylesheet>
So with this input
<a:b xmlns:a="ans" xmlns:c="cns">
<c:x/>
</a:b>
I expect
{ans}b
{ans}b/ {cns}x
precise spacing is immaterial.
I am getting output as if I had used the name() function instead of node-name i.e
a:b
a:b / c:x
There is probably a work-around by concatenating local-name and namespace-uri but I would like to know why what is posted isn't doing what I hoped it would.
Perhaps the path
function helps: <xsl:value-of select="descendant::*!path()" separator=" "/>
.
Or construct the format you want from namespace-uri-from-QName
and the local-name-fromQName
:
<xsl:value-of select="descendant::*!string-join(ancestor-or-self::*!node-name()!('{' || namespace-uri-from-QName(.) || '}' || local-name-from-QName(.)), '/')" separator=" "/>
https://xsltfiddle.liberty-development.net/naZXVFj
As for why node-name()
returns an xs:QName
but its string value gives the format you see, I think https://www.w3.org/TR/xpath-functions-31/#casting-to-string specifies about casting an xs:QName
to a string:
If ST is xs:QName or xs:NOTATION:
if the qualified name has a prefix, then TV is the concatenation of the prefix of SV, a single colon (:), and the local name of SV.
otherwise TV is the local-name.