Quick Introduction to generating XML with XmlPull v1 API

This document describes how to use XmlSerializer that is part of XmlPull API to generate/write/serialize XML.

Main features of API

XmlSerializer provides:

Requirements

Before running sample code make sure to have parser that implements XmlPull API 1.1.x  (read relevant part from Quick Introduction)

Writing XML: in few easy steps

All XML generating can be done by using XmlSerializer interface. However before we can start writing we need to obtain instance of class that implements this interface.

XmlPull API allows multiple implementations to be used. To achieve this flexibility serializer class is not created directly but by using configurable factory that is responsible for locating and creating implementation. In general that involves following steps:

In your code as the first thing make sure to import XmlPull v1 API classes:
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
and the code to create serializer may look like this:
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance(
            System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
        XmlSerializer serializer = factory.newSerializer();
Next step is to set serializer output - in this case it is set to write to standard output but can easily redirected to file or socket:
        serializer.setOutput(new PrintWriter( System.out ));
and now we can start using serializer to write XML!

Typical applicaition will write XML declaration and then follow with writing few element start and end tags and their content.

Output must always have at least one start tag:

        serializer.startTag(NAMESPACE, "poem");
then we cna start writing more start tags, text cotnent, and end tags:
        serializer.startTag(NAMESPACE, "title");
        serializer.text("Roses are Red");
        serializer.endTag(NAMESPACE, "title");
where namespace is declared as string constant
private final static String NAMESPACE = "http://www.megginson.com/ns/exp/poetry";

it is possible to chain multiple calls:

        serializer.startTag(NAMESPACE, "l")
	    .text("Roses are red,")
	    .endTag(NAMESPACE, "l");
or put them even in one line:
        serializer.startTag(NAMESPACE, "l").text("Violets are blue;").endTag(NAMESPACE, "l");
but what make API really flexible and modular is to define functions that outputs well defined parts of XML, for example:
    private static void writeLine(XmlSerializer serializer, String line, boolean addNewLine)
        throws IOException {
        serializer.startTag(NAMESPACE, "l");
        serializer.text(line);
        serializer.endTag(NAMESPACE, "l");
        if(addNewLine) serializer.text("\n");
    }
and then to write chunkof XML output it is enough to simply call:
        writeLine(serializer, "Sugar is sweet,", addNewLine);
        writeLine(serializer, "And I love you.,", addNewLine);

Serializer will check that end tag name and namespace is the same as of matching start tag (very good to validate that XML output is correct) so to finish writing XML we should close top level start tag:

        serializer.endTag(NAMESPACE, "poem");

It is important to inform serializer when XML output is finished so any remianing buffered XML output is send to putput stream and serializer will not allow any more input to do this call endDocument():

        serializer.endDocument();

Controlling namespace prefixes

There is no need to manually set prefixes as XmlSerializer will automatically declare prefixes when needed. However sometimes it is necessary to indicate what prefix should be used:
        serializer.setPrefix("ns", NAMESPACE);
or what namespace should be bound as default namespace (to special empty string prefix):
        serializer.setPrefix("", NAMESPACE);

Prefix declaration must be done just before call to start tag and the prefix declaration scope starts on this star tag and finishes when corresponding end tag is reached.

Controlling output formatting

XmlSerializer allows to create any infoset so it is possible to add manually new lines or indentation. for exmaple if would like to have new line after every end tag it is as easy as to call text() with new line:

        if(addNewLine) serializer.text("\n");

If serializer supports optional formatting properties and features then they can be used to have output indented automatically. Read more about them:

 

Sample code

The finished working sample created that was described is in MyXmlWriteApp.java file in src/java/samples directory.

For more information about XmlPull API please visit http://www.xmlpull.org/.

Output from sample application

When new lines are added manually:

java MyXmlWriteApp -n
serializer implementation class is class org.kxml2.io.KXmlSerializer
<?xml version="1.0"?>

<poem xmlns="http://www.megginson.com/ns/exp/poetry">
<title>Roses are Red</title>
<l>Roses are red,</l>
<Violets are blue;</l>
<l>Sugar is sweet,</l>
<l>And I love you.,</l>
</poem>

When using one of optional formatting properties to set indentation:

java MyXmlWriteApp -i 4
serializer implementation class is class org.xmlpull.mxp1_serializer.MXSerializer
<?xml version="1.0"?>

<poem xmlns="http://www.megginson.com/ns/exp/poetry">
    <title>Roses are Red</title>
    <l>Roses are red,</l>
    <l>Violets are blue;</l>
    <l>Sugar is sweet,</l>
    <l>And I love you.,</l>
</poem>

Aleksander Slominski