Java – Leer XML con SAX Parser

En este ejemplo, mostraremos como leer un archivo XML con Java utilizando SAX, una de las opciones más eficientes para leer XMLs y que hacen menos uso de memoria.

Para este ejemplo usamos un XML con la estructura siguiente:

datos.xml

<?xml version="1.0"?>
<empresa>
    <empleado id="1">
        <nombre>José Ernesto</nombre>
        <username>jose</username>
        <password>321423</password>
    </empleado>
    <empleado id="2">
        <nombre>Daniel Pérez</nombre>
        <username>dperez</username>
        <password>433543</password>
    </empleado>
    <empleado id="3">
        <nombre>José López</nombre>
        <username>jlopez</username>
        <password>534534</password>
    </empleado>
</empresa>




Vamos al código:

package com.decodigo.ejemplos;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 *
 * @author decodigo
 */
public class LeerXMLConSAX {

    public static void main(String argv[]) {

        try {

            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser saxParser = factory.newSAXParser();

            DefaultHandler handler = new DefaultHandler() {

                boolean bNombre = false;
                boolean bUsername = false;
                boolean bPassword = false;

                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                    System.out.println("inicia elemento:" + qName);
                    if (qName.equalsIgnoreCase("empleado")) {
                        String id = attributes.getValue("id");
                        System.out.println("id: " + id);
                    }
                    if (qName.equalsIgnoreCase("nombre")) {
                        bNombre = true;
                    }
                    if (qName.equalsIgnoreCase("username")) {
                        bUsername = true;
                    }

                    if (qName.equalsIgnoreCase("password")) {
                        bUsername = true;
                    }
                }

                public void endElement(String uri, String localName, String qName) throws SAXException {
                    System.out.println("finaliza elemento:" + qName);
                }

                public void characters(char ch[], int start, int length) throws SAXException {

                    if (bNombre) {
                        System.out.println("nombre: " + new String(ch, start, length));
                        bNombre = false;
                    }

                    if (bUsername) {
                        System.out.println("username: " + new String(ch, start, length));
                        bUsername = false;
                    }

                    if (bPassword) {
                        System.out.println("password: " + new String(ch, start, length));
                        bPassword = false;
                    }
                }

            };

            File file = new File("/home/decodigo/Documentos/java/archivos/datos.xml");
            InputStream inputStream = new FileInputStream(file);
            Reader reader = new InputStreamReader(inputStream, "UTF-8");

            InputSource is = new InputSource(reader);
            is.setEncoding("UTF-8");
            saxParser.parse(is, handler);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Lo primero que debes notar es que estamos construyendo un manejador “handler“, que se encarga de leer y registrar partes específicas de nuestro XML. Es necesario aclarar que debemos conocer la estructura del archivo XML que estamos leyendo.

Mientras el archivo se lee, vamos descubriendo elementos de interés en nuestro XML que registramos con la ayuda de variables booleanas:

                boolean bNombre = false;
                boolean bUsername = false;
                boolean bPassword = false;

Con la ayuda del método startElement registramos cada encuentro y cambiamos el valor de nuestras variables booleanas.

                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                    System.out.println("inicia elemento:" + qName);
                    if (qName.equalsIgnoreCase("empleado")) {
                        String id = attributes.getValue("id");
                        System.out.println("id: " + id);
                    }
                    if (qName.equalsIgnoreCase("nombre")) {
                        bNombre = true;
                    }
                    if (qName.equalsIgnoreCase("username")) {
                        bUsername = true;
                    }

                    if (qName.equalsIgnoreCase("password")) {
                        bUsername = true;
                    }
                }

El método characters, nos permitirá obtener la infromación contenida en la etiqueta de XML encontrada.  Después de hacer “algo” con la información encontrada (en nuestro caso sólo la imprimos en consola), devolvemos al estado anterior al booleano que corresponde a la etiqueta del XML.

                public void characters(char ch[], int start, int length) throws SAXException {

                    if (bNombre) {
                        System.out.println("nombre: " + new String(ch, start, length));
                        bNombre = false;
                    }

                    if (bUsername) {
                        System.out.println("username: " + new String(ch, start, length));
                        bUsername = false;
                    }

                    if (bPassword) {
                        System.out.println("password: " + new String(ch, start, length));
                        bPassword = false;
                    }
                }

Si ejecutas el código podrás ver en consola que cada que se encuentra una etiqueta nombre, username o password se imprime su contenido:

Para la lectura de los atributos de una etiqueta, usamos la variable attributes que recibimos como argumento en el método startElement y simplemente tomamos el valor de los mismos con la función getValue.

                        String id = attributes.getValue("id");

Por último te mostramos como inicializar el analizador usando el método parse, que recibe los datos del archivo y el manejador que implementamos específicamente para la estuctura del XML de ejemplo.

            File file = new File("/home/decodigo/Documentos/java/archivos/datos.xml");
            InputStream inputStream = new FileInputStream(file);
            Reader reader = new InputStreamReader(inputStream, "UTF-8");

            InputSource is = new InputSource(reader);
            is.setEncoding("UTF-8");
            saxParser.parse(is, handler);

El método parse puede recibir directamente una variable file y al manejador, pero lo hacemos de este modo para poder especificar que el archivo que será leido contiene caracteres en UTF-8, que es el que permite varios de los caracteres especiales del español.

Esperamos que este ejemplo te sea de utilidad.