Leer un XML con SAX en Java

Hola a todos, hoy os voy a explicar como podemos leer un XML con SAX en Java.

SAX o Sample API for XML es un estándar de parseo de XML que  procesa el documento como DOM pero de una forma diferente.

SAX procesa la información en XML manipulando cada elemento, ideal para manipular archivos de gran tamaño. Es más rápido y sencillo que utilizar DOM.

Teniendo este XML de ejemplo:


<?xml version="1.0" encoding="UTF-8"?>
<libros>	
	<libro año="1994">
		<titulo>TCP/IP Illustrated</titulo>
		<autor>
			<apellido>Stevens</apellido>
			<nombre>W.</nombre>
		</autor>
		<editorial>Addison-Wesley</editorial>
		<precio> 65.95</precio>
	</libro>
	<libro año="1992">
		<titulo>Advan Programming for Unix environment</titulo>
		<autor>
			<apellido>Stevens</apellido>
			<nombre>W.</nombre>
		</autor>
		<editorial>Addison-Wesley</editorial>
		<precio>65.95</precio>
	</libro>
	<libro año="2000">
		<titulo>Data on the Web</titulo>
		<autor>
			<apellido>Abiteboul</apellido>
			<nombre>Serge</nombre>
		</autor>
		<autor>
			<apellido>Buneman</apellido>
			<nombre>Peter</nombre>
		</autor>
		<autor>
			<apellido>Suciu</apellido>
			<nombre>Dan</nombre>
		</autor>
		<editorial>Morgan Kaufmann editorials</editorial>
		<precio>39.95</precio>
	</libro>
</libros>

Para empezar con SAX, necesitamos crear una clase que herede de la clase DefaultHandler.


package sax;

import org.xml.sax.helpers.DefaultHandler;

public class LibroHandler extends DefaultHandler {


}

Necesitaremos un StringBuilder para ir almacenando el contenido de la etiqueta.


package sax;

import org.xml.sax.helpers.DefaultHandler;

public class LibroHandler extends DefaultHandler {

    private StringBuilder value;

    public LibroHandler() {
        this.value = new StringBuilder();
    }

}

Tenemos 3 métodos que vamos a sobrescribir: startElementcharactersendElement.

Con SAX, para cada etiqueta, pasará por estos 3 métodos.

Empecemos por startElement


package sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class LibroHandler extends DefaultHandler {

    private StringBuilder value;

    public LibroHandler() {
        this.value = new StringBuilder();
    }

    @Override
    public void startElement(String uri, String localName,
            String qName, Attributes attributes)
            throws SAXException {

        this.value.setLength(0);

    }

}

Ponemos el StringBuilder su longitud a 0, ya que su valor lo rellenaremos en el método characters  y lo mostraremos en el método endElement.

Para los atributos, lo podemos coger desde el parámetro attributes. El parámetro qName es el nombre de la etiqueta.

En nuestro caso, cuando la etiqueta es libro, cogeremos el valor del atributo año.


package sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class LibroHandler extends DefaultHandler {

    private StringBuilder value;

    public LibroHandler() {
        this.value = new StringBuilder();
    }

    @Override
    public void startElement(String uri, String localName,
            String qName, Attributes attributes)
            throws SAXException {

        this.value.setLength(0);

        if (qName.equals("libro")) {
            String anio = attributes.getValue("año");
            System.out.println("Atributo año: " + anio);
        }

    }

}

En el método characters, iremos añadiendo el contenido de la etiqueta a nuestro StringBuilder.


package sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class LibroHandler extends DefaultHandler {

    private StringBuilder value;

    public LibroHandler() {
        this.value = new StringBuilder();
    }

    @Override
    public void startElement(String uri, String localName,
            String qName, Attributes attributes)
            throws SAXException {

        this.value.setLength(0);

        if (qName.equals("libro")) {
            String anio = attributes.getValue("año");
            System.out.println("Atributo año: " + anio);
        }

    }

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

        this.value.append(ch, start, length);
    }

}

En el método endElement, salta cuando terminamos con esa etiqueta. Lo que haremos es mostrar el contenido de nuestro StringBuilder. Según el parámetro qName, mostraremos un mensaje u otro.


package sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class LibroHandler extends DefaultHandler {

    private StringBuilder value;

    public LibroHandler() {
        this.value = new StringBuilder();
    }

    @Override
    public void startElement(String uri, String localName,
            String qName, Attributes attributes)
            throws SAXException {

        this.value.setLength(0);

        if (qName.equals("libro")) {
            String anio = attributes.getValue("año");
            System.out.println("Atributo año: " + anio);
        }

    }

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

        this.value.append(ch, start, length);
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {

        switch (qName) {
            case "libro":
                System.out.println("");
                break;
            case "titulo":
                System.out.println("Titulo: " + this.value.toString());
                break;
            case "apellido":
                System.out.println("Apellido autor: " + this.value.toString());
                break;
            case "nombre":
                System.out.println("Nombre autor: " + this.value.toString());
                break;
            case "editorial":
                System.out.println("Editorial: " + this.value.toString());
                break;
            case "precio":
                System.out.println("Precio: " + this.value.toString());
                break;
        }

    }

}

Recodar que en el método startElement, reiniciamos nuestro StringBuilder.

Ahora, nos creamos una clase ejecutable con el siguiente contenido:


package sax;

import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;

public class Principal {

    public static void main(String[] args) {

        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();

            SAXParser parser = factory.newSAXParser();

            LibroHandler handler = new LibroHandler();
            parser.parse("libros.xml", handler);

        } catch (ParserConfigurationException | SAXException | IOException ex) {
            System.out.println(ex.getMessage());
        }

    }

}


Creamos una instancia de SAXParserFactory y de esta creamos un SAXParser, aparte de una instancia de LibroHandler.

Este es el resultado:

Os dejo un repositorio con el código.

https://github.com/DiscoDurodeRoer/ejemplo-sax-java

Espero que os sea de ayuda. Si tenéis dudas, preguntad. Estamos para ayudar.

Compartir

Deja una respuesta

Tu dirección de correo electrónico no será publicada.