sábado, 12 de julio de 2008

Java y XML: SAX (II)

Puesto que parece que eso de controlar el estado del procesado del xml que se comentaba en el post anterior no ha quedado muy claro, en este post pongo un ejemplo más real de procesado de XML.

En este ejemplo se trata de procesar el XML que define un libro:

<?xml version="1.0" encoding="UTF-8"?>
<libro isbn="978-84-8346-520-2">
   <titulo>El Ocho</titulo>
   <autor>Katherine Neville</autor>
   <anyo>1988</anyo>
   <editorial>Ballantine Books</editorial>
</libro>

Usaremos un manejador de eventos específico para este XML. Esta clase recibirá en el constructor un objeto de la clase Libro, en el cual se almacenará la información leida del XML.

Guardaremos en una variable lo último que se haya leído en el método characters y en el evento de fin de etiqueta, endElement, guardaremos este valor en la propiedad correspondiente del objeto libro.

Puesto que el ISBN nos viene en un atributo tendremos que procesarlo en el evento startElement de la etiqueta libro.


ManejadorLibro.java


package es.latascadexela.xml.sax;

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

/**
* Clase que procesa los eventos SAX al leer el xml de un libro.
* Guardará todos los datos obtenidos del xml en el objeto libro,
* el cual se pasa en el constructor.
*
* @author Xela
*
*/
public class ManejadorLibro extends DefaultHandler{

   private String valor = null;
   
   private Libro libro;
   
   public ManejadorLibro(Libro libro){
      this.libro=libro;
   }
   
   @Override
   public void startElement(String uri, String localName, String name,
         Attributes attributes) throws SAXException {
      
      // Limpiamos la variable temporal.
      valor=null;
      
      // Si la etiqueta es libro leemos el atributo isbn
      if(localName.equals("libro")){
         String isbn = attributes.getValue("isbn");
         // Lo guardamos en el objeto libro
         libro.setIsbn(isbn);
      }
   }
   
   @Override
   public void characters(char[] ch, int start, int length)
         throws SAXException {
      // Guardamos el texto en la variable temporal
      valor = new String(ch,start,length);
   }

   @Override
   public void endElement(String uri, String localName, String name)
         throws SAXException {
      // Según la etiqueta guardamos el valor leido
      // en una propiedad del objeto libro
      if (localName.equals("titulo")){
         libro.setTitulo(valor);
      }else if (localName.equals("autor")){
         libro.setAutor(valor);
      }else if (localName.equals("anyo")){
         libro.setAnyo(valor);
      }else if (localName.equals("editorial")){
         libro.setEditorial(valor);
      }
      
   }

}

Una vez tenemos construido el manejador, tendremos que crear la clase que procesa el XML utilizando nuestro manejador.


ProcesaLibro.java


package es.latascadexela.xml.sax;

import java.io.FileInputStream;
import java.io.IOException;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

/**
* Clase que procesa un XML de un libro mediante el handler SAX ManejadorLibro
*
* @author Xela
*
*/
public class ProcesaLibro {

   public static void main(String[] args) {
      
      try {
         // Creamos nuestro objeto libro vacío
         Libro libro = new Libro();
         // Creamos la factoria de parseadores por defecto
         XMLReader reader = XMLReaderFactory.createXMLReader();
         // Añadimos nuestro manejador al reader pasandole el objeto libro
         reader.setContentHandler(new ManejadorLibro(libro));         
         // Procesamos el xml de ejemplo
         reader.parse(new InputSource(new FileInputStream("/ruta_hasta_fichero/libro.xml")));
         // Ya tenemos nuestro objeto libro con los valores obtenidos del xml
         // Lo imprimimos
         System.out.println(libro.toString());         
      } catch (SAXException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }

   }

}

Por último, la clase entidad que almacena los datos de un libro.

Libro.java


package es.latascadexela.xml.sax;

/**
* Clase que almacena los datos de un libro
*
* @author Xela
*
*/
public class Libro {
   
   private String isbn = null;
   private String titulo = null;
   private String autor = null;
   private String anyo = null;
   private String editorial = null;
   
   // Constructor por defecto
   public Libro() {
      
   }
   
   public String getIsbn() {
      return isbn;
   }
   
   public void setIsbn(String isbn) {
      this.isbn = isbn;
   }
   
   public String getTitulo() {
      return titulo;
   }
   
   public void setTitulo(String titulo) {
      this.titulo = titulo;
   }
   
   public String getAutor() {
      return autor;
   }
   
   public void setAutor(String autor) {
      this.autor = autor;
   }
   
   public String getAnyo() {
      return anyo;
   }
   
   public void setAnyo(String anyo) {
      this.anyo = anyo;
   }
   
   public String getEditorial() {
      return editorial;
   }
   
   public void setEditorial(String editorial) {
      this.editorial = editorial;
   }

   @Override
   public String toString() {
      StringBuilder sb = new StringBuilder();
      sb.append("\nISBN: "+isbn);
      sb.append("\nTítulo: "+titulo);
      sb.append("\nAutor: "+autor);
      sb.append("\nAño: "+anyo);
      sb.append("\nEditorial: "+editorial);
      
      return sb.toString();
   }
   
   

}

Al ejecutar el main tenemos que el objeto libro tiene toda la información obtenida del XML. Puesto que lo hemos imprimido por la salida estándar obtendríamos lo siguiente:

ISBN: 978-84-8346-520-2
Título: El Ocho
Autor: Katherine Neville
Año: 1988
Editorial: Ballantine Books

Espero que os haya aclarado algo.


10 comentarios:

Anónimo dijo...

No falta la clase del objeto libro ?

Xela dijo...

Pues tienes toda la razón. Se me olvidó ponerla. Ahí la tienes.

Muchas gracias por la apreciación.

Gon dijo...

Despues de mirarme muchos tutoriales sobre SAX para hacer 4 chorradas para una practica de la universidad, encontre que este era el mas conciso y el mas claro para los que necesitamos parsear un simple XML.

Enhorabuena por el tutorial.

Xela dijo...

Muchas gracias, Gon.

Se agradecen comentarios como este. ;-)

Pai dijo...

Excelente articulo!, despues de horas de busqueda, este fue el unico que aclaró mis dudas.

Deil dijo...

Muy bien explicado a mis alumnos en la universidad siempre les indico tu blog.

Felicitactiones.

Jacinto dijo...

Hola Xela,

creo que existe un error en la clase Libro, concretamente en el método toString, ya que a la hora de llamar al método append del StringBuilder, pones \\n y eso Java lo toma como el caracter de escape \ y el salto de línea se lo come, por lo tanto, cuando se imprime por la salida estándar pone: \nISBN: .... \nTítulo: ... etc.

Un Saludo.

Xela dijo...

Muchas gracias, Jacinto. Corregido queda.

Saludos.

wcordero8 dijo...

buen dia, me llamo william y tengo una duda:

como hago para leer varios libros, porque ahi esta claro para uno solo, pero cuando se tienen bastantes
¿como se hace?
¿en donde se modifica?

grax por la info y muy buen post

Iran Vasquez dijo...

Hey!! felicitaciones.. después de dar muchas vueltas al fin encuentro un tuto decente que explique lo que se necesita saber.

Regards.