W3docs

Introduzione a XML in Java

Panoramica sull'elaborazione XML in Java: approcci DOM, SAX, StAX e JAXB con esempi pratici.

XML (Extensible Markup Language) è un formato testuale per rappresentare dati strutturati e gerarchici tramite tag annidati. Molto prima che JSON dominasse le API web, XML era lo standard predefinito per i file di configurazione, i formati di documento e lo scambio di messaggi — ed è ancora ovunque, dai file Maven pom.xml ai servizi SOAP fino ai documenti Office.

Java offre un supporto XML ricco e integrato nel JDK: non è necessaria alcuna libreria esterna per leggere o scrivere XML. I package javax.xml.parsers e org.w3c.dom, insieme a org.xml.sax e javax.xml.stream, forniscono tre distinti modelli di parsing. Questo capitolo illustra cosa è XML, quale modello di parsing scegliere e come XML si confronta con JSON — in modo che il resto di questa sezione (DOM, SAX e JAXB) si basi su fondamenta solide.

Questa pagina tratta:

  • Come appare un documento XML e i termini che è necessario conoscere (elemento, attributo, radice, ben formato).
  • I tre modelli di parsing del JDK — DOM, SAX e StAX — e quando ciascuno è adatto.
  • Un esempio DOM eseguibile che utilizza solo classi JDK.
  • Le differenze tra XML e JSON, per scegliere tra i due.

Come appare XML

Un documento XML è un albero di elementi. Ogni elemento ha un nome, attributi opzionali e contenuto testuale o elementi figli annidati. Esiste sempre esattamente un elemento radice che racchiude tutto.

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
  <book id="1" lang="en">
    <title>Effective Java</title>
    <price>45.00</price>
  </book>
</catalog>

Qui <catalog> è la radice, <book> è un elemento figlio con due attributi (id e lang), mentre <title> e <price> contengono testo. La dichiarazione XML nella prima riga indica la versione e la codifica dei caratteri. XML ben formato richiede che ogni tag di apertura sia chiuso e correttamente annidato.

I tre modelli di parsing

Il JDK offre tre modi per leggere XML, ciascuno con un diverso compromesso tra comodità e memoria. Scegliere quello giusto è la decisione XML più importante che si possa prendere.

ModelloStileMemoriaAdatto per
DOMCarica l'intero albero in memoriaAltaAccesso casuale, modifica, documenti piccoli/medi
SAXInvia eventi durante la scansione (callback)BassaDocumenti grandi, streaming in sola lettura
StAXEstrae eventi su richiesta (cursore)BassaDocumenti grandi, con flusso di controllo più semplice

DOM costruisce un albero completo in memoria che si può navigare liberamente e modificare. SAX attiva callback (startElement, characters, endElement) durante la lettura, senza mai tenere l'intero documento in memoria. StAX è anch'esso in streaming, ma consente al proprio codice di estrarre il prossimo evento quando è pronto, il che di solito è più facile da seguire rispetto alle callback di SAX.

DOM: l'albero in memoria

DOM è il modello più comodo quando i documenti sono abbastanza piccoli da stare in memoria. Si effettua il parsing una volta, poi si naviga o si interroga l'albero quante volte si vuole.

import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document doc = factory.newDocumentBuilder().parse("catalog.xml");

NodeList books = doc.getElementsByTagName("book");
System.out.println("Books: " + books.getLength());

getElementsByTagName restituisce una NodeList live; si accede agli elementi tramite indice e si fa il cast dei nodi a Element per leggere attributi e testo dei figli. Il capitolo dedicato al parser XML DOM in Java illustra in dettaglio come navigare, modificare e scrivere l'albero.

Attenzione

By default the JDK parser resolves external entities, which exposes you to XXE (XML External Entity) attacks when parsing untrusted input. For production code that reads XML from outside your control, disable DTDs with factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); before creating the builder.

SAX e StAX: lo streaming

Quando un documento è troppo grande per stare in memoria, si usa lo streaming. SAX invia eventi a un handler fornito dall'utente:

import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;

DefaultHandler handler = new DefaultHandler() {
    public void startElement(String uri, String local, String name, Attributes a) {
        System.out.println("Start: " + name);
    }
};
SAXParserFactory.newInstance().newSAXParser()
    .parse("catalog.xml", handler);

StAX fornisce un cursore che si avanza manualmente, il che molti trovano più chiaro:

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamConstants;
import java.io.FileReader;

XMLStreamReader r = XMLInputFactory.newInstance()
    .createXMLStreamReader(new FileReader("catalog.xml"));
while (r.hasNext()) {
    if (r.next() == XMLStreamConstants.START_ELEMENT) {
        System.out.println("Start: " + r.getLocalName());
    }
}

Vedere il capitolo sul parser XML SAX in Java per una guida completa agli event handler. Se si preferisce evitare il parsing manuale dei nodi e mappare XML direttamente su oggetti Java, JAXB associa gli elementi a classi annotate.

Un esempio autonomo

L'esempio eseguibile qui sotto usa solo classi JDK — nessun Jackson o JAXB necessario. Effettua il parsing di un catalogo XML da una stringa in memoria con DOM, scorre gli elementi <book>, legge attributi e testo dei figli, e somma i prezzi.

java— editable, runs on the server

Cosa ricavare dall'esecuzione:

  • Il parsing DOM non richiede dipendenze esterne — DocumentBuilderFactory e org.w3c.dom sono inclusi nel JDK, motivo per cui il programma stampa i risultati senza nulla nel classpath.
  • Il nome dell'elemento radice stampato come catalog conferma che esiste esattamente una radice che racchiude l'intero documento.
  • getElementsByTagName("book") ha restituito una NodeList di lunghezza 2, quindi è possibile indicizzarla come una lista e fare il cast di ogni elemento a Element.
  • Gli attributi (id) si leggono con getAttribute, mentre il contenuto testuale (title, price) si legge con getTextContent — sono tipi di dati diversi sullo stesso elemento.
  • Poiché l'intero albero è in memoria, sommare i prezzi di tutti i libri per ottenere $83.50 è solo un ciclo con accesso casuale — la comodità che rende DOM vantaggioso nonostante il costo in memoria.

XML o JSON?

XML e JSON risolvono lo stesso problema — scambiare dati strutturati — ma con compromessi diversi.

AspettoXMLJSON
SintassiTag verbosi, apertura e chiusuraParentesi graffe e quadre compatte
AttributiSì (id="1")No — tutto è una coppia chiave/valore
CommentiSupportati (<!-- ... -->)Non supportati
Schema/validazioneMaturo (XSD, DTD)JSON Schema, meno diffuso
Supporto JDKIntegrato (javax.xml.*)Nessuno integrato — richiede una libreria
Uso tipico oggiConfigurazione, documenti, SOAP, sistemi legacyAPI web/REST, servizi moderni

Scegliere XML quando è necessario consumare un formato XML esistente (un servizio SOAP, un pom.xml, un documento Office) o quando si necessita di attributi, commenti o validazione rigorosa tramite schema. Scegliere JSON per le nuove API web, dove le dimensioni ridotte e il supporto nativo del browser sono vincenti.

Passi successivi

Esercitazione

Pratica
Quale modello di parsing XML carica l'intero documento in memoria come un albero navigabile?
Quale modello di parsing XML carica l'intero documento in memoria come un albero navigabile?
Was this page helpful?