By dave | February 17, 2014

In this entry I show how to use the inbuilt Java XMLStreamReader PULL parser class to read an XML file. The XML stream libraries are PULL based XML parsers that do not load the whole document into a memory structure, so therefore are more suited to large volumes of XML.

Below is an example XML file for a zoo, it contains Animal data types that have both attributes and data. It is kept simple for the sake of example. To run the example, copy this XML into the ROOT of your classpath.

<zoo>
    <animal id="5">
        <name>Zeb</name>
        <type>Zebra</type>
        <location>A1B</location>
    </animal>
    <animal id="6">
        <name>Leo</name>
        <type>Lion</type>
        <location>A1C</location>
    </animal>
</zoo>

And then add the following class to your project.

package com.thecoderscorner.example.xmlstream;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * This is a simple XML stream reader example that is fairly much self
 * contained.
 */
public class XmlStreamReader {

    private enum Element {ANIMAL, TYPE, NAME, LOCATION}
    private final XMLInputFactory factory;
    private final Map<String, Element> nameToTypeMapping = new HashMap<>();

    private StringBuilder currentText;
    private Element currentElement;
    private Animal animal;

    /**
     * Create the stream reader class and put in the mappings between
     * element names and the Element type (currentElement). This mapping
     * is used to work out how to handle each data type.
     */
    public XmlStreamReader() {
        factory = XMLInputFactory.newFactory();
        nameToTypeMapping.put("name", Element.NAME);
        nameToTypeMapping.put("type", Element.TYPE);
        nameToTypeMapping.put("location", Element.LOCATION);
        nameToTypeMapping.put("animal", Element.ANIMAL);
    }

    /**
     * Actually performs the read operation on the XML file by repeatedly
     * calling hasNext() and next() until the document ends.
     * @param input the XML stream to read.
     * @throws XMLStreamException if the parsing fails.
     */
    public void readXml(InputStream input) throws XMLStreamException {

        // get an XML reader instance.
        XMLStreamReader xmlReader = factory.createXMLStreamReader(input);

        // before calling next() we can find out key things about the
        // document, because we would now be in XMLEvent.START_DOCUMENT
        // state.
        assert(xmlReader.getEventType() == XMLEvent.START_DOCUMENT);

        // iterate by calling hasNext in a loop until there are no more
        // elements left to process.
        while(xmlReader.hasNext()) {

            // get the next event and process it.
            int eventType = xmlReader.next();
            switch(eventType) {
                case XMLEvent.CDATA:
                case XMLEvent.SPACE:
                case XMLEvent.CHARACTERS:
                    processText(xmlReader.getText());
                    break;
                case XMLEvent.END_ELEMENT:
                    ended(xmlReader.getLocalName());
                    break;
                case XMLEvent.START_ELEMENT:
                    startElement(xmlReader.getLocalName());
                    int attributes = xmlReader.getAttributeCount();
                    for(int i=0;i<attributes;++i) {
                        attribute(xmlReader.getAttributeLocalName(i),
                                xmlReader.getAttributeValue(i));
                    }
                break;
            }
        }
    }

    /**
     * Handles the start of a new XML element, so we can prepare for the new
     * element. In our case we clear down the text storage and set the element
     * type field.
     * @param localName the name of the element without namespace
     */
    private void startElement(String localName) {
        currentElement = nameToTypeMapping.get(localName);
        currentText = new StringBuilder(256);
        if(currentElement == Element.ANIMAL) {
            animal = new Animal();
        }
    }

    /**
     * Called when text is found within the element, this may be whitespace,
     * text or CDATA.
     * @param text the text to be added to the current elements data.
     */
    private void processText(String text) {
        if(currentElement != null && currentText != null) {
            currentText.append(text);
        }
    }

    /**
     * Called for each attribute in the start element call. With the name and
     * value.
     * @param localName the name of the attribute
     * @param value the value of the attribute
     */
    private void attribute(String localName, String value) {
        if(currentElement == Element.ANIMAL && localName.equals("id")) {
            animal.setId(Integer.valueOf(value));
        }
    }

    /**
     * Called each time an element ends, with the name of the element that
     * has just ended.
     * @param localName the element name that has ended
     */
    private void ended(String localName) {
        // find the element type, and see if we can process it.
        currentElement = nameToTypeMapping.get(localName);
        if(currentElement != null) {

            // We can process the element, so perform the right function.
            // In a real world example, the "currentElement" type may be
            // more complex and have functionality to perform the action.
            switch (currentElement) {
                case TYPE:
                    animal.setType(currentText.toString());
                    break;
                case NAME:
                    animal.setName(currentText.toString());
                    break;
                case LOCATION:
                    animal.setLocation(currentText.toString());
                    break;
                case ANIMAL:
                    renderAnimal();
            }
            currentElement = null;
            currentText = null;
        }
    }

    /**
     * Renders an Animal instance onto the console.
     */
    private void renderAnimal() {
        System.out.println("Animal object created: id=" + animal.getId());
        System.out.println("  name=" + animal.getName());
        System.out.println("  type=" + animal.getType());
        System.out.println("  location=" + animal.getLocation());
    }

    public static void main(String[] args) throws XMLStreamException {
        InputStream xmlStream = XmlStreamReader.class.getResourceAsStream("/example.xml");
        XmlStreamReader reader = new XmlStreamReader();
        reader.readXml(xmlStream);
    }
}

And lastly you'll need this Value object, as that is how the above code represents each entry read from the XML.

package com.thecoderscorner.example.xmlstream;

/**
 * Represents the XML animal data type in object form
 */
public class Animal {
    private int id;
    private String type;
    private String name;
    private String location;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }
}

Here is the output of the program

Animal object created: id=5
  name=Zeb
  type=Zebra
  location=A1B
Animal object created: id=6
  name=Leo
  type=Lion
  location=A1C

Process finished with exit code 0

Other pages within this category

comments powered by Disqus

This site uses cookies to analyse traffic, and to record consent. We also embed Twitter, Youtube and Disqus content on some pages, these companies have their own privacy policies.

Our privacy policy applies to all pages on our site

Should you need further guidance on how to proceed: External link for information about cookie management.

Send a message
X

Please use the forum for help with UI & libraries.

This message will be securely transmitted to our servers.