Java – Leer archivo XML

Con DOM, el archivo entero se carga en memoria como un árbol y puedes ir a cualquier nodo cuando quieras. Es lo cómodo mientras el archivo quepa; cuando no quepa, hay que pasar a SAX.

El XML de ejemplo

catalogo.xml<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<catalogo>
  <libro id="1">
    <titulo>El Quijote</titulo>
    <autor>Cervantes &amp; Saavedra</autor>
  </libro>
</catalogo>

Leerlo

import java.io.File;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.*;

public class LeerXml {
    public static void main(String[] args) throws Exception {
        var fabrica = DocumentBuilderFactory.newInstance();
        fabrica.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        fabrica.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");

        Document doc = fabrica.newDocumentBuilder().parse(new File("catalogo.xml"));
        doc.getDocumentElement().normalize();

        System.out.println("raíz: " + doc.getDocumentElement().getNodeName());

        NodeList libros = doc.getElementsByTagName("libro");
        System.out.println("libros: " + libros.getLength());

        for (int i = 0; i < libros.getLength(); i++) {
            Element e = (Element) libros.item(i);
            System.out.println("  id     : " + e.getAttribute("id"));
            System.out.println("  titulo : " + texto(e, "titulo"));
            System.out.println("  autor  : " + texto(e, "autor"));
        }
    }

    static String texto(Element e, String etiqueta) {
        NodeList n = e.getElementsByTagName(etiqueta);
        return n.getLength() == 0 ? null : n.item(0).getTextContent();
    }
}
salidaraíz: catalogo
libros: 1
  id     : 1
  titulo : El Quijote
  autor  : Cervantes & Saavedra

El ampersand vuelve a aparecer sin escapar: el analizador deshace las entidades por ti. Y el método texto de abajo existe por una razón: getElementsByTagName puede devolver una lista vacía, y item(0) sobre ella da null y luego un NullPointerException en la línea siguiente. Es el fallo número uno al leer XML con DOM.

Las dos líneas de seguridad no son opcionales. Un XML puede declarar entidades externas y hacer que el analizador lea archivos del servidor o abra conexiones: es el ataque XXE. Si el XML viene de fuera —de un usuario, de una API, de un correo—, hay que desactivar eso antes de analizar. Con FEATURE_SECURE_PROCESSING y los accesos externos en blanco, el analizador se niega.

Dos detalles de DOM que pillan a todo el mundo

getElementsByTagName busca en todo el subárbol, no solo en los hijos directos. Si hay un <titulo> anidado más abajo, también sale. Cuando eso importa, hay que recorrer getChildNodes() y filtrar.

Los espacios en blanco también son nodos. Un getChildNodes() sobre un XML sangrado devuelve nodos de texto con saltos de línea entre cada elemento. Por eso casi todo el mundo usa getElementsByTagName, y por eso se llama a normalize(), que junta los nodos de texto partidos.

Cuando la ruta es complicada, XPath

var xpath = javax.xml.xpath.XPathFactory.newInstance().newXPath();
String titulo = xpath.evaluate("/catalogo/libro[@id='1']/titulo", doc);

Para sacar un dato concreto de un documento grande, una expresión XPath se lee mejor que cuatro bucles anidados. Viene en el JDK, sin dependencias.

Si…Usa
El archivo cabe en memoriaDOM, como en esta página
El archivo es enormeSAX
Buscas un dato concretoXPath
El XML viene de fueraDOM o SAX, pero con la configuración segura
Quieres objetos Java directamenteJAXB o Jackson XML, ya con dependencias

Más información en inglés: Read XML files in Java.

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.

2 comentarios en «Java – Leer archivo XML»

  1. Hola me sirvio bastante tu codigo, pero me he quedado con esta duda como consultar nodos de nodos o no se como ser mas explicito, me gustaria recorrer todo este en un while.

    Responder
    • No necesitas de un while, porque cada elemento o lista de elementos se obtiene de forma explícita. En caso de tener más de un nodo del mismo tipo usas getElementsByTagName. Si desconoces el formato que tiene el XML quizá necesitas de un enfoque diferente para navegar tu XML, usar SAX por ejemplo, pero su implementación es más compleja. Saludos.

      Responder

Deja un comentario