Search code examples
javaxmlstaxwoodstox

How to append XML (String) to XmlEventWriter (StAX) which already created the start of document


In order to create big XML files, we decided to make use of the StAX API. The basic structure is build by using the low-level api's: createStartDocument(), createStartElement(). This works as expected.

However, in some cases we like to append existing XML data which resides in a String (retrieved from database). The following snippet illustrates this:

import java.lang.*;
import java.io.*;
import javax.xml.stream.*;

public class Example {
    public static void main(String... args) throws XMLStreamException {
        XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
        XMLInputFactory inputFactory = XMLInputFactory.newInstance();
        XMLEventFactory eventFactory = XMLEventFactory.newInstance();

        StringWriter writer = new StringWriter();
        XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer);

        eventWriter.add(eventFactory.createStartDocument("UTF-8", "1.0"));
        eventWriter.add(eventFactory.createStartElement("ns0", "http://example.org", "root"));
        eventWriter.add(eventFactory.createNamespace("ns0", "http://example.org"));

        //In here, we want to append a piece of XML which is stored in a string variable.
        String xml = "<fragments><fragment><data>This is pure text.</data></fragment></fragments>";
        eventWriter.add(inputFactory.createXMLEventReader(new StringReader(xml)));

        eventWriter.add(eventFactory.createEndDocument());

        System.out.println(writer.toString());
    }
}

With the above code, depending on the implementation, we are not getting the expected result:

  • Woodstox: The following exception is thrown:'Can not output XML declaration, after output has already been done'. It seems that the XMLEventReader starts off with a startDocument event, but since a startDocument event was already triggered programatically, it throws the error.
  • JDK: It appends <?xml version="1.0" ... <fragments><fragment>... -> Which leads to invalid XML.

I have also tried to append the XML by using:

eventFactory.createCharacters(xml);

The problem here is that even though the XML is appended, the < and > are transformed into &lt and &gt. Therefore, this results in invalid XML.

Am I missing an API that allows me to simply append a String as XML?


Solution

  • You can first consume any StartDocument if necessary:

        String xml = "<fragments><fragment><data>This is pure text.</data></fragment></fragments>";
        XMLEventReader xer = inputFactory.createXMLEventReader(new StringReader(xml));
        if (xer.peek().isStartDocument())
        {
            xer.nextEvent();
        }
        eventWriter.add(xer);