I have some JAXB classes that are supposed to map XML that may contain unknown elements which it should preserve.
I created a tiny testcase for this with two classes Thing
and Subthing
, where Thing
also has an @XmlAnyElement List<Element>
property.
Source XML, with line wraps and indentation added for readability:
<a:thing xmlns:a="some:uri:a">
<a:subthing val="1"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p/>
</div>
<b:something xmlns:b="some:uri:b"/>
</a:thing>
Result after unmarshal and marshal, again formatted for readability:
<a:thing xmlns:a="some:uri:a">
<a:subthing val="1"/>
<div:div xmlns="http://www.w3.org/1999/xhtml"
xmlns:div="http://www.w3.org/1999/xhtml">
<p/>
</div:div>
<b:something xmlns:b="some:uri:b"/>
</a:thing>
Notice that the div element now has a div namespace prefix and corresponding attribute. It's valid and equivalent to the input, but I don't trust that whatever is supposed to consume this later will handle it correctly (especially since in this case it's html (even though it's xhtml), but it could be something else too).
I checked the unmarshalled object using the debugger, and the DOM element does not have the prefix, so it seems the marshaller adds this prefix.
Is there any way to prevent this?
Complete source:
package-info.java
@XmlSchema(namespace = "some:uri:a", xmlns = {
@XmlNs(prefix = "a", namespaceURI = "some:uri:a")
})
package p;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlSchema;
Thing.java
package p;
import org.w3c.dom.Element;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
@XmlRootElement(namespace = "some:uri:a")
public class Thing {
@XmlElement(namespace = "some:uri:a")
public Subthing subthing;
@XmlAnyElement
public List<Element> other;
}
Subthing.java
package p;
import javax.xml.bind.annotation.XmlAttribute;
class Subthing {
@XmlAttribute
public int val;
}
Test case (groovy syntax):
@Test
void opaqueXMLNamespaceHandling2() {
def xml = '<a:thing xmlns:a="some:uri:a"><a:subthing val="1"/><div xmlns="http://www.w3.org/1999/xhtml"><p/></div><b:something xmlns:b="some:uri:b"/></a:thing>'
JAXBContext ctx = JAXBContext.newInstance(Thing.class, Subthing.class);
Unmarshaller unmarshaller = ctx.createUnmarshaller();
def thing = (Thing) unmarshaller.unmarshal(new StringReader(xml));
println thing.subthing.val
Marshaller m = ctx.createMarshaller();
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
StringWriter sw = new StringWriter();
m.marshal(thing, sw)
println sw.toString()
thing = (Thing) unmarshaller.unmarshal(new StringReader(sw.toString()));
println thing.subthing.val
}