I have data objects that is marshalled to xml and written to file. All objects are generated with xjc, so it is not possible to change objects, package-info.java etc.
The MainElem contains a list of RepeationElems. When marshaling the MainElem with this code:
JAXBContext jaxbContext = JAXBContext.newInstance(MainElem.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(mainElemObj, sw);
I get the following output, which is OK, and validates.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mainelem xmlns="http://schema.blah.com/xx/xxx/1">
<repeatingelem>
<id>123344567</id>
<type>A</type>
</repeatingelem>
<repeatingelem>
<id>98775312</id>
<type>B</type>
</repeatingelem>
</mainelem>
However I ran in to problems with "Out Of Memory". (The RepeatingElem contains much more data than showed, and there can be several 1000 of them)
As a solutions I followed this StreamingMarshal solution How to stream large Files using JAXB Marshaller?
That is write directly to file and one object at the time. Doing this I dont get the same output, and dont know how to get it right.
New code:
JAXBContext context = JAXBContext.newInstance(RepeatingElem.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
XMLOutputFactory xof = XMLOutputFactory.newFactory();
xof.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
XMLStreamWriter xmlOut = xof.createXMLStreamWriter(new FileOutputStream("myXmlFiel"));
xmlOut.setDefaultNamespace("http://schema.blah.com/xx/xxx/1");
xmlOut.writeStartDocument();
xmlOut.writeStartElement("mainelem");
for(RepeatingElem elem: elemList){
JAXBElement<RepeatingElem> element = new JAXBElement<>(new QName(null, "repeatingelem"), RepeatingElem.class, elem);
marshaller.marshal(element, xmlOut);
}
xmlOut.writeEndDocument();
xmlOut.close();
This results in a xml that is not OK, and it does not validate.
<?xml version="1.0" ?>
<mainelem xmlns="http://schema.blah.com/xx/xxx/1">
<repeatingelem xmlns=""
xmlns:ns2="http://schema.blah.com/xx/xxx/1">
<ns2:id>123344567</ns2:id>
<ns2:type>A</ns2:type>
</repeatingelem
<repeatingelem xmlns=""
xmlns:ns2="http://schema.blah.com/xx/xxx/1">
<ns2:id>98775312</ns2:id>
<ns2:type>B</ns2:type>
</repeatingelem>
</mainelem>
I dont want the empty xmlns="" and not the ns2: either. Also the xml-tag should have encoding.
I have tried with and without:
xof.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
xmlOut.setPrefix("ns2", "http://schema.blah.com/xx/xxx/1");
xmlOut.setDefaultNamespace("http://schema.blah.com/xx/xxx/1");
xmlOut.writeStartElement("ns0", "mainelem", "http://schema.blah.com/xx/xxx/1");
Nothig removes the xmlns="" on the RepeatingElem.
The XSD look like:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schema.blah.com/xx/xxx/1"
targetNamespace="http://schema.blah.com/xx/xxx/1" elementFormDefault="qualified"
attributeFormDefault="unqualified" version="1.0.0">
<xsd:element name="mainelem">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="repeatingelem" type="Rep" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="Rep">
<xsd:element name="id" type="xsd:string"/>
<xsd:element name="type" xsd:string"/> type="TimeStamp"/>
...
</xsd:complexType>
</xsd:schema>
UPDATE I have updated the jaxb version to 4.0.4 with no change in the output
If I remove:
xof.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
xmlOut.setDefaultNamespace("http://schema.blah.com/xx/xxx/1");
and add:
xmlOut.writeAttribute("xlmns", "http://schema.blah.com/xx/xxx/1");
I get
<?xml version="1.0" ?>
<mainelem xmlns="http://schema.blah.com/xx/xxx/1">
<repeatingelem xmlns:ns2="http://schema.blah.com/xx/xxx/1">
<ns2:id>123344567</ns2:id>
<ns2:type>A</ns2:type>
</repeatingelem>
...
So the empty xmlns="" was fixed! But it does not validate, I think the ns2 is the problem. How do I solve this?
EDIT: the following removed the problematic ns2
Changing:
JAXBElement<RepeatingElem> element = new JAXBElement<>(new QName(null, "repeatingelem"), RepeatingElem.class, elem);
To:
JAXBElement<RepeatingElem> element = new JAXBElement<>(new QName("http://schema.blah.com/xx/xxx/1", "repeatingelem", XMLConstants.DEFAULT_NS_PREFIX), RepeatingElem.class, elem);
With the newer version of jaxb 4.0.4 (thanks @Laurent Schoelens) and some changes the result is now validating. The empty xmlns-attribute and the faulty namspace ns2 is gone!
NEW CODE:
JAXBContext context = JAXBContext.newInstance(Repeatingelem.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
XMLStreamWriter xmlOut = XMLOutputFactory.newFactory().createXMLStreamWriter(new FileOutputStream("myXmlFile"));
xmlOut.writeStartDocument();
xmlOut.writeStartElement("mainelem");
xmlOut.writeAttribute("xmlns", "http://schema.blah.com/xx/xxx/1");
for(RepeatingElem elem: elemList){
JAXBElement<RepeatingElem> element = new JAXBElement<>(new QName("http://schema.blah.com/xx/xxx/1", "repeatingelem", XMLConstants.DEFAULT_NS_PREFIX), Repeatingelem.class, elem);
marshaller.marshal(element, xmlOut);
}
xmlOut.writeEndDocument();
xmlOut.close();
The output is as:
<?xml version="1.0" ?>
<mainelem xmlns="http://schema.blah.com/xx/xxx/1">
<repeatingelem xmlns="http://schema.blah.com/xx/xxx/1">
<id>123344567</id>
<type>A</type>
</repeatingelem>
<repeatingelem xmlns="http://schema.blah.com/xx/xxx/1">
...
Still the repeating-element has an extra xmlns attribute that is not present when marshalling "all-in-one" with the Mainelem, but it validates so maybe that is good enough.