Generating XML File Using Java Streaming API for XML (StAX) – A Clean Tutorial

This tutorial is about creating a XML file using the Streaming API for XML (StAX). If you want to know the basic of what is StAX, continue reading the following block of text from Wikipedia, else you can jump to the code section.

Streaming API for XML (StAX) is an application programming interface (API) to read and write XML documents, originating from the Java programming language community.

Traditionally, XML APIs are either:

  • Tree based – the entire document is read into memory as a tree structure for random access by the calling application
  • Event based – the application registers to receive events as entities are encountered within the source document.

Both have advantages; the former (for example, DOM) allows for random access to the document, the latter (e.g. SAX) requires a small memory footprint and is typically much faster.

These two access metaphors can be thought of as polar opposites. A tree based API allows unlimited, random access and manipulation, while an event based API is a ‘one shot’ pass through the source document.

StAX was designed as a median between these two opposites. In the StAX metaphor, the programmatic entry point is a cursor that represents a point within the document. The application moves the cursor forward – ‘pulling’ the information from the parser as it needs. This is different from an event based API – such as SAX – which ‘pushes’ data to the application – requiring the application to maintain state between events as necessary to keep track of location within the document. [Source: Wikipedia]

package com.kushal.xml;

/**
 * GenerateXMLUsingXMLEventFactory.java
 * @Author Kushal Paudyal
 * www.sanjaal.com/java
 * 
 * Demonstrates the use of StAX (Streaming API for XML) in creating XML file.
 */
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndDocument;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartDocument;
import javax.xml.stream.events.StartElement;

public class GenerateXMLUsingXMLEventFactory {

	public static void main(String[] args) throws Exception {
		/**Generate Streaming XML and write it to console**/
		generateXML(System.out);

		/** Regenerate the Streaming XML and write it to File**/
		generateXML(new FileOutputStream("C:/temp/myStAXgenerated.xml"));
	}

	public static void generateXML(OutputStream stream) throws Exception {

		/**
		 * Create a new instance of the XMLEventFactory object
		 */
		XMLEventFactory xmlEventFactory = XMLEventFactory.newInstance();
		/**
		 * Create a new instance of the XMLOutputFactory object
		 */
		XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();

		/**
		 * Create a new XMLEventWriter object using the XMLOuputFactory Object
		 * The parameter denotes that the output will be done in XML.
		 */
		XMLEventWriter writer = outputFactory.createXMLEventWriter(stream);

		/**
		 * Creates a new instance of a StartDocument event
		 * First Parameters: Document Encoding
		 * Second Parameter: version
		 */
		StartDocument startDocument = xmlEventFactory.createStartDocument(
				"UTF-8", "1.0");

		/**Add this document to the writer**/
		writer.add(startDocument);

		/**
		 * Create a new StartElement object and add it to the event writer.
		 * The StartElement interface provides access to information about start elements. 
		 * A StartElement is reported for each Start Tag in the document. 
		 * 
		 * This defaults the NamespaceContext to an empty NamespaceContext. Querying this event for 
		 * its namespaces or attributes will result in an empty iterator being returned. 
		 * 
		 * Parameter 1: Prefix - the prefix of the QName of the new StartElement 
		 * Parameter 2: Namespace URI - the uri of the QName of the new StartElement
		 * Parameter 3:	Local Name - the local name of the QName of the new StartElement
		 */
		StartElement startElement = xmlEventFactory.createStartElement("", "",
				"University");
		writer.add(startElement);

		/**
		 * We will then create an attribute list to be used for another element - Department
		 */
		Attribute name = xmlEventFactory.createAttribute("Name",
				"Computer Science");
		Attribute campus = xmlEventFactory.createAttribute("Campus",
				"North Campus");
		List attributeList = Arrays.asList(name, campus);

		List nsList = Arrays.asList();

		StartElement departStartElement = xmlEventFactory.createStartElement(
				"", "", "Department", attributeList.iterator(), nsList
						.iterator());
		writer.add(departStartElement);

		/**
		 * Under each department, we will create a student that has two sub elements:
		 * Name and Roll
		 */

		StartElement studentStarElement = xmlEventFactory.createStartElement(
				"", "", "Student");
		writer.add(studentStarElement);

		StartElement studentNameStartElement = xmlEventFactory
				.createStartElement("", "", "Name");
		writer.add(studentNameStartElement);
		Characters studentNameChars = xmlEventFactory
				.createCharacters("John Doe");
		writer.add(studentNameChars);
		EndElement studentNameEndElement = xmlEventFactory.createEndElement("",
				"", "Name");
		writer.add(studentNameEndElement);

		StartElement rollStartElement = xmlEventFactory.createStartElement("",
				"", "Roll");
		writer.add(rollStartElement);
		Characters rollChars = xmlEventFactory.createCharacters("2134");
		writer.add(rollChars);
		EndElement rollEndElement = xmlEventFactory.createEndElement("", "",
				"Roll");
		writer.add(rollEndElement);

		/**Ending the student Tag**/
		EndElement studentEndElement = xmlEventFactory.createEndElement("", "",
				"Student");
		writer.add(studentEndElement);

		/**Ending other Tags**/
		EndDocument endDocument = xmlEventFactory.createEndDocument();
		writer.add(endDocument);

		/**
		 * Flush the content to console (as we used System.out in the EventWriter parameter.
		 * If you use FileStream, it will be flushed to file.
		 */
		writer.flush();
		/**
		 * Remember to close the XMLEventWriter
		 */
		writer.close();
		stream.close();
	}
	
	/*
	 * SANJAAL CORPS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
	 * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
	 * LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
	 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SANJAAL CORPS SHALL NOT BE
	 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
	 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
	 * 
	 * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
	 * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
	 * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
	 * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
	 * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
	 * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
	 * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). SANJAAL CORPS
	 * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
	 * HIGH RISK ACTIVITIES.
	 */

}

The following was the output XML. Note that the program above prints output to Console and File – although it prints the same content. The XML Formatting seems to be an issue in the StAX. No neat way of formatting the output XML was available. The following XML file was ‘hand-formatted’.