| API | Class | Style | Performance | Best for |
| Cursor | XMLStreamReader | Stateful cursor; call next() to advance | Highest — no event object allocation | Performance-critical parsing |
| Iterator | XMLEventReader | Returns XMLEvent objects | Slightly lower — allocates event objects | Filtering, pipelining, cleaner code |
import javax.xml.stream.*;
import java.io.*;
import java.util.*;
public class StaxCursorExample {
public static List<String> parseTitles(InputStream xml) throws XMLStreamException {
List<String> titles = new ArrayList<>();
XMLInputFactory factory = XMLInputFactory.newInstance();
// Disable XXE
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader reader = factory.createXMLStreamReader(xml);
try {
boolean inTitle = false;
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT -> {
inTitle = "title".equals(reader.getLocalName());
if ("book".equals(reader.getLocalName())) {
// read attribute
String id = reader.getAttributeValue(null, "id");
System.out.println("Found book id=" + id);
}
}
case XMLStreamConstants.CHARACTERS -> {
if (inTitle) titles.add(reader.getText().trim());
}
case XMLStreamConstants.END_ELEMENT -> {
inTitle = false;
}
}
}
} finally {
reader.close();
}
return titles;
}
}
Always close XMLStreamReader in a finally block or use try-with-resources (it implements AutoCloseable in Java 7+). Failing to close it leaks the underlying stream.
| Constant | Value | Meaning |
START_DOCUMENT | 7 | Start of document |
END_DOCUMENT | 8 | End of document |
START_ELEMENT | 1 | Opening tag |
END_ELEMENT | 2 | Closing tag |
CHARACTERS | 4 | Text content (may be whitespace) |
CDATA | 12 | CDATA section |
COMMENT | 5 | XML comment |
PROCESSING_INSTRUCTION | 3 | Processing instruction |
SPACE | 6 | Ignorable whitespace |
ATTRIBUTE | 10 | Standalone attribute (rare) |
import javax.xml.stream.*;
import javax.xml.stream.events.*;
import java.io.*;
public class StaxIteratorExample {
public static void parse(InputStream xml) throws Exception {
XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
XMLEventReader reader = factory.createXMLEventReader(xml);
try {
while (reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if (event.isStartElement()) {
StartElement start = event.asStartElement();
String name = start.getName().getLocalPart();
if ("book".equals(name)) {
Attribute idAttr = start.getAttributeByName(
new javax.xml.namespace.QName("id"));
System.out.println("Book id: " + (idAttr != null ? idAttr.getValue() : "?"));
}
if ("title".equals(name)) {
// peek at next event (should be Characters)
XMLEvent next = reader.nextEvent();
if (next.isCharacters()) {
System.out.println("Title: " + next.asCharacters().getData().trim());
}
}
}
if (event.isEndElement()) {
String name = event.asEndElement().getName().getLocalPart();
if ("library".equals(name)) break; // early exit cleanly
}
}
} finally {
reader.close();
}
}
}
import javax.xml.stream.*;
import java.io.*;
public class StaxWriteExample {
public static String writeLibrary() throws XMLStreamException {
StringWriter sw = new StringWriter();
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter writer = factory.createXMLStreamWriter(sw);
writer.writeStartDocument("UTF-8", "1.0");
writer.writeCharacters("\n");
writer.writeStartElement("library");
writer.writeCharacters("\n ");
// First book
writer.writeStartElement("book");
writer.writeAttribute("id", "1");
writer.writeAttribute("genre", "technical");
writer.writeStartElement("title");
writer.writeCharacters("Effective Java");
writer.writeEndElement(); // title
writer.writeStartElement("author");
writer.writeCharacters("Joshua Bloch");
writer.writeEndElement(); // author
writer.writeEndElement(); // book
writer.writeCharacters("\n");
writer.writeEndElement(); // library
writer.writeEndDocument();
writer.flush();
writer.close();
return sw.toString();
}
}
XMLStreamWriter does not automatically indent output. For pretty-printed XML, set the javax.xml.stream.isRepairingNamespaces property and manually write whitespace characters, or use a DOM Transformer with OutputKeys.INDENT.
The iterator API supports EventFilter to skip unwanted events before your code sees them.
import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.util.EventReaderDelegate;
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader raw = factory.createXMLEventReader(inputStream);
// Filter: keep only START_ELEMENT and END_ELEMENT events
XMLEventReader filtered = factory.createFilteredReader(raw,
(EventFilter) event -> event.isStartElement() || event.isEndElement());
while (filtered.hasNext()) {
XMLEvent event = filtered.nextEvent();
// only START_ELEMENT and END_ELEMENT events reach here
if (event.isStartElement()) {
System.out.println("Start: " + event.asStartElement().getName().getLocalPart());
}
}
filtered.close();