Bug #6387
closednon-qualified elements declare illegal prefix-emptyNamespace mapping
100%
Description
I have a Camel-XQuery application which processes SOAP messages using CXF and Undertow transport.
Roughly the stack trace looks like this:
org.apache.cxf.interceptor.Fault: Could not generate the XML stream caused by: javax.xml.stream.XMLStreamException: Non-default namespace can not map to empty URI (as per Namespace 1.0 # 2) in XML 1.0 documents.
at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:130) ~[cxf-core-4.0.2.jar:4.0.2]
at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:67) ~[cxf-core-4.0.2.jar:4.0.2]
at org.apache.camel.component.cxf.jaxws.HybridSourceDataBinding$1.write(HybridSourceDataBinding.java:73) ~[camel-cxf-soap-4.0.0.jar:4.0.0]
...
at org.apache.cxf.transport.http_undertow.CxfUndertowServlet.invoke(CxfUndertowServlet.java:51) ~[cxf-rt-transports-http-undertow-4.0.2.jar:4.0.2]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:303) ~[cxf-rt-transports-http-4.0.2.jar:4.0.2]
...
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:278) ~[cxf-rt-transports-http-4.0.2.jar:4.0.2]
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) ~[undertow-servlet-2.3.10.jar:2.3.10]
...
at io.undertow.servlet.spec.AsyncContextImpl$TaskDispatchRunnable.run(AsyncContextImpl.java:553) ~[undertow-servlet-2.3.10.jar:2.3.10]
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18) ~[jboss-threads-3.5.0.Final.jar:3.5.0.Final]
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513) ~[jboss-threads-3.5.0.Final.jar:3.5.0.Final]
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1512) ~[jboss-threads-3.5.0.Final.jar:3.5.0.Final]
at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282) ~[xnio-api-3.8.8.Final.jar:3.8.8.Final]
at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]
Caused by: javax.xml.stream.XMLStreamException: Non-default namespace can not map to empty URI (as per Namespace 1.0 # 2) in XML 1.0 documents
at com.ctc.wstx.sw.BaseStreamWriter.throwOutputError(BaseStreamWriter.java:1596) ~[woodstox-core-6.5.1.jar:6.5.1]
at com.ctc.wstx.sw.SimpleNsStreamWriter.writeNamespace(SimpleNsStreamWriter.java:135) ~[woodstox-core-6.5.1.jar:6.5.1]
at org.apache.cxf.staxutils.StaxUtils.writeStartElement(StaxUtils.java:835) ~[cxf-core-4.0.2.jar:4.0.2]
...
at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:126) ~[cxf-core-4.0.2.jar:4.0.2]
... 41 common frames omitted
This stack trace shows a problem where CXF/StAX tries to process an element without namespace where its parent element is namespaced.
After digging the problem more, I tracked down how the problematic DOM is created and the stack trace is:
"XNIO-3 task-3@16475" prio=5 tid=0x59 nid=NA runnable
java.lang.Thread.State: RUNNABLE
at net.sf.saxon.dom.DOMWriter.startElement(DOMWriter.java:164)
at net.sf.saxon.event.TreeReceiver.startElement(TreeReceiver.java:148)
at net.sf.saxon.event.ComplexContentOutputter.startContent(ComplexContentOutputter.java:782)
at net.sf.saxon.event.ComplexContentOutputter.characters(ComplexContentOutputter.java:272)
at net.sf.saxon.event.ComplexContentOutputter.decompose(ComplexContentOutputter.java:846)
at net.sf.saxon.event.ComplexContentOutputter.append(ComplexContentOutputter.java:661)
at net.sf.saxon.event.Outputter.append(Outputter.java:341)
at net.sf.saxon.expr.elab.PullElaborator.lambda$elaborateForPush$0(PullElaborator.java:40)
at net.sf.saxon.expr.elab.PullElaborator$$Lambda$1611/0x00007f317c9a8450.processLeavingTail(Unknown Source:-1)
at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator.lambda$elaborateForPush$0(FixedElement.java:653)
at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator$$Lambda$1612/0x00007f317c9a8678.processLeavingTail(Unknown Source:-1)
at net.sf.saxon.expr.instruct.Block$BlockElaborator.lambda$elaborateForPush$4(Block.java:898)
at net.sf.saxon.expr.instruct.Block$BlockElaborator$$Lambda$1613/0x00007f317c9a88a0.processLeavingTail(Unknown Source:-1)
at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator.lambda$elaborateForPush$0(FixedElement.java:653)
at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator$$Lambda$1612/0x00007f317c9a8678.processLeavingTail(Unknown Source:-1)
at net.sf.saxon.expr.instruct.Block$BlockElaborator.lambda$elaborateForPush$2(Block.java:864)
at net.sf.saxon.expr.instruct.Block$BlockElaborator$$Lambda$1615/0x00007f317c9a8cf0.processLeavingTail(Unknown Source:-1)
at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator.lambda$elaborateForPush$0(FixedElement.java:653)
at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator$$Lambda$1612/0x00007f317c9a8678.processLeavingTail(Unknown Source:-1)
at net.sf.saxon.expr.instruct.Block$BlockElaborator.lambda$elaborateForPush$1(Block.java:854)
at net.sf.saxon.expr.instruct.Block$BlockElaborator$$Lambda$1616/0x00007f317c9a8f18.processLeavingTail(Unknown Source:-1)
at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator.lambda$elaborateForPush$0(FixedElement.java:653)
at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator$$Lambda$1612/0x00007f317c9a8678.processLeavingTail(Unknown Source:-1)
at net.sf.saxon.expr.instruct.UserFunction.process(UserFunction.java:712)
at net.sf.saxon.expr.UserFunctionCall$UserFunctionCallElaborator.lambda$elaborateForPush$5(UserFunctionCall.java:846)
at net.sf.saxon.expr.UserFunctionCall$UserFunctionCallElaborator$$Lambda$1607/0x00007f317c9a1788.processLeavingTail(Unknown Source:-1)
at net.sf.saxon.query.XQueryExpression.processQuery(XQueryExpression.java:499)
at net.sf.saxon.query.XQueryExpression.run(XQueryExpression.java:473)
at org.apache.camel.component.xquery.XQueryBuilder.evaluateAsDOM(XQueryBuilder.java:234)
at org.apache.camel.component.xquery.XQueryBuilder.evaluate(XQueryBuilder.java:194)
at org.apache.camel.component.xquery.XQueryBuilder.evaluate(XQueryBuilder.java:169)
...
at org.apache.camel.support.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:65)
at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:383)
...
at org.apache.camel.component.cxf.jaxws.CxfConsumer$CxfConsumerInvoker.invoke(CxfConsumer.java:162)
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
...
at org.apache.cxf.transport.http_undertow.UndertowHTTPHandler.handleRequest(UndertowHTTPHandler.java:122)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:393)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859)
...
at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)
at java.lang.Thread.run(Thread.java:842)
The document being processed looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<msg:soap-message xmlns:msg="http://data.example.com">
<header:header-container xmlns:header="http://header.example.com">
<header:header1>
<id>12</id>
<system-id>33</system-id>
<time />
According to XSD, msg:soap-message, header:header-container and header:header1 are qualified elements, but id, system-id and time are defined like this:
<xsd:complexType name="header1">
<xsd:sequence>
<xsd:element name="id" nillable="true" type="xsd:string">
</xsd:element>
<xsd:element name="system-id" nillable="true" type="xsd:string">
</xsd:element>
...
because id and system-id don't have form
attribute and there's no explicit elementFormDefault="qualified"
, these elements effective are in no namespace at all.
When taking this document literally and parsing it using standard JAXP DOM, I can confirm it by printing QNames and namespaces:
<?xml version="1.0" encoding="UTF-8"?>
<msg:soap-message> (msg:http://data.example.com)
<header:header-container> (header:http://header.example.com)
<header:header1> (header:http://header.example.com)
<id> (null:null)
<system-id> (null:null)
<time> (null:null)
...
When changing this document to:
<?xml version="1.0" encoding="UTF-8"?>
<msg:soap-message> (msg:http://data.example.com)
<header:header-container> (header:http://header.example.com)
<header:header1> (header:http://header.example.com)
<id xmlns:header=""> (null:null)
<system-id> (null:null)
<time> (null:null)
...
I'm getting:
[Fatal Error] :5:32: The value of the attribute "prefix="xmlns",localpart="header",rawname="xmlns:header"" is invalid. Prefixed namespace bindings may not be empty.
org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 32; The value of the attribute "prefix="xmlns",localpart="header",rawname="xmlns:header"" is invalid. Prefixed namespace bindings may not be empty.
at java.xml/com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:261)
at java.xml/com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
at java.xml/javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:122)
...
And this is exactly what Saxon-HE 12.4 is doing in net.sf.saxon.dom.DOMWriter#startElement()
:
- elemName parameter is "id"
- attributes parameter is net.sf.saxon.om.EmptyAttributeMap
- namespaces parameter is:
namespaces = {net.sf.saxon.om.NamespaceMap@12206} ""
prefixes: java.lang.String[] = {java.lang.String[0]@16626} []
uris: net.sf.saxon.om.NamespaceUri[] = {net.sf.saxon.om.NamespaceUri[0]@16627}
nsStack.peek()
passed to namespaces.getDifferences()
is:
parentNamespaces = {net.sf.saxon.om.NamespaceMap@16534} "header=http://header.example.com "
prefixes: java.lang.String[] = {java.lang.String[1]@16633} ["header"]
uris: net.sf.saxon.om.NamespaceUri[] = {net.sf.saxon.om.NamespaceUri[1]@16634}
0 = {net.sf.saxon.om.NamespaceUri@16638} "http://header.example.com"
While parentNamespaces
is fine (matches NS declarations of parent "header:header1" element, the result of namespaces.getDifferences()
is:
declarations = {net.sf.saxon.om.NamespaceBinding[1]@16546}
0 = {net.sf.saxon.om.NamespaceBinding@16642} "header="
prefix: java.lang.String = {@16635} "header"
uri: net.sf.saxon.om.NamespaceUri = {net.sf.saxon.om.NamespaceUri@16644} ""
It means that in element "id", org.w3c.dom.Element#setAttributeNS()
is called with:
- namespace:
http://www.w3.org/2000/xmlns/
- qname:
xmlns:header
- nsURI (value):
""
(empty string)
In my opinion, net.sf.saxon.om.NamespaceMap#getDifferences()
should not simply do:
} else if (j < other.prefixes.length) {
// prefix present in other map, absent from this: add an undeclaration
result.add(new NamespaceBinding(other.prefixes[j], NamespaceUri.NULL));
it CAN'T add NULL namespace URI when prefix is not empty.
Sorry for not providing full reproducer, but I hope my analysis is enough.
kind regards Grzegorz Grzybek
Please register to edit this issue