1. Introduzione al parsing in streaming
Storicamente in Java si sono affermati due approcci al lavoro con XML.
Sappiamo già che DOM (Document Object Model) costruisce in memoria l’albero del documento. È comodo spostarsi tra gli elementi e modificarli, ma per file grandi è troppo costoso: la memoria finisce in fretta.
SAX (Simple API for XML), a sua volta, elabora il file in modo sequenziale e genera eventi al passaggio dei tag. È parsimonioso con la memoria e consente di lavorare con documenti enormi. Tuttavia, scrivere i gestori è scomodo e non è possibile tornare indietro nella struttura.
StAX (Streaming API for XML) è nato come compromesso. È anch’esso in streaming, come SAX, ma dà al programmatore più controllo: siamo noi a “tirare” gli eventi dallo stream quando serve. Questo approccio si chiama pull parsing e consente di scrivere codice più chiaro e flessibile.
Introduzione a StAX
StAX (Streaming API for XML) è un parser XML moderno in streaming per Java, introdotto in JDK 6+.
Idea principale: modello pull («parser che tira»).
A differenza di SAX, dove il parser invoca da solo i vostri metodi (modello push), con StAX siete voi a gestire il processo:
Siete voi a chiedere al parser: «Dammi il prossimo evento!»
Analogia:
SAX è come la TV: gli eventi «ti piovono addosso» e devi reagire.
StAX è come un servizio in cui premi tu «video successivo» quando sei pronto.
Classi chiave di StAX
Per lavorare con StAX, vi servono due classi principali dal package javax.xml.stream:
- XMLInputFactory — factory per creare i parser.
- XMLStreamReader — il parser in streaming, che legge l’XML «a pezzi».
Esempio di codice di base:
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();
// gestione dell'evento
}
reader.close();
2. Principio di funzionamento di StAX: modello pull
In StAX gestisci tu la lettura dell’XML:
- Apri lo stream (per esempio, un file).
- Crei un XMLStreamReader.
- Nel ciclo chiami reader.next() per ottenere il prossimo evento.
- Controlli il tipo di evento (START_ELEMENT, END_ELEMENT, CHARACTERS, ecc.).
- Quando arrivi al punto desiderato, elabori i dati.
- Chiudi il parser.
Schema di funzionamento:
flowchart TD
A[Aprire XMLStreamReader] --> B{hasNext?}
B -- sì --> C["next()"]
C --> D{Tipo di evento?}
D -- START_ELEMENT --> E[Gestione dell'inizio dell'elemento]
D -- CHARACTERS --> F[Gestione del testo]
D -- END_ELEMENT --> G[Gestione della fine dell'elemento]
D -- END_DOCUMENT --> H[Termina]
B -- no --> H
Perché è comodo?
- Decidi tu quando leggere il prossimo elemento.
- Puoi «fermarti» nel punto desiderato ed elaborare solo una parte del file.
- Non serve scrivere una marea di gestori come in SAX.
3. Tipi di eventi in StAX
Quando chiami reader.next(), il parser restituisce un tipo di evento — un intero (una costante dell’interfaccia XMLStreamConstants). Ecco i principali tipi di eventi:
- START_ELEMENT — inizio di un elemento XML (<tag>).
- END_ELEMENT — fine di un elemento XML (</tag>).
- CHARACTERS — contenuto testuale tra i tag.
- END_DOCUMENT — fine del documento.
Esempio di gestione degli eventi:
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT:
String name = reader.getLocalName();
System.out.println("Inizio dell'elemento: " + name);
break;
case XMLStreamConstants.CHARACTERS:
String text = reader.getText().trim();
if (!text.isEmpty()) {
System.out.println("Testo: " + text);
}
break;
case XMLStreamConstants.END_ELEMENT:
System.out.println("Fine dell'elemento: " + reader.getLocalName());
break;
}
}
4. Dettagli utili
Quando usare StAX?
StAX è la scelta ideale se:
- Il file XML è molto grande (gigabyte) e non vuoi caricarlo interamente in memoria.
- Devi elaborare solo una parte del documento (ad esempio, trovare un elemento specifico e fermarti).
- Serve codice semplice e chiaro: StAX è più semplice di SAX e non richiede di scrivere tanti gestori.
Esempi di casi d’uso:
- Import di un grande file XML di dati (ad esempio, esportazione da 1C, estratti bancari, cataloghi di prodotti).
- Ricerca ed elaborazione solo degli elementi necessari (ad esempio, solo <transaction> da un milione di record).
- Trasformazione dell’XML «al volo» (ad esempio, filtraggio, aggregazione).
Confronto tra DOM, SAX e StAX
| Approccio | Memoria | Semplicità | Flessibilità | Quando usarlo |
|---|---|---|---|---|
| DOM | Alta (tutto in memoria) | Molto semplice | Possibile modificare l’albero | File piccoli/medi, quando serve modificare l’XML |
| SAX | Minima | Difficile (gestori di eventi) | Sola lettura, non si può tornare indietro | File molto grandi, elaborazione semplice |
| StAX | Minima | Media (modello pull) | Si può leggere a parti, comodo fermarsi | File grandi, quando servono flessibilità e semplicità |
StAX — il giusto compromesso:
— Non consuma memoria come DOM.
— Non richiede gestori complessi come SAX.
— Consente di controllare il processo di parsing.
5. Esempio: lettura di un grande file XML con StAX
Supponiamo di avere un file "books.xml":
<library>
<book>
<title>Java per principianti</title>
<author>Ivan Ivanov</author>
</book>
<book>
<title>Java avanzato</title>
<author>Pyotr Petrov</author>
</book>
<!-- ... molti libri ... -->
</library>
Obiettivo: stampare tutti i titoli dei libri.
Codice con 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(); // passiamo a CHARACTERS
System.out.println("Libro: " + reader.getText());
}
}
reader.close();
}
}
Vantaggi:
- Non carichiamo l’intero file in memoria.
- Si possono elaborare anche un milione di libri — il programma non «cadrà».
6. Errori tipici con StAX
Errore n. 1: hai dimenticato di chiudere il parser o lo stream. Chiudi sempre XMLStreamReader e lo stream (InputStream) per evitare leak di risorse.
Errore n. 2: non controlli il tipo di evento. Non tutti gli eventi sono l’inizio o la fine di un elemento. Controlla il tipo di evento, altrimenti potresti ottenere stringhe vuote o perdere dati necessari.
Errore n. 3: non tieni conto della nidificazione degli elementi. Se la struttura XML è complessa (ad esempio, libri dentro sezioni), tieni traccia del livello corrente di nidificazione per non confondere gli elementi.
Errore n. 4: usi DOM per file grandi. Se il file è grande, non usare DOM, altrimenti potresti ottenere OutOfMemoryError. Per i file grandi, usa StAX o SAX.
Errore n. 5: non gestisci le eccezioni. Il lavoro con file e XML può lanciare eccezioni (XMLStreamException, IOException). Gestiscile o propagale più in alto.
GO TO FULL VERSION