Bug #3889
closedNo-namespace element copied without required xmlns="" declaration
100%
Description
FINAL RESOLUTION
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.
ORIGINAL REPORT
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 9.8.0.12 within Oxygen 20.1
Sincelery, Frank Steimke
Files
Updated by Michael Kay about 6 years ago
Am I right in thinking I need to apply c.xsl to form_1.xml and that form_2.xml is the output?
Updated by Michael Kay about 6 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.
Updated by Michael Kay about 6 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.
Updated by Michael Kay about 6 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 header
element.
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>
where the header
element is missing an xmlns=""
declaration to indicate that it is (or should be) in no namespace.
Updated by Michael Kay about 6 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.
Updated by Michael Kay about 6 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 TinyElementNode.copy()
method.
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.
Updated by Michael Kay about 6 years ago
- Status changed from Resolved to In Progress
Reopening. The patch has side-effects, e.g on the JUnit tests for TestCanonicalSerializer - some of these tests are adding an xmlns="" undeclaration where it is not needed.
See also bug #2209 in this area.
Updated by Michael Kay about 6 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.
Updated by Michael Kay about 6 years ago
Sure enough, test namespace-2608 fails: the output contains a redundant xmlns="" declaration.
It seems the change to NamespaceReducer was unnecessary, and it has been reverted. This appears to give clean test results.
Updated by Michael Kay about 6 years ago
- Status changed from In Progress to Resolved
Patch to ComplexContentOutputter committed. Previous patch to TinyElementImpl.copy() reverted. Applies to both 9.8 and 9.9
Updated by O'Neil Delpratt about 6 years ago
- % Done changed from 0 to 100
- Fixed in Maintenance Release 9.9.0.1 added
Bug fix applied in the Saxon 9.9.0.1 major release.
Leave open until fix applied in the next Saxon 9.8 maintenance release.
Updated by O'Neil Delpratt about 6 years ago
- Status changed from Resolved to Closed
- Fixed in Maintenance Release 9.8.0.15 added
Bug fix applied in the Saxon 9.8.0.15 maintenance release.
Please register to edit this issue