GNOME Bugzilla – Bug 624663
namespace nodes are not copied with xsl:copy
Last modified: 2021-07-05 11:00:43 UTC
http://www.w3.org/TR/xslt#copying says: "The xsl:copy element provides an easy way of copying the current node. Instantiating the xsl:copy element creates a copy of the current node. The namespace nodes of the current node are automatically copied as well". With that definition the result of applying the stylesheet <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="/*"> <test-root> <xsl:apply-templates/> </test-root> </xsl:template> </xsl:stylesheet> to the XML document <root xmlns="http://example.com/ns1" xmlns:ns2="http://example.com/ns2"> <foo att-with-qname-value="ns2:baz"> <bar ns2:att="foobar"/> </foo> </root> should be <test-root> <foo xmlns="http://example.com/ns1" xmlns:ns2="http://example.com/ns2" att-with-qname-value="ns2:baz"> <bar ns2:att="foobar"/> </foo> </test-root> but using xsltproc I get <test-root> <foo xmlns="http://example.com/ns1" att-with-qname-value="ns2:baz"> <bar xmlns:ns2="http://example.com/ns2" ns2:att="foobar"/> </foo> </test-root> which looks as if the namespace nodes in scope on the 'foo' element have not been copied and thus in the output the attribute 'att-with-qname-value' ends up with an attribute value for which no namespace declaration is in scope. xsltproc --version outputs "Using libxml 20706, libxslt 10126 and libexslt 815".
I might be wrong, but I think that your copy template should look like this: <xsl:template match="ns2:*|ns2:*/@*"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> I think the match="" attribute of <template> is namespace-sensitive. If what I say is correct, this bug could be closed. In any case, I hope this helps.
The template <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> in the sample stylesheet is called the identity transformation (template), it is taken directly from http://www.w3.org/TR/xslt#copying. And xsltproc applies it to the elements ("foo", "bar") and attributes ("ns2:att") that are in namespaces in the input document, otherwise the elements and attributes would not be copied. Only the in scope namespace nodes are not copied correctly. That is what the bug report is about. Of course XSLT and XPath works on XML with namespaces what you might call "namespace-sensitive" but the patterns (http://www.w3.org/TR/xslt#patterns) I used ("node()", "@*") match any element node (and other nodes like text, comment and processing instruction nodes) respectively any attribute node, independent of any namespace. Thus I disagree that your comment means the bug should be closed.
Tssss... I did not say that "the bug should be closed", I said "if what I say is correct, it could be closed" :-). I did not look into the spec to check whether the identity transformation template applies to all namespaces, or only to the default one. At least, the template I gave can provide a workaround to anyone hitting this bug. So I renew my hope that this would help :-). Best,
I took the time to look again at http://www.w3.org/TR/xpath. This document says: - * selects all element children of the context node - the child axis contains the children of the context node - A node test node() is true for any node of any type whatsoever. - A node test * is true for any node of the principal node type. For example, child::* will select all element children of the context node, and attribute::* will select all attributes of the context node. - A node test can have the form NCName:*. In this case, the prefix is expanded in the same way as with a QName, using the context namespace declarations. It is an error if there is no namespace declaration for the prefix in the expression context. The node test will be true for any node of the principal type whose expanded-name has the namespace URI to which the prefix expands, regardless of the local part of the name. So if I interpret well, * is the same as child::node() and child::node() should not regard namespaces as important, while ns2:* should take the namespace prefix ns2 into account. So basically, yes, "*" test should not take only the nodes of default namespace as libxslt does, but should also take all nodes of the axis, independantly of their namespaces. But these specifications are written in a rather cryptic way, and hard to interpret correctly. So I still don't discard the possibility that libxslt does it the right way.
The spec says that only the namespace nodes of the current node should be copied, not all namespaces nodes that are in scope. IMO, the current behavior is correct.
What I wrote above is wrong. Thinking more about it, the bug report is valid. This is closely related to bug #341870.
GNOME is going to shut down bugzilla.gnome.org in favor of gitlab.gnome.org. As part of that, we are mass-closing older open tickets in bugzilla.gnome.org which have not seen updates for a longer time (resources are unfortunately quite limited so not every ticket can get handled). If you can still reproduce the situation described in this ticket in a recent and supported software version, then please follow https://wiki.gnome.org/GettingInTouch/BugReportingGuidelines and create a new ticket at https://gitlab.gnome.org/GNOME/libxslt/-/issues/ Thank you for your understanding and your help.