GNOME Bugzilla – Bug 302020
Duplicate attributes again & namespace errors (?) new in 1.1.12
Last modified: 2006-05-19 10:09:23 UTC
Distribution/Version: current debian sarge Testcase: xsl: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:test="http://example.com/xmlns/test"> <xsl:output method="xml" indent="yes" /> <xsl:strip-space elements="*" /> <xsl:template name="copyWhatever" priority="0.6" match="text()|node()|@*"> <xsl:copy> <xsl:apply-templates select="text()|node()|@*" /> </xsl:copy> </xsl:template> <xsl:template match="/" priority="1"> <xsl:apply-templates select="node()|text()|@*" /> </xsl:template> <xsl:template match="@label" priority="1"> <xsl:attribute name="{name()}" namespace="{namespace-uri()}"> <xsl:value-of select="." /> </xsl:attribute> </xsl:template> <xsl:template match="test:test[parent::test:use]" priority="1"> <xsl:copy> <xsl:apply-templates select="/test:root/test:def/test:test[@name=current()/@name]/@*" /> <xsl:apply-templates select="@*" /> <xsl:apply-templates select="text()|node()" /> </xsl:copy> </xsl:template> </xsl:stylesheet> xml: <?xml version="1.0"?> <root xmlns="http://example.com/xmlns/test" xmlns:test="http://example.com/xmlns/test" > <def> <test name="foo" label="bleh" def="new" /> </def> <use> <test name="foo" label="foo" other="bar"/> </use> </root> output in 1.1.12: <?xml version="1.0"?> <root xmlns="http://example.com/xmlns/test" xmlns:test="http://example.com/xmlns/test"> <def> <test xmlns="" name="foo" label="bleh" def="new"/> </def> <use> <test xmlns="" name="foo" label="bleh" def="new" label="foo" other="bar"/> </use> </root> xsltproc was compiled against libxml 20603, libxslt 10102 and libexslt 802: This version did not produce the duplicate attributes and the in my opinion wrong xmlns="" xsltproc was compiled against libxml 20616, libxslt 10112 and libexslt 810 This version produces above output. Removing the redundant namespace=.. attribute on xsl:attribute fixes the problem.
Checked now as well the most recent 1.1.14 binaries for windows: Using libxml 20619CVS2407, libxslt 10114CVS1011 and libexslt 812CVS1011 They produce the same result.
Added test from the web, with an additional bug appearing in both xsltproc 1.1.12 debian sarge and 1.1.14 windows. This second bug is not respecting "Adding an attribute to an element replaces any existing attribute of that element with the same expanded-name." of the xsl specification. Testcase from the web: xsltproc http://bebabo.homelinux.org/test/xsltproc_bug/test.xsl http://bebabo.homelinux.org/test/xsltproc_bug/test.xml
True, the result is wrong. I tried with the current CVS HEAD (> 1.1.16): this produces the same result.
The bug producing the incorrect namespace "undeclaration" (xmlns="") is in: xsltAttributeInternal() (attributes.c) --> namespace = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *) "namespace", XSLT_NAMESPACE); xsltEvalAttrValueTemplate() returns here the empty string for the expression "{namespace-uri()}" Unfortunately the next code-line does not check for the empty string, but just for NULL: if (namespace != NULL) { ns = xsltGetSpecialNamespace(ctxt, inst, namespace, prefix, ctxt->insert); Thus xsltGetSpecialNamespace() undeclares the current default namespace.
The second bug, producing the duplicate @same via xsl:attribute, is also located in xsltAttributeInternal() (attributes.c). xsltAttributeInternal(): Calls with an empty string: --> xsltGetSpecialNamespace(): Here the default namespace is queried, which returns previously declared xmlns="" (see comment above). if ((prefix == NULL) && (URI[0] == 0)) { ret = xmlSearchNs(out->doc, out, NULL); Now the code tries to undeclare the default namespace, which results in an error: xmlNewNs() will return NULL, since there is already a xmlns="" on the same element node. if (ret != NULL) { ret = xmlNewNs(out, URI, prefix); return(ret); NULL is returned and assigned to the newly created @same. At the end we get: <test xmlns="" name="foo" label="bleh" def="new" label="foo" other="bar"/> With the first @label being internally incorrectly bound to xmlns="" and the second @label being in no namespace; that's why it looks like the first @label wasn't overwritten. This means xsltGetSpecialNamespace() is not able yet to handle namespace declaration clashes. I think it should generate an error message if it cannot create the desired ns-declaration. Fixing the issue in the comment above, also heals this behaviour; but the extra error message (if xmlNewNs() returns NULL) will be also added.
I wonder if xsltGetSpecialNamespace() should ever return an xmlNs struct representing an xmlns="" at all. TODO: Check if this produces problems in other scenarios.
A reduced scenario for this: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:foo="urn:test:foo"> <xsl:output indent="yes"/> <xsl:template match="text()|node()|@*" priority="0.6"> <xsl:copy> <xsl:apply-templates select="text()|node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="@same" priority="1"> <xsl:attribute name="{name()}" namespace="{namespace-uri()}">generated</xsl:attribute> </xsl:template> <xsl:template match="foo:zoo" priority="1"> <xsl:copy> <xsl:apply-templates select="/foo:foo/foo:bar/@*"/> <xsl:apply-templates select="@*"/> <xsl:apply-templates select="text()|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> <?xml version="1.0"?> <foo xmlns="urn:test:foo" xmlns:test="urn:test:foo"> <bar same="new" same-2="new"/> <zoo same="orig" same-2="orig" other="orig"/> </foo> The result: <?xml version="1.0"?> <foo xmlns="urn:test:foo" xmlns:test="urn:test:foo"> <bar same="generated" same-2="new"/> <zoo same="generated" same-2="orig" other="orig"/> </foo>
Fixed now in CVS, libxslt/attributes.c, revision 1.44 and libxslt/namespaces.c 1.28. Thanks for the report! TODO: Add the reduced scenario to the regression tests.