Parsear XML con SAX de java

Este capitulo merece leerselo poco a poco. Java nos ofrece dos modelos de parseador XML: Uno es Serial Access Xml y el otro es Document Object Model. El mejor y más sencillo de usar es el DOM. Por contrapartida es el mas lento y pesado. Por lo que yo, amante de las cafeteras y máquinas viejas me decanto en primera instancia por el SAX dado que es más ligero rápido para mi viejo Intel PentiumII.

SAX tien 2 inconvenientes.

  1. Es más dificil de manipular
  2. Realiza una lectura secuencial del documento por lo que una vez leido no se puede volver atras. Cosa que DOM si que permite.

Una vez explicados los inconvenientes y ventajas (es mas ligero) de SAX voy a contarte como funciona un poco por encina. Si quieres una explicación mas detallada vete a la página de Sun

El caso es que SAX es una modelo de manipulación XML. Lo mas inportante en todo esto es el DocumentHandler, el manipulador del documento que es donde le vas a indicar lo que tiene que hacer el parseador.

La cosa va tal que así: Tu declaras una factoría parseadora. Y de esa factoria parseadora le dices que cree un parseador. Y a se parseador le pasas tu DocumentHandler que es donde le dices lo que tiene que hacer en cada momento.

El DocumentHandler es una interfaz que responde a eventos. Por lo que se llamarán los métodos especificados cuando suceda algo en concreto. Los métodos principales son:

  • startDocument Que se invoca cuando se detecta que el documento empieza. Esto quiere decir que si quieres que haga algo al principio del documento tienes que indicarselo aqui.
  • endDocuement Que se invoca cuando detecta que el documento ha acabado. Por lo tanto, lo que tenga que ocurrir cuando acabe de leer el documento se lo tienes que decir aqui.
  • startElement Que se invoca cuando encuentra un nuevo elemento, nodo, etiqueta, tag, como lo quieras llamar ( <cosa> ). Aqui le tienes que decir lo que quieras que pase cuando detecta un nuevo elemento. Es aqui donde se recoge la información de los atributos tambien (<cosa atributo ='contenido del atributo'> contenido del elemento</cosa> )
  • endElement Que se invoca una vez ha leido el elemento. Aqui tenemos la información del nodo y del contenido del nodo (<nodo>contenido del nodo </nodo>) por lo que es aqui donde normalmente se recoge la información.

Uno de los diseños más sencillos es el de implementar una clase interna que sea tu DocumentHandler. En ese caso simplemente extiendes la clase de DefaultHandler y implementas los métodos deseados. Como puedes ver en este sencilliiiiisimo ejemplo:

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

public class LectorSAX  {
    public void lee(String url){
       try{
            SAXParserFactory spf=SAXParserFactory.newInstance();
            SAXParser sp = spf.newSAXParser();
           	sp.parse(url, new LibraryXMLReader() );
        }catch(ParserConfigurationException e){
        	System.err.println("error de  parseo");
        }catch(SAXException e2){
        	System.err.println("error de  sax : " + e2.getStackTrace());
        } catch (IOException e3) {
			// TODO Auto-generated catch block
        	System.err.println("error de  io : " + e3.getMessage() );
        }

    }

	public static void main(String[] args){
	LectorSAX lector = new LectorSAX();
	lector.	lee("http://badopi.net/atom.xml");
}
//--------------------------------------------------------------------------------- 
    private class LibraryXMLReader extends DefaultHandler {
  	
    	 String contenido="";  // cadena para almacenar el contenido de un tag

	public void startDocument() throws SAXException{
	 	System.out.println("Estoy al principio del documento");	
      
  	}
	public void endDocument()throws SAXException{
    	 	System.out.println("Estoy al final del documento");	
  	}

     	/* Esta funcion el llamada cuando se produce el evento 
    	 * de(non-Javadoc)
    	 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
    	 */
    	public void startElement(String uri, String localName, String qName, Attributes attributes) {
		System.out.println("he encontrado una nueva etiqueta :" + qName);	
        }

    	/* Esta funcion es llamada cuando ve el contenido de un tag
    	 * (non-Javadoc)
    	 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
    	 */
        public void characters(char buf[], int offset, int len)
        throws SAXException
        {
        	contenido = new String(buf, offset, len); 
        }
        /* y esta al llegar al final
         * (non-Javadoc)
         * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
         */
        public void endElement(String uri, String localName, String qName) {
		System.out.println("he leido la  etiqueta : " + qName + " y su contenido es : " + contenido);	
         }
    }
    
}

Una buena idea para parsear un XML a traves de SAX y poder manipularlo luego tranquilamente es crearte un objeto que te almacene los datos. de ese modo tu puedes manipular el contenido del XML después a tu gusto. Espero que este ejemplo te sirva de ayuda:

Clase almacenadora de datos ( las malas lenguas dicen que a esto se le llama BEAN)

public class OrigenXML {
private String titulo, descripcion, enlace, fecha;
	public void setTitulo(String titulo) {
		this.titulo = titulo;
	}
	public String getTitulo() {
		return titulo;
	}
	
	public void setFecha(String titulo) {
		this.fecha = titulo;
	}
	public String getFecha() {
		return fecha;
	}
	
	public void setDescripcion(String descripcion) {
		this.descripcion = descripcion;
	}
	public String getDescripcion() {
		return descripcion;
	}
	
	public void setEnlace(String enlace) {
		this.enlace = enlace;
	}
	public String getEnlace() {
		return enlace;
	}

}

Una vez que tienes esta clase puedes modificar el ejemplo anterior para que te meta el contenido del XML en ella:

import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;



public class LectorSAX  {
	ArrayList nodos;

	public ArrayList getNodos(){
		return this.nodos;
	}

    public LectorSAX(String url){
        nodos = new ArrayList();
        try{
            SAXParserFactory spf=SAXParserFactory.newInstance();  // creo la factoría sax
            SAXParser sp = spf.newSAXParser();                    // creo el parseador
           	sp.parse(url, new LibraryXMLReader() );	            // al parseador le digo que parsee la url que quiero con el 
        }catch(ParserConfigurationException e){                   // manipulador de documento (documentHandler) que quiero
        	System.err.println("error de  parseo");             // (la url es una url o una path de tu ordenador se lo 
        }catch(SAXException e2){                                  // traga igual )
        	System.err.println("error de  sax : " + e2.getStackTrace());
        } catch (IOException e3) {
			// TODO Auto-generated catch block
        	System.err.println("error de  io : " + e3.getMessage() );
        }

    }
 
    private class LibraryXMLReader extends DefaultHandler {
    	 String contenido="";
    	private OrigenXML nodoActual= new OrigenXML();

    	/* 
    	 * Esta funcion el llamada cuando se produce el evento  de ver una nueva etiqueta
    	 */
    	public void startElement(String uri, String localName, String qName, Attributes attributes) {
            if ("item".equals(qName)) {
            	nodoActual = new OrigenXML();
            }
          
        	
        }
    	/* 
    	 * Esta funcion es llamada cuando ve el contenido de una etiqueta      
    	 */
        public void characters(char buf[], int offset, int len)
        throws SAXException
        {
        	contenido = new String(buf, offset, len);
           
        }
        /* 
         * y esta al llegar al final
         */
        public void endElement(String uri, String localName, String qName) {
        	 if("title".equals(qName)){	
     	    	nodoActual.setTitulo(contenido);
     	    	
     	      } 
        	 if("link".equals(qName)) {
     	    	  nodoActual.setEnlace(contenido);
     	    	  
     	      } 
        	 if("description".equals(qName)) {
     	    	  nodoActual.setDescripcion(contenido);
     	    	  
     	      } 
        	 if("pubDate".equals(qName)) {
     	    	 nodoActual.setFecha(contenido);
     	    	 
     	      } 
        	 if("item".equals(qName)) {
     	    	 nodos.add(nodoActual);    	    
     	      }
     	  
        }
    }
    
}

De este modo ya tengo el contenido de mi lector de XML en el ArrayList de nodos que devolveré cuando me lo pidan. Y ese ArrayList son los objetos OrigenXML que contienen la información que a mi me interesa.

 
java/61.txt · Última modificación: 2008/05/13 10:00 (editor externo)
 
Excepto donde se indique lo contrario, el contenido de esta wiki se autoriza bajo la siguiente licencia:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki