1. Einführung in das Streaming-Parsing
In Java haben sich historisch zwei Ansätze für die Arbeit mit XML herausgebildet.
Wir wissen bereits, dass das DOM (Document Object Model) den Dokumentbaum im Speicher aufbaut. Das Navigieren durch Elemente und deren Bearbeitung ist bequem, aber für große Dateien ist es zu kostspielig: Der Speicher ist schnell erschöpft.
SAX (Simple API for XML) verarbeitet die Datei dagegen sequentiell und löst Ereignisse beim Treffen auf Tags aus. Das ist speicherschonend und erlaubt die Arbeit mit sehr großen Dokumenten. Aber das Schreiben von Handlern ist umständlich, und ein Zurückspringen in der Struktur ist unmöglich.
StAX (Streaming API for XML) entstand als Kompromiss. Es ist ebenfalls streamingbasiert wie SAX, gibt dem Entwickler jedoch mehr Kontrolle: Wir „ziehen“ die Ereignisse selbst aus dem Stream, wenn wir sie benötigen. Dieser Ansatz heißt Pull-Parsing und ermöglicht verständlicheren und flexibleren Code.
Einführung in StAX
StAX (Streaming API for XML) ist ein moderner Streaming-Parser für XML in Java, eingeführt mit JDK 6+.
Hauptidee: Pull-Parsing („ziehender“ Parser).
Im Gegensatz zu SAX, wo der Parser selbst Ihre Methoden aufruft (Push-Modell), steuern Sie bei StAX den Prozess selbst:
Sie fragen den Parser aktiv: „Gib mir das nächste Ereignis!“
Analogie:
SAX ist wie Fernsehen: Ereignisse „strömen“ auf Sie ein, Sie müssen reagieren.
StAX ist wie ein Dienst, bei dem Sie selbst auf „nächstes Video“ klicken, wenn Sie bereit sind.
Schlüsselklassen von StAX
Um mit StAX zu arbeiten, benötigen Sie zwei Hauptklassen aus dem Paket javax.xml.stream:
- XMLInputFactory – Fabrik zum Erstellen von Parsern.
- XMLStreamReader – der eigentliche Streaming-Parser, der XML „in Stücken“ liest.
Beispielcode (Grundlage):
import javax.xml.stream.*;
import java.io.FileInputStream;
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("data.xml"));
while (reader.hasNext()) {
int event = reader.next();
// Ereignis verarbeiten
}
reader.close();
2. Funktionsprinzip von StAX: Pull-Modell
In StAX steuern Sie das Lesen von XML selbst:
- Sie öffnen einen Stream (z. B. eine Datei).
- Sie erstellen einen XMLStreamReader.
- In einer Schleife rufen Sie reader.next() auf, um das nächste Ereignis zu erhalten.
- Sie prüfen den Ereignistyp (START_ELEMENT, END_ELEMENT, CHARACTERS usw.).
- Wenn Sie an der gewünschten Stelle sind – verarbeiten Sie die Daten.
- Sie schließen den Parser.
Ablaufschema:
flowchart TD
A[XMLStreamReader öffnen] --> B{hasNext?}
B -- ja --> C["next()"]
C --> D{Ereignistyp?}
D -- START_ELEMENT --> E[Beginn eines Elements verarbeiten]
D -- CHARACTERS --> F[Text verarbeiten]
D -- END_ELEMENT --> G[Ende eines Elements verarbeiten]
D -- END_DOCUMENT --> H[Beenden]
B -- nein --> H
Worin liegt der Vorteil?
- Sie entscheiden selbst, wann das nächste Element gelesen wird.
- Sie können an der gewünschten Stelle „anhalten“ und nur einen Teil der Datei verarbeiten.
- Keine Vielzahl an Handlern nötig wie bei SAX.
3. Ereignistypen in StAX
Wenn Sie reader.next() aufrufen, liefert der Parser einen Ereignistyp – eine ganze Zahl (Konstante aus dem Interface XMLStreamConstants). Das sind die wichtigsten Ereignistypen:
- START_ELEMENT – Beginn eines XML-Elements (<tag>).
- END_ELEMENT – Ende eines XML-Elements (</tag>).
- CHARACTERS – Textinhalt zwischen Tags.
- END_DOCUMENT – Ende des Dokuments.
Beispiel zur Ereignisbehandlung:
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT:
String name = reader.getLocalName();
System.out.println("Beginn des Elements: " + name);
break;
case XMLStreamConstants.CHARACTERS:
String text = reader.getText().trim();
if (!text.isEmpty()) {
System.out.println("Text: " + text);
}
break;
case XMLStreamConstants.END_ELEMENT:
System.out.println("Ende des Elements: " + reader.getLocalName());
break;
}
}
4. Nützliche Details
Wann sollte man StAX verwenden?
StAX ist die ideale Wahl, wenn:
- die XML-Datei sehr groß ist (Gigabytes) und Sie sie nicht vollständig in den Speicher laden möchten.
- nur ein Teil des Dokuments verarbeitet werden soll (z. B. ein bestimmtes Element finden und anhalten).
- ein einfacher und verständlicher Code benötigt wird: StAX ist einfacher als SAX und erfordert keine Unmenge an Handlern.
Beispielfälle:
- Import einer großen XML-Datei (z. B. Export aus 1C, Kontoauszüge, Produktkataloge).
- Suche und Verarbeitung nur der benötigten Elemente (z. B. nur <transaction> aus einer Million Einträgen).
- Transformation von XML „on the fly“ (z. B. Filtern, Aggregation).
Vergleich von DOM, SAX und StAX
| Ansatz | Speicher | Einfachheit | Flexibilität | Wann verwenden |
|---|---|---|---|---|
| DOM | Hoch (alles im Speicher) | Sehr einfach | Baum kann verändert werden | Kleine/mittlere Dateien, wenn XML bearbeitet werden muss |
| SAX | Minimal | Komplex (Event-Handler) | Nur Lesen, kein Zurückspringen | Sehr große Dateien, einfache Verarbeitung |
| StAX | Minimal | Mittel (Pull-Modell) | Partielles Lesen möglich, leicht anzuhalten | Große Dateien, wenn Flexibilität und Einfachheit benötigt werden |
StAX ist der goldene Mittelweg:
– Verbraucht nicht so viel Speicher wie DOM.
– Erfordert keine komplexen Handler wie SAX.
– Ermöglicht die Steuerung des Parsing-Prozesses.
5. Beispiel: Ein großes XML mit StAX lesen
Nehmen wir an, wir haben die Datei "books.xml":
<library>
<book>
<title>Java für Anfänger</title>
<author>Ivan Ivanov</author>
</book>
<book>
<title>Java für Fortgeschrittene</title>
<author>Pyotr Petrov</author>
</book>
<!-- ... viele Bücher ... -->
</library>
Aufgabe: alle Buchtitel ausgeben.
Code mit StAX:
import javax.xml.stream.*;
import java.io.*;
public class StaxDemo {
public static void main(String[] args) throws Exception {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("books.xml"));
while (reader.hasNext()) {
int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT && "title".equals(reader.getLocalName())) {
reader.next(); // zum CHARACTERS-Ereignis wechseln
System.out.println("Buch: " + reader.getText());
}
}
reader.close();
}
}
Vorteile:
- Wir laden die Datei nicht vollständig in den Speicher.
- Selbst eine Million Bücher lässt sich verarbeiten – das Programm stürzt nicht ab.
6. Typische Fehler beim Arbeiten mit StAX
Fehler Nr. 1: Parser oder Stream nicht geschlossen. Schließen Sie immer den XMLStreamReader und den Stream (InputStream), um Ressourcenlecks zu vermeiden.
Fehler Nr. 2: Ereignistyp wird nicht geprüft. Nicht jedes Ereignis ist der Beginn oder das Ende eines Elements. Prüfen Sie den Ereignistyp, sonst erhalten Sie leere Strings oder übersehen benötigte Daten.
Fehler Nr. 3: Verschachtelung der Elemente wird nicht berücksichtigt. Wenn die XML-Struktur komplex ist (z. B. Bücher innerhalb von Abschnitten), verfolgen Sie die aktuelle Verschachtelungsebene, damit Elemente nicht verwechselt werden.
Fehler Nr. 4: DOM für große Dateien verwendet. Wenn die Datei groß ist – verwenden Sie kein DOM, sonst erhalten Sie eine OutOfMemoryError. Für große Dateien – nur StAX oder SAX.
Fehler Nr. 5: Exceptions werden nicht behandelt. Die Arbeit mit Dateien und XML kann Exceptions auslösen (XMLStreamException, IOException). Behandeln Sie sie oder werfen Sie sie weiter.
GO TO FULL VERSION