martes, 29 de enero de 2013

Leer grandes ficheros XML


Ya hicimos un post acerca de leer ficheros XML. Esta vez nos vamos a centrar en leer ficheros XML que pueden llegar a ser demasiado grandes. Aunque ya indicamos que hacerlo con SAX era mejor que con DOM porque solo carga los elementos que lee en memoria, es posible que aun no sea suficiente. Para esta nueva forma usaremos XMLInputFactory.

El ejemplo es básicamente igual e incluso los métodos se parecen bastante por lo cual no será difícil de entender. El XML de ejemplo es:

 
  Las estrellas mi destino
  Alfred Bester
 
 
  El juego de Ender
  Orson Scott Card
 
 .....

Crearemos una clase que será la encargada de leer el ficheor XML y 'parsearlo'. Y que contiene los atributos necesarios para devolver una lista de libros en formato de objetos java.
public class BigXmlOwnHandler {
private Libro libro;
private List list;
public List getList(){
return list;
}
El 'parseo' lo realizaremos en un método propio que denominamos parser:
public void parser(final String absFilePath) throws FileNotFoundException, XMLStreamException {
 //Creamos el InputStream asociado al fichero pasado
 final FileInputStream in = new FileInputStream(absFilePath);
  //Creamos la factory que nos permite obtener el lector del XML
 final XMLInputFactory factory = XMLInputFactory.newInstance();
 final XMLStreamReader parser = factory.createXMLStreamReader(in);
 //Iteramos por los eventos (elementos) del XML
 for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
  switch (event) {
  //Al comenzar un elemento vamos al metodo que contiene la logica necesaria para obtener la informacion
  case XMLStreamConstants.START_ELEMENT:
   startElement(parser);
   break;
  //Al acabar un elemento vamos al metodo que contiene la logica necesaria para almacenar la informacion
  case XMLStreamConstants.END_ELEMENT:
   endElement(parser);
   break;
  }
 }
}
En este caso, no se trata de sobrescribir métodos sino de iterar por los eventos (elementos) de un fichero XML. Para generar nuestra lista de libros nosotros solo necesitaremos realizar cierta lógica en los eventos START_ELEMENT y END_ELEMENT. A cada evento le asociamos un método propio que permite obtener y almacenar la información Evento STAR_ELEMENT, con este evento podemos ver que elemento vamos a leer y cual es la información que contiene.
public void startElement(final XMLStreamReader parser) throws XMLStreamException {
 //vamos a leer el elemento 
 if ("libro".equals(parser.getLocalName())) {
  libro = new Libro();
  //Iteramos por sus atributos para obtener el valor de las paginas
  for (int i = 0; i < parser.getAttributeCount(); i++) {
   final String localName = parser.getAttributeLocalName(i);
   final String value = parser.getAttributeValue(i);
   if ("paginas".equals(localName)) {
    libro.setPaginas(Integer.valueOf(value));
   }
  }
 //vamos a leer el elemento  y obtenemos su contenido con getElementText()
 } else if ("autor".equals(parser.getLocalName())) {
  libro.setAutor(parser.getElementText());
 //vamos a leer el elemento  y obtenemos su contenido con getElementText()
 } else if ("nombre".equals(parser.getLocalName())) {
  libro.setNombre(parser.getElementText());
 }
}
Evento END_ELEMENT, con este evento podemos ver que elemento acabamos de terminar de leer y almacenar la información.
public void endElement(final XMLStreamReader parser) {
 if ('libro'.equals(parser.getLocalName())) {
  list.add(libro);
 }
}
Toda la lógica del método parser no es necesaria incluirla en una clase pero de esta forma encapsulamos la lógica que permite leer el fichero XML y lo tenemos todo un poco más ordenado. Con este método no necesitamos ninguna librería extra, y podemos usar esta solución a partir de la JDK 5

No hay comentarios:

Publicar un comentario