1. Introducción al análisis en streaming
En Java, históricamente se han consolidado dos enfoques para trabajar con XML.
Ya sabemos que DOM (Document Object Model) construye el árbol del documento en memoria. Es cómodo desplazarse por los elementos y editarlos, pero para archivos grandes es demasiado costoso: la memoria se agota rápidamente.
Por su parte, SAX (Simple API for XML) procesa el archivo de forma secuencial y dispara eventos al encontrar etiquetas. Es ahorrador en memoria y permite trabajar con documentos enormes. Pero escribir manejadores es incómodo y no es posible retroceder en la estructura.
StAX (Streaming API for XML) nació como un compromiso. También es de flujo, como SAX, pero da más control al programador: nosotros mismos «tiramos» de los eventos del flujo cuando lo necesitamos. A este enfoque se le llama parsing pull, y permite escribir un código más claro y flexible.
Introducción a StAX
StAX (Streaming API for XML) es un parser XML moderno en flujo para Java, aparecido en JDK 6+.
La idea principal: parsing pull (analizador «que extrae»).
A diferencia de SAX, donde el parser invoca tus métodos (modelo push), en StAX tú controlas el proceso:
Tú mismo le pides al parser: «¡Dame el siguiente evento!»
Analogía:
SAX es como la televisión: los eventos «te llegan» sin parar y tienes que reaccionar.
StAX es como un servicio en el que tú mismo pulsas «siguiente vídeo» cuando estás listo.
Clases clave de StAX
Para trabajar con StAX, necesitas dos clases principales del paquete javax.xml.stream:
- XMLInputFactory — fábrica para crear parsers.
- XMLStreamReader — el parser en flujo que lee XML «a trozos».
Ejemplo de código básico:
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();
// procesamiento del evento
}
reader.close();
2. Cómo funciona StAX: modelo pull
En StAX controlas tú mismo la lectura de XML:
- Abres un flujo (por ejemplo, un archivo).
- Creas XMLStreamReader.
- En un bucle llamas a reader.next() para obtener el siguiente evento.
- Compruebas el tipo de evento (START_ELEMENT, END_ELEMENT, CHARACTERS, etc.).
- Cuando llegas al lugar necesario, procesas los datos.
- Cierras el parser.
Esquema de trabajo:
flowchart TD
A[Abrir XMLStreamReader] --> B{hasNext?}
B -- sí --> C["next()"]
C --> D{¿Tipo de evento?}
D -- START_ELEMENT --> E[Procesar inicio de elemento]
D -- CHARACTERS --> F[Procesar texto]
D -- END_ELEMENT --> G[Procesar fin de elemento]
D -- END_DOCUMENT --> H[Finalizar]
B -- no --> H
¿Qué ventajas tiene?
- Tú decides cuándo leer el siguiente elemento.
- Puedes «detenerte» en el lugar adecuado para procesar solo una parte del archivo.
- No necesitas escribir un montón de manejadores como en SAX.
3. Tipos de eventos en StAX
Cuando llamas a reader.next(), el parser devuelve un tipo de evento — un entero (constante de la interfaz XMLStreamConstants). Estos son los principales tipos de eventos:
- START_ELEMENT — inicio de un elemento XML (<tag>).
- END_ELEMENT — fin de un elemento XML (</tag>).
- CHARACTERS — contenido de texto entre etiquetas.
- END_DOCUMENT — fin del documento.
Ejemplo de manejo de eventos:
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT:
String name = reader.getLocalName();
System.out.println("Inicio del elemento: " + name);
break;
case XMLStreamConstants.CHARACTERS:
String text = reader.getText().trim();
if (!text.isEmpty()) {
System.out.println("Texto: " + text);
}
break;
case XMLStreamConstants.END_ELEMENT:
System.out.println("Fin del elemento: " + reader.getLocalName());
break;
}
}
4. Detalles útiles
¿Cuándo usar StAX?
StAX es la elección ideal si:
- El archivo XML es muy grande (gigabytes) y no quieres cargarlo completo en memoria.
- Necesitas procesar solo una parte del documento (por ejemplo, encontrar un elemento concreto y detenerte).
- Se requiere código simple y claro: StAX es más sencillo que SAX y no obliga a escribir un montón de manejadores.
Ejemplos de tareas:
- Importación de un archivo XML grande con datos (por ejemplo, exportación desde 1C, extractos bancarios, catálogos de productos).
- Búsqueda y procesamiento solo de los elementos necesarios (por ejemplo, únicamente <transaction> entre un millón de registros).
- Transformación de XML «al vuelo» (por ejemplo, filtrado, agregación).
Comparativa entre DOM, SAX y StAX
| Enfoque | Memoria | Simplicidad | Flexibilidad | Cuándo usar |
|---|---|---|---|---|
| DOM | Alta (todo en memoria) | Muy simple | Permite modificar el árbol | Archivos pequeños/medianos cuando es necesario editar el XML |
| SAX | Mínima | Difícil (manejadores de eventos) | Solo lectura, no se puede volver atrás | Archivos muy grandes, procesamiento simple |
| StAX | Mínima | Media (modelo pull) | Permite leer por partes, fácil de pausar | Archivos grandes cuando se necesita flexibilidad y sencillez |
StAX es el término medio:
— No consume memoria como DOM.
— No requiere manejadores complejos como SAX.
— Permite controlar el proceso de parsing.
5. Ejemplo: lectura de un archivo XML grande con StAX
Supongamos que tenemos un archivo "books.xml":
<library>
<book>
<title>Java para principiantes</title>
<author>Ivan Ivanov</author>
</book>
<book>
<title>Java avanzado</title>
<author>Pyotr Petrov</author>
</book>
<!-- ... muchos libros ... -->
</library>
Objetivo: mostrar todos los títulos de los libros.
Código 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(); // avanzamos a CHARACTERS
System.out.println("Libro: " + reader.getText());
}
}
reader.close();
}
}
Ventajas:
- No cargamos todo el archivo en memoria.
- Se puede procesar incluso un millón de libros: la aplicación no se «caerá».
6. Errores típicos al trabajar con StAX
Error n.º 1: olvidaste cerrar el parser o el flujo. Cierra siempre XMLStreamReader y el flujo (InputStream) para evitar fugas de recursos.
Error n.º 2: no compruebas el tipo de evento. No todos los eventos son inicio o fin de elemento. Comprueba el tipo de evento o podrías obtener cadenas vacías o saltarte datos necesarios.
Error n.º 3: no tienes en cuenta el anidamiento de elementos. Si la estructura XML es compleja (por ejemplo, libros dentro de secciones), lleva control del nivel de anidamiento actual para no confundir elementos.
Error n.º 4: usas DOM para archivos grandes. Si el archivo es grande, no uses DOM o tendrás un OutOfMemoryError. Para archivos grandes, usa StAX o SAX.
Error n.º 5: no gestionas las excepciones. Trabajar con archivos y XML puede lanzar excepciones (XMLStreamException, IOException). Manéjalas o propágalas hacia arriba.
GO TO FULL VERSION