No-namespace element copied without required xmlns="" declaration
When an element node is copied from a TinyTree, and the element is in a namespace but has a descendant that is in no namespace, and the node is copied to another tree where a default namespace is in scope, then no namespace undeclaration is added to the target tree and the no-namespace element therefore ends up incorrectly being in the default namespace of the target tree.
Hi, an xslt script pricuces a document which is invalid. This is not detected, although the template states validation='strict'. Pleas see attached files.
I have a schema a.xsd for targetNamespace a with elementFormDefault="unqualified". It defines a global type with a header element.
b.xsd is imported in an schema b.xsd with targetNamespace b.xsd. There is a global b:request element defined. Valid instance is a b:request element with header as a child element from the schema a. header is in no namespace.
There is another schema c.xsd in the c namespace which imports b.xsd. It has a global element form which may have an optional b:request child element. A valid instance is a form element with c as default namespace. `<form xmlns="test.com/c" DATA`
There is a simple xstl script which takes a c:form Element and adds a valid b:request element. The result should b a valid c:form element. However, when i accidentialy ust xsl:sequence instead of xsl:copy-of, the result is an invalid document, because the header element is in the default namespace c
Bug report: the transformation script says validation=strict, so that this error should be detected. But it is not detected. Script runs without any problems, but the result is indeed invalid.
This Happens with Saxon EE 18.104.22.168 within Oxygen 20.1
Sincelery, Frank Steimke
#2 Updated by Michael Kay almost 2 years ago
Problem reproduced. I think the problem is not so much that the result tree isn't validated, as the fact that it is incorrectly serialized: the header element is created in no namespace, so it should be serialized with an xmlns="" undeclaration, which would make it valid. I think that somehow the NamespaceReducer which would normally be added to the output pipeline and which would create this undeclaration isn't there, or is in the wrong place in the pipeline relative to the two validators.
#3 Updated by Michael Kay almost 2 years ago
There is a
NamespaceReducer on the pipeline, but it is not adding the
xmlns="" undeclaration because the
startElement event has the property
NAMESPACE_OK (=64), indicating that the caller asserts that there is no need for the
NamespaceReducer to take this action.
The validated element has in fact been placed on a temporary TinyTree (for reasons that might be worth investigating separately...) and is being copied from the TinyTree to the XMLEmitter with copyOptions correctly set to ALL_NAMESPACES.
The code for copying an element from a TinyTree is assuming, I think, that all required local namespace declarations (and undeclarations) are present in the tree. But in this case they are not. In fact, a no-namespace element in a TinyTree build by parsing a source document does not have a local namespace binding for
xmlns="" unless the undeclaration was explicitly present in the lexical XML source.
#4 Updated by Michael Kay almost 2 years ago
It looks as if this has nothing to do with schema validation. A typeless version of the same transformation also fails to add an xmlns="" declaration to the serialized form of the
In fact the stylesheet can be reduced to a non-schema-aware stylesheet with the single template rule:
<xsl:template match="/*"> <xsl:copy> <xsl:sequence select="doc('b.xml')/b:request"/> </xsl:copy> </xsl:template>
to demonstrate the problem: the output is:
<?xml version="1.0" encoding="UTF-8"?> <form xmlns="test.com/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <b:request xmlns:b="test.com/b"> <header>HEADER</header> <b:service>SERVICE</b:service> </b:request> </form>
header element is missing an
xmlns="" declaration to indicate that it is (or should be) in no namespace.
#5 Updated by Michael Kay almost 2 years ago
- Subject changed from Invalid document not detected although validation=strict to No-namespace element copied without required xmlns="" declaration
- Category set to XSLT conformance
- Status changed from New to In Progress
- Assignee set to Michael Kay
- Priority changed from Low to Normal
- Applies to branch 9.8, trunk added
I have modified the bug title to reflect its newly-discovered nature. It's fairly remarkable that such a basic fault should get through the thousands of tests we run! I have added a new test case namespace-1901 to the W3C XSLT test suite.
#6 Updated by Michael Kay almost 2 years ago
- Status changed from In Progress to Resolved
- Fix Committed on Branch 9.8, trunk added
Note that the problem does not occur with -tree:linked. Therefore it would be appropriate to try and fix it within the
I've added the appropriate code to TinyElementNode.copy() and the test is working. It's a little unfortunate that it's adding code to a mainstream path, but I don't see an easy alternative.
#9 Updated by Michael Kay almost 2 years ago
I think my earlier observation that the problem was not present with the linked tree was incorrect. Running namespace-1901 from the Transform command line with -tree:linked gives the incorrect output.
So I'm now looking at the ComplexContentOutputter / NamespaceReducer combination to see how this should be tackled.
Firstly in CCO startContent we currently skip the checkProposedPrefix() check for a no-namespace element. It seems that this is not safe.
Secondly, in NamespaceReducer.isNeeded(), we decide (after performing various other checks) that a default namespace declaration is not needed. Again, this seems unsafe.
If we make these changes, test namespace-1901 succeeds with both tinyTree and linkedTree. But I strongly suspect this will have side-effects.
Please register to edit this issue