CodeGym /Corsi /JAVA 25 SELF /StAX (Streaming API for XML) — parsing in streaming

StAX (Streaming API for XML) — parsing in streaming

JAVA 25 SELF
Livello 47 , Lezione 2
Disponibile

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:

  1. Apri lo stream (per esempio, un file).
  2. Crei un XMLStreamReader.
  3. Nel ciclo chiami reader.next() per ottenere il prossimo evento.
  4. Controlli il tipo di evento (START_ELEMENT, END_ELEMENT, CHARACTERS, ecc.).
  5. Quando arrivi al punto desiderato, elabori i dati.
  6. 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.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION