The issue here is that self::[QName]
can only refer to an element, not an attribute1.
I think michael.hor257k's suggestion is the best for this particular case, and checking the name as in kjhughes' answer should be ok in this particular case because it is about the xml
namespace, which is unambiguous.
But in general, if you wanted to exclude a single attribute without relying on name()
, you can do this:
<xsl:template match="abstract[@xml:lang]">
<xsl:copy>
<xsl:apply-templates select="@*[(. | ../@xml:lang)[2]]|node()"/>
</xsl:copy>
</xsl:template>
http://xsltransform.net/eiZQaFp/2
This will only work correctly if the xml:lang
attribute is present, but your pattern in the match
attribute here ensures that it is indeed present.
- Here is the relevant text from the XPath spec that explains why this is true:
Every axis has a principal node type. If an axis can contain elements, then the principal node type is element; otherwise, it is the type of the nodes that the axis can contain. Thus,
- For the attribute axis, the principal node type is attribute.
- For the namespace axis, the principal node type is namespace.
- For other axes, the principal node type is element.
A node test that is a QName is true if and only if the type of the node (see [5 Data Model]) is the principal node type and has an expanded-name equal to the expanded-name specified by the QName. For example, child::para selects the para element children of the context node; if the context node has no para children, it will select an empty set of nodes. attribute::href selects the href attribute of the context node; if the context node has no href attribute, it will select an empty set of nodes.
The principal node type of self::
is element, so if it is followed by a QName (such as xml:lang
), then self::xml:lang
can only refer to an element, not an attribute.