El tutor de nuestro curso online de Desarrollo de Aplicaciones para Android, Víctor Ramírez Las,…

Tratamiento de XML en Android: SAX
Para realizar el tratamiento de información XML en Android tenemos básicamente dos modelos de programación: streaming y DOM.
El modelo de streaming lee y procesa la información de forma secuencial, mientras que el DOM, carga toda la información previamente en memoria, y una vez allí, puede manipularla a través del mapa de nodos que crea del documento.
El modelo secuencial es más rápido y requiere menos recursos de memoria y procesador. El modelo DOM nos da más flexibilidad y capacidad de manipulación de la información, al tenerla toda disponible de forma estructurada.
En esta publicación vamos a describir el analizador (parseador) SAX, basado en ese modelo secuencial, incluyendo un pequeño ejemplo, y en los siguientes tutoriales veremos el modelo DOM, desarrollando un proyecto ejemplo con él.
SAX (Simple API for XML)
SAX es un parseador secuencial basado en eventos. Nos permite recorrer el archivo XML en pequeños fragmentos, a la vez que puede generar eventos al leer determinados elementos del documento como pueden ser las etiquetas de apertura o cierre o el contenido de texto.
SAX es un parseador de tipo ‘push‘, por lo que nos envía (push) los datos XML a nuestra aplicación cliente conforme los lee. Es decir, una vez empieza a leer el fichero XML, lo hace de forma completa, generando todos los eventos, sin que tengamos control sobre ello. Fun
Por el contrario, en los parseadores de tipo ‘pull‘, somos nosotros desde la aplicación cliente los que solicitamos explícitamente los datos XML (pull) cada vez que los necesitamos. Un ejemplo de este modelo es el método XmlPull, que mencionaremos brevemente al final de este tutorial ya que lo empleamos en una parte del proyecto que desarrollaremos en publicaciones posteriores.
Centrándonos pues en SAX, nos detendremos en las interfaces que expone el paquete org.xml.sax
(documentación oficial de SAX) que nos proporcionan un fácil acceso a la lectura de un documento XML:
org.xml.sax.Attributes
Interfaz que se encargará de listar los atributos definidos dentro del XML.
Métodos públicos
Método | Descripción |
getIndex(String uri, String localName) | Busca el índice por el nombre del espacio de nombres. |
getLength() | Devuelve el número de atributos en la lista. |
getLocalName(int index) | Busca el nombre de un atributo local por el índice. |
getQName(int index) | Busca el nombre de un atributo XML cualificado por el índice. |
getValue(String qName) | Busca el valor de un atributo XML cualificado. |
getType(String qName) | Busca el tipo de un atributo XML cualificado por el nombre. |
getURI(int index) | Busca la URI del espacio de nombres del atributo por el índice. |
org.xml.sax.XMLReader
Interfaz que proporciona las herramientas necesarias para realizar la lectura de un documento XML haciendo uso de retrollamadas.
Métodos públicos
Método | Descripción |
getContentHandler() | Devuelve el controlador actual de contenido. |
getDTDHandler() | Devuelve el controlador actual del DTD. |
getEntityResolver() | Devuelve la resolución de la entidad actual. |
getFeature(String name) | Look up the value of a feature flag. |
parse(InputSource input) | Parsea un documento XML. |
setContentHandler(ContentHandler handler) | Permite a una aplicación registrar el evento manejador de contenido. |
setFeature(String name, boolean value) | Establece el valor de la bandera del elemento. |
setProperty(String name, Object value) | Establece el valor de la propiedad. |
org.xml.sax.ContentHandler
Interfaz que permite recibir notificaciones del contenido de un documento.
Métodos públicos
Método | Descripción |
endDocument() | Recibe las notificaciones del final de un documento. |
endElement(String uri, String localName, String qName) | Recibe las notificaciones del final de un elemento. |
startDocument() | Recibe las notificaciones del comienzo de un documento. |
startElement(String uri, String localName, String qName, Attributes atts) | Recibe las notificaciones del comienzo de un elemento. |
skippedEntity(String name) | Recibe notificaciones de una entidad omitida. |
setDocumentLocator(Locator locator) | Recibe un objeto para localizar el origen de eventos del documento SAX. |
Ejemplo con SAX
Vamos a ver un pequeño ejemplo que nos permita comprender desde un punto de vista más funcional el uso de este método para la lectura de un documento XML. Para ello nos basaremos en este sencillo archivo XML:
1 2 3 4 5 6 7 |
<?xml version='1.0' encoding='utf-8' ?> <Clientes> <Cliente Cuenta= "0001"> <Nombre>Nombre1</Nombre> </Cliente> </Clientes> |
Inicialmente, se implementa una clase llamada ParsearSAX
, que hereda de la clase base DefaultHandler
, y que sobrescribe una serie de métodos para controlar los eventos de SAX:
1 2 3 |
public class ParsearSAX extends DefaultHandler { |
Función que inicializará las variables que posteriormente serán usadas en la clase. Este método posibilita el comienzo del procesado del documento:
1 2 3 4 5 6 |
@Override public void startDocument() throws SAXException { System.out.println("\nINICIO DOCUMENTO..."); } |
Se van mostrando diferentes mensajes a raíz de cada evento que se va lanzando. Este método será llamado al comenzar procesar una etiqueta XML:
1 2 3 4 5 6 7 8 |
@Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { System.out.println("URI: " + uri); System.out.println("LOCALNAME: " + localName); System.out.println("NAME: " + name); |
Se recorren los atributos de los elementos:
1 2 3 4 5 6 7 8 |
System.out.println("\tATRIBUTOS: " + attributes.getLength()); for(int i=0;i<attributes.getLength();i++) { System.out.println("\t\tNOMBRE ATRIBUTO: " + attributes.getQName(i)); System.out.println("\t\tTEXTO ATRIBUTO: " + attributes.getValue(i)); } } |
Al encontrar una cadena de texto se ejecutará el siguiente método:
1 2 3 4 5 6 7 |
@Override public void characters(char[] ch, int start, int length) { System.out.println("\nTEXTO ETIQUETA"); System.out.println("\tTEXTO: " + String.valueOf(ch, start, length)); } |
Función encargada de comprobar la etiqueta final de cada elemento del documento:
1 2 3 4 5 6 7 8 9 |
@Override public void endElement(String uri, String localName, String name) throws SAXException { System.out.println("\nFIN ETIQUETA"); System.out.println("\tURI: "+uri); System.out.println("\tLOCALNAME: "+localName); System.out.println("\tNAME: "+name); } |
Este método se lanzará al finalizar el procesado del documento:
1 2 3 4 5 |
@Override public void endDocument() throws SAXException { } } |
Como se puede apreciar en el siguiente método, se crea una instancia SAXParserFactory
, para posteriormente crear un nuevo parseador de tipo SAXParser
. A continuación se crea un objeto ParsearSAX
(que si recordamos heredaba de la clase DefaultHandler
y sobrescribía una serie de métodos), asociándolo al XMLReader
, indicándole finalmente el InputStream
que recibe como argumento de entrada:
1 2 3 4 5 6 7 8 9 10 |
public void leerXMLSAX(InputStream stream) throws Exception { SAXParserFactory fabrica = SAXParserFactory.newInstance(); SAXParser parser = fabrica.newSAXParser(); XMLReader reader = parser.getXMLReader(); ParsearSAX parsearSAX = new ParsearSAX(); reader.setContentHandler(parsearSAX); reader.parse(new InputSource(new FileInputStream("data/data/com.academiaandroid.parsearxml/files/clienteSAX.xml"))); } |
Finalmente, la salida de este ejemplo será la siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
INICIO DOCUMENTO... 11-28 01:20:49.476 32600-32600/? I/System.out﹕ URI: 11-28 01:20:49.476 32600-32600/? I/System.out﹕ LOCALNAME: Clientes 11-28 01:20:49.480 32600-32600/? I/System.out﹕ NAME: Clientes 11-28 01:20:49.480 32600-32600/? I/System.out﹕ ATRIBUTOS: 0 11-28 01:20:49.480 32600-32600/? I/System.out﹕ [ 11-28 01:20:49.480 32600:32600 I/System.out ] TEXTO ETIQUETA 11-28 01:20:49.480 32600-32600/? I/System.out﹕ TEXTO: 11-28 01:20:49.480 32600-32600/? I/System.out﹕ URI: 11-28 01:20:49.480 32600-32600/? I/System.out﹕ LOCALNAME: Cliente 11-28 01:20:49.480 32600-32600/? I/System.out﹕ NAME: Cliente 11-28 01:20:49.480 32600-32600/? I/System.out﹕ ATRIBUTOS: 1 11-28 01:20:49.480 32600-32600/? I/System.out﹕ NOMBRE ATRIBUTO: Cuenta 11-28 01:20:49.480 32600-32600/? I/System.out﹕ TEXTO ATRIBUTO: 0001 11-28 01:20:49.480 32600-32600/? I/System.out﹕ [ 11-28 01:20:49.480 32600:32600 I/System.out ] TEXTO ETIQUETA 11-28 01:20:49.480 32600-32600/? I/System.out﹕ TEXTO: 11-28 01:20:49.480 32600-32600/? I/System.out﹕ URI: 11-28 01:20:49.480 32600-32600/? I/System.out﹕ LOCALNAME: Nombre 11-28 01:20:49.480 32600-32600/? I/System.out﹕ NAME: Nombre 11-28 01:20:49.480 32600-32600/? I/System.out﹕ ATRIBUTOS: 0 11-28 01:20:49.480 32600-32600/? I/System.out﹕ [ 11-28 01:20:49.480 32600:32600 I/System.out ] TEXTO ETIQUETA 11-28 01:20:49.480 32600-32600/? I/System.out﹕ TEXTO: Nombre1 11-28 01:20:49.480 32600-32600/? I/System.out﹕ [ 11-28 01:20:49.480 32600:32600 I/System.out ] FIN ETIQUETA 11-28 01:20:49.480 32600-32600/? I/System.out﹕ URI: 11-28 01:20:49.480 32600-32600/? I/System.out﹕ LOCALNAME: Nombre 11-28 01:20:49.480 32600-32600/? I/System.out﹕ NAME: Nombre 11-28 01:20:49.480 32600-32600/? I/System.out﹕ [ 11-28 01:20:49.480 32600:32600 I/System.out ] TEXTO ETIQUETA 11-28 01:20:49.480 32600-32600/? I/System.out﹕ TEXTO: 11-28 01:20:49.480 32600-32600/? I/System.out﹕ [ 11-28 01:20:49.480 32600:32600 I/System.out ] FIN ETIQUETA 11-28 01:20:49.480 32600-32600/? I/System.out﹕ URI: 11-28 01:20:49.480 32600-32600/? I/System.out﹕ LOCALNAME: Cliente 11-28 01:20:49.480 32600-32600/? I/System.out﹕ NAME: Cliente 11-28 01:20:49.480 32600-32600/? I/System.out﹕ [ 11-28 01:20:49.480 32600:32600 I/System.out ] TEXTO ETIQUETA 11-28 01:20:49.480 32600-32600/? I/System.out﹕ TEXTO: 11-28 01:20:49.480 32600-32600/? I/System.out﹕ [ 11-28 01:20:49.480 32600:32600 I/System.out ] FIN ETIQUETA |
XMLPull
Como hemos indicado al principio, dentro del modelo de parseo en streaming hay otra forma de hacer el tratamiento de la información, que denominamos de tipo ‘pull’.
XmlPull es un parseado de ese tipo, muy similar al modelo StAX (Streaming API for XML), que sería como una variante de SAX. Todos hacen una lectura secuencial de la información, pero en los de tipo ‘pull’ somos nosotros los que vamos solicitando el siguiente elemento del fichero XML para realizar las acciones que necesitamos.
En una publicación posterior se describirá el método crearXML() dentro del ejercicio práctico que desarrollaremos y donde se hará uso de la interfaz XmlSerializer del paquete org.xmlpull.v1 para la creación de un documento XML (documentación oficial de la API)
Esta entrada tiene 2 comentarios
Los comentarios están cerrados.
[…] 2.Tratamiento de XML en Android: SAX […]
[…] 2.Tratamiento de XML en Android: SAX […]