Skip to content
Advertisement

How to add XML elements from List into XMLEventWriter? Append XML to already created XMLEventWriter/XmlStreamWriter

I have a List<String> which contains the XML events created as a part of the output from the JAXB Marshaling approach. After completion of the JAXB Marshaling process this List<String> can contain large amounts of XML.

These XML fragments so are part of a large XML. The large XML has some additional header elements so I am trying to create the large XML using the XMLEventWriter and trying to add the elements from my LIST<String> but it does not work as expected and running into various errors.

I get the following error:

Exception in thread "main" javax.xml.stream.XMLStreamException: Trying to output second root

Following is the code I have:

import javax.xml.namespace.QName;
import javax.xml.stream.*;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

public class TestMain {
    public static void main(String[] args) throws XMLStreamException {
        final XMLEventWriter xmlEventWriter = XMLOutputFactory.newInstance().createXMLEventWriter(System.out);
        final XMLEventFactory events = XMLEventFactory.newInstance();
        List<String> eventList = new ArrayList<>();
        eventList.add("<fragment><data>First Event</data></fragment>");
        eventList.add("<fragment><data>Second Event</data></fragment>");
        eventList.add("<another><data>Third Event</data></another>");

        xmlEventWriter.add(events.createStartDocument());
        xmlEventWriter.add(events.createStartElement(new QName("root"), null, null));
        xmlEventWriter.add(events.createStartElement(new QName("fragments"), null, null));
        for (String event : eventList) {
            final XMLEventReader xer = XMLInputFactory.newInstance().createXMLEventReader(new StringReader(event));
            if (xer.peek().isStartDocument()) {
                xer.nextEvent();
                xmlEventWriter.add(xer);
            }
        }
        xmlEventWriter.add(events.createEndDocument());
        xmlEventWriter.add(events.createEndDocument());
        xmlEventWriter.close();


    }
}

Following is the output I am expecting:

<root>
    <fragments>
        <fragment>
            <data>First Event</data>
        </fragment>
        <fragment>
            <data>Second Event</data>
        </fragment>
        <another>
            <data>Third Event</data>
        </another>
    </fragments>
</root>

I looked into XMLStreamWriter but I got to know that this cannot be done using that. I am not particular about XMLEventWriter. All I want to is get the required output using any of the approaches/libraries.

Can someone please help me with this? I just want to add the XML from my List to XMLEventWriter which has been created already with few Nodes.

Answer

First, your ending events are wrong:

xmlEventWriter.add(events.createEndDocument());
xmlEventWriter.add(events.createEndDocument());

They should be:

xmlEventWriter.add(events.createEndElement(new QName("fragments"), null));
xmlEventWriter.add(events.createEndElement(new QName("root"), null));
xmlEventWriter.add(events.createEndDocument());

Second, the issue is that the xer event reader ends with an “End Document” event that you don’t want copied, so you need to filter it out.

To do that, wrap xer with a delegate that ends the event stream when the “End Document” event is reached:

xer = new EventReaderDelegate(xer) {
    @Override
    public boolean hasNext() {
        if (! super.hasNext())
            return false;
        try {
            return ! super.peek().isEndDocument();
        } catch (@SuppressWarnings("unused") XMLStreamException ignored) {
            return true;
        }
    }
};
Advertisement