How to remove empty xmlns="" on repeating elements in JAXB writing to file?

76 Views Asked by At

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);
2

There are 2 best solutions below

0
On BEST ANSWER

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.

6
On

You should upgrade to latest jaxb-ri / jaxb-impl version 4.0.4

This is a known issue in 4.0.3 which was fixed here in 4.0.4 release