Java API for XML (JAXP) – StAX

StAX API in JAXP

StAX stands for Streaming API for XML. In the earlier tutorials we have seen DOM (Document Object Model) where a Document tree is created out of the xml and the entire document tree is stored in memory. We have also see the SAX (Simple API for XML) API wherein the parser fires events for different components of the XML and the events need to be handled by the client. Each method of parsing has its pros and cons. In this tutorial we look at the third way of parsing an xml document – StAX. The StAX API makes the XML document available as a stream of events. However, unlike SAX, the client asks for the next event from the parser. The history or state of the XML Document is not maintained and hence the client code needs to store the state in its context. There are two kinds of StAX API :

  • Stream based – The Stream based API considers the XML Document as a stream of XML events. The cursor points to the current event in the XML document. The client can move the cursor forward and retrive the element that the cursor is currently pointing to.
  • Event based – The Event based API presents the XML as a sequence of XMLEvents that the user can request for. The API provides a method called peek that enables the user to peek at the type of next element without actually requesting for the next event.

JAXP provider readers and writers for both the stream API and the reader API. In the examples below we will look at how to read an XML document using the stream and reader API and how to write an XML document using a reader API.

Examples

In the first example we look at parsing an XML document using an event based API.

package com.studytrails.xml.jaxp;

import java.io.IOException;
import java.net.URL;
import java.util.Iterator;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

public class JaxpSTAXExample3 {

	private static String xmlSource = "http://feeds.bbci.co.uk/news/technology/rss.xml?edition=int";

	public static void main(String[] args) throws XMLStreamException, IOException {
		// the XMLInputfactory helps in creating the reader for the XML document
		XMLInputFactory factory = XMLInputFactory.newFactory();
		URL url = new URL(xmlSource);
		// the reader is the main interface that wraps the parser.
		XMLEventReader reader = factory.createXMLEventReader(url.openStream());
		System.out.println(reader.getClass());

		// continue iterating through the reader events till they are available.
		while (reader.hasNext()) {
			// peek at the next event without actually retrieving it
			XMLEvent event = reader.peek();
			// the type of event can be identified
			if (event.getEventType() == XMLEvent.START_ELEMENT) {
				event = reader.nextEvent();
				StartElement startElement = event.asStartElement();
				// System.out.println(startElement.getName().getLocalPart());
				if ("rss".equals(startElement.getName().getLocalPart()))
					handleRSSElement(startElement);
				if ("channel".equals(startElement.getName().getLocalPart()))
					handleChannel(reader);

			}
			if (reader.hasNext())
				reader.next();
		}

	}

	private static void handleChannel(XMLEventReader reader) throws XMLStreamException {
		while (reader.hasNext()) {
			XMLEvent event = reader.peek();
			if (event.isStartElement()) {
				StartElement startElement = reader.nextEvent().asStartElement();
				if ("title".equals(startElement.getName().getLocalPart())) {
					// System.out.println(reader.nextEvent().asCharacters().getData());
				} else if ("image".equals(startElement.getName().getLocalPart())) {
					// create an image object from an image element. This also demonstrates a very basic way of XML-POJO binding.
					Image image = getImage(reader);
					System.out.println("url::" + image.getUrl());
				}
			} else
				reader.next();
		}
	}

	// bind the Image POJO to the XML 'image' element.
	private static Image getImage(XMLEventReader reader) throws XMLStreamException {
		Image image = new Image();
		while (reader.hasNext()) {
			XMLEvent event = reader.nextEvent();
			if (event.isStartElement()) {
				String name = event.asStartElement().getName().getLocalPart().trim();
				if (name.equals("url"))
					image.url = reader.nextEvent().asCharacters().getData();
				else if (name.equals("title"))
					image.title = reader.nextEvent().asCharacters().getData();
				else if (name.equals("link"))
					image.link = reader.nextEvent().asCharacters().getData();
				else if (name.equals("width"))
					image.width = reader.nextEvent().asCharacters().getData();
				else if (name.equals("height"))
					image.height = reader.nextEvent().asCharacters().getData();

			} else if (event.isEndElement()) {
				String name = event.asEndElement().getName().getLocalPart().trim();
				if (name.equals("image"))
					break;

			}
		}
		return image;
	}

	private static void handleRSSElement(StartElement startElement) throws XMLStreamException {
		// find out the namespaces in an element
		Iterator namespaces = startElement.getNamespaces();
		while (namespaces.hasNext()) {
			Namespace namespace = namespaces.next();
			System.out.println(namespace.getPrefix());
			System.out.println(namespace.getNamespaceURI());
		}

	}

	static class Image {
		static String url;
		static String title;
		static String link;
		static String width;
		static String height;

		public static String getUrl() {
			return url;
		}

	}
}




In the second example we look at parsing an XML document using a stream based parser

package com.studytrails.xml.jaxp;

import java.io.IOException;
import java.net.URL;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;

public class JaxpStAXExample7 {
	private static String xmlSource = "http://feeds.bbci.co.uk/news/technology/rss.xml?edition=int";

	public static void main(String[] args) throws XMLStreamException, IOException { 
		//create the input factory
		XMLInputFactory factory = XMLInputFactory.newFactory();
		URL url = new URL(xmlSource);
		// obtain a stream reader
		XMLStreamReader streamReader = factory.createXMLStreamReader(url.openStream());
		//keep moving the cursor forward
		while (streamReader.hasNext()) {
			int event = streamReader.next();
			// check if the element that the cursor is currently pointing to is a start element
			if (event == XMLEvent.START_ELEMENT) {
				// if the cursor is pointing to a start element then get its name
				String name = streamReader.getName().getLocalPart();
				if ("rss".equals(name)) {
					handleRSSElement(streamReader);
				} else if ("channel".equals(name))
					handleChannel(streamReader);
			}
		}
	}

	private static void handleChannel(XMLStreamReader streamReader) throws XMLStreamException {
		while (streamReader.hasNext()){
			int nextEventType = streamReader.next();
			if (nextEventType==XMLEvent.START_ELEMENT){
				String name = streamReader.getName().getLocalPart();
				if ("title".equals(name)){
					// move the cursor one position forward to read the text
					streamReader.next();
					System.out.println(streamReader.getText());
				}
			}
		}
		
	}

	private static void handleRSSElement(XMLStreamReader streamReader) {
		int noOfNamespaces = streamReader.getNamespaceCount();
		for (int i = 0; i < noOfNamespaces; i++) {
			System.out.println(streamReader.getNamespacePrefix(i));
			System.out.println(streamReader.getNamespaceURI(i));
		}

	}
}

Last we look at ways to write to an XML document. In this example we read the bbc xml and rewrite it to a modified xml after changing the title.(we add the word studytrail at the beginning of the title)

package com.studytrails.xml.jaxp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;

import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

public class JaxpStAXWriterExample8 {
	private static String xmlSource = "http://feeds.bbci.co.uk/news/technology/rss.xml?edition=int";

	public static void main(String[] args) throws XMLStreamException, IOException {
		JaxpStAXWriterExample8 writer = new JaxpStAXWriterExample8();
		writer.writeUsingEventWriter();
	}

	public void writeUsingEventWriter() throws XMLStreamException, IOException {
		// create the input factory for obtaining the event reader
		XMLInputFactory factory = XMLInputFactory.newFactory();
		// create the output factory for obtainin the event writer
		XMLOutputFactory outputFactory = XMLOutputFactory.newFactory();
		URL url = new URL(xmlSource);

		// create the event reader
		XMLEventReader reader = factory.createXMLEventReader(url.openStream());
		// creae the event writer
		XMLEventWriter writer = outputFactory.createXMLEventWriter(new FileOutputStream(new File("modified.xml")));

		// the xmlEventFactory can be used to create new XMLEvents of any
		// specific type.
		XMLEventFactory xmlEventFactory = XMLEventFactory.newFactory();
		while (reader.hasNext()) {
			XMLEvent nextEvent = reader.nextEvent();
			if (nextEvent.getEventType() == XMLEvent.START_ELEMENT) {
				StartElement startElement = nextEvent.asStartElement();
				writer.add(startElement);
				if ("title".equals(startElement.getName().getLocalPart())) {
					XMLEvent titleTextEvent = reader.nextEvent();
					String titleText = titleTextEvent.asCharacters().getData();
					// modify the title text
					titleText = "StudyTrails:" + titleText;
					// create a new character event using the modified text and
					// add the new title instead of the existing one
					XMLEvent newTitleTextEvent = xmlEventFactory.createCharacters(titleText);
					writer.add(newTitleTextEvent);
				}
			} else {
				writer.add(nextEvent);
			}
		}
		writer.flush();
		writer.close();
		reader.close();
	}
}


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.