SAX no construye ningún árbol: te va avisando según lee. Gasta una memoria mínima y por eso es la opción cuando el archivo no cabe; a cambio, el estado lo llevas tú.
También te puede interesar
La idea
DOM carga el documento entero y luego lo recorres. SAX lo lee de principio a fin una sola vez y, por cada cosa que encuentra, llama a un método tuyo: startElement al abrir una etiqueta, characters con el texto, endElement al cerrarla. Nunca hay más de unos kilobytes en memoria, sea el archivo de 2 KB o de 2 GB.
catalogo.xml<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<catalogo>
<libro id="1">
<titulo>El Quijote</titulo>
<autor>Cervantes & Saavedra</autor>
</libro>
</catalogo>El manejador
import java.io.File;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
public class Sax {
public static void main(String[] args) throws Exception {
var fabrica = SAXParserFactory.newInstance();
fabrica.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
var manejador = new DefaultHandler() {
private final StringBuilder texto = new StringBuilder();
private boolean esHoja = false;
@Override
public void startElement(String uri, String local, String nombre, Attributes a) {
texto.setLength(0);
esHoja = true;
if (nombre.equals("libro")) {
System.out.println("libro id=" + a.getValue("id"));
}
}
@Override
public void characters(char[] c, int inicio, int largo) {
texto.append(c, inicio, largo);
}
@Override
public void endElement(String uri, String local, String nombre) {
if (esHoja) {
System.out.println(" " + nombre + " = " + texto.toString().strip());
}
texto.setLength(0);
esHoja = false;
}
};
fabrica.newSAXParser().parse(new File("catalogo.xml"), manejador);
}
}salidalibro id=1 titulo = El Quijote autor = Cervantes & Saavedra
Las dos trampas de SAX
characters puede llamarse varias veces para el mismo texto. El analizador entrega lo que tiene en el búfer, y un texto largo, o uno que contiene una entidad como &, llega partido en trozos. Por eso no se puede imprimir dentro de characters: hay que acumular en un StringBuilder y leerlo en endElement, que es cuando ya está completo.esHoja, al cerrar <libro> y <catalogo> el programa imprime otra vez el último texto acumulado, porque esos elementos cierran después y el búfer sigue lleno. La bandera se pone al abrir cualquier elemento y se quita al cerrar: si al llegar al cierre sigue puesta, es que nadie abrió nada por en medio y por tanto el elemento era una hoja. Esto, en la primera versión de esta página, estaba mal.SAX o DOM
| DOM | SAX | |
|---|---|---|
| Memoria | todo el documento | unos kilobytes |
| Recorrido | libre, en cualquier orden | una pasada, de principio a fin |
| Volver atrás | sí | no |
| Modificar | sí | no, es solo lectura |
| Código | corto | más largo, llevas tú el estado |
| Para | configuraciones, respuestas de API | exportaciones, archivos enormes |
Hay un tercero, StAX (XMLStreamReader), que es también de un solo paso pero al revés: en lugar de que el analizador te llame, eres tú quien pide el siguiente evento. Gasta lo mismo que SAX y el código sale más legible, así que para empezar hoy suele ser mejor opción.
FEATURE_SECURE_PROCESSING y los accesos externos en blanco, el analizador se niega.Más información en inglés: Read XML with SAX parser.
Todo el código se compiló y se ejecutó con Java 25 LTS en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.