Inicio Android Tratamiento de XML en Android (II): SAX Simplificado

Tratamiento de XML en Android (II): SAX Simplificado

por sgoliver

En el artículo anterior del tutorial vimos cómo realizar la lectura y tratamiento de un documento XML utilizando el modelo SAX clásico. Vimos cómo implementar un handler SAX, donde se definían las acciones a realizar tras recibirse cada uno de los posibles eventos generados por el parser XML.

Este modelo, a pesar de funcionar perfectamente y de forma bastante eficiente, tiene claras desventajas. Por un lado se hace necesario definir una clase independiente para el handler. Adicionalmente, la naturaleza del modelo SAX implica la necesidad de poner bastante atención a la hora de definir dicho handler, ya que los eventos SAX definidos no estan ligados de ninguna forma a etiquetas concretas del documento XML sino que se lanzarán para todas ellas, algo que obliga entre otras cosas a realizar la distinción entre etiquetas dentro de cada evento y a realizar otros chequeos adicionales.

Estos problemas se pueden observar perfectamente en el evento endElement() que definimos en el ejemplo del artículo anterior. En primer lugar teníamos que comprobar la condición de que el atributo noticiaActual no fuera null, para evitar confundir el elemento <title> descendiente de <channel> con el del mismo nombre pero descendiente de <item>. Posteriormente, teníamos que distinguir con un IF gigantesco entre todas las etiquetas posibles para realizar una acción u otra. Y todo esto para un documento XML bastante sencillo. No es dificil darse cuenta de que para un documento XML algo más elaborado la complejidad del handler podría dispararse rápidamente, dando lugar a posibles errores.

Para evitar estos problemas, Android propone una variante del modelo SAX que evita definir una clase separada para el handler y que permite asociar directamente las acciones a etiquetas concretas dentro de la estructura del documento XML, lo que alivia en gran medida los inconvenientes mencionados.

Veamos cómo queda nuestro parser XML utilizando esta variante simplificada de SAX para Android y después comentaremos los aspectos más importantes del mismo.

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Attributes;

import android.sax.Element;
import android.sax.EndElementListener;
import android.sax.EndTextElementListener;
import android.sax.RootElement;
import android.sax.StartElementListener;
import android.util.Xml;

public class RssParserSax2
{
	private URL rssUrl;
	private Noticia noticiaActual;

	public RssParserSax2(String url)
	{
		try
		{
			this.rssUrl = new URL(url);
		}
		catch (MalformedURLException e)
		{
			throw new RuntimeException(e);
		}
	}

	public List<Noticia> parse()
	{
		final List<Noticia> noticias = new ArrayList<Noticia>();

		RootElement root = new RootElement("rss");
		Element channel = root.getChild("channel");
		Element item = channel.getChild("item");

		item.setStartElementListener(new StartElementListener(){
			public void start(Attributes attrs) {
				noticiaActual = new Noticia();
			}
		});

		item.setEndElementListener(new EndElementListener(){
			public void end() {
				noticias.add(noticiaActual);
			}
		});

		item.getChild("title").setEndTextElementListener(
			new EndTextElementListener(){
				public void end(String body) {
					noticiaActual.setTitulo(body);
				}
		});

		item.getChild("link").setEndTextElementListener(
			new EndTextElementListener(){
				public void end(String body) {
					noticiaActual.setLink(body);
				}
		});

		item.getChild("description").setEndTextElementListener(
			new EndTextElementListener(){
				public void end(String body) {
					noticiaActual.setDescripcion(body);
				}
		});

		item.getChild("guid").setEndTextElementListener(
			new EndTextElementListener(){
				public void end(String body) {
					noticiaActual.setGuid(body);
				}
		});

		item.getChild("pubDate").setEndTextElementListener(
			new EndTextElementListener(){
				public void end(String body) {
					noticiaActual.setFecha(body);
				}
		});

		try
		{
			Xml.parse(this.getInputStream(),
					Xml.Encoding.UTF_8,
					root.getContentHandler());
		}
		catch (Exception ex)
		{
			throw new RuntimeException(ex);
		}

		return noticias;
	}

	private InputStream getInputStream()
	{
		try
		{
			return rssUrl.openConnection().getInputStream();
		}
		catch (IOException e)
		{
			throw new RuntimeException(e);
		}
	}
}

Debemos atender principalmente al método parse(). En el modelo SAX clásico nos limitamos a instanciar al handler definido en una clase independiente y llamar al correspondiente método parse() de SAX. Por el contrario, en este nuevo modelo SAX simplificado de Android, las acciones a realizar para cada evento las vamos a definir en esta misma clase y además asociadas a etiquetas concretas del XML. Y para ello lo primero que haremos será navegar por la estructura del XML hasta llegar a las etiquetas que nos interesa tratar y una vez allí, asignarle algunos de los listeners disponibles [de apertura (StartElementListener) o cierre (EndElementListener) de etiqueta] incluyendo las acciones oportunas. De esta forma, para el elemento <item> navegaremos hasta él obteniendo en primer lugar el elemento raíz del XML (<rss>) declarando un nuevo objeto RootElement y después accederemos a su elemento hijo <channel> y a su vez a su elemento hijo <item>, utilizando en cada paso el método getChild(). Una vez heos llegado a la etiqueta deseada, asignaremos los listeners necesarios, en nuestro caso uno de apertura de etiqueta y otro de cierre, donde inicializaremos la noticia actual y la añadiremos a la lista final respectivamente, de forma análoga a lo que hacíamos para el modelo SAX clásico. Para el resto de etiquetas actuaremos de la misma forma, accediendo a ellas con getChild() y asignado los listeners necesarios.

Finalmente, iniciaremos el proceso de parsing simplemente llamando al método parse() definido en la clase android.Util.Xml, al que pasaremos como parámetros el stream de entrada, la codificación del documento XML y un handler SAX obtenido directamente del objeto RootElement definido anteriormente.

Importante indicar, tal como vimos en el apartado anterior, que si queremos ejecutar nuestro parser sin errores en cualquier versión de Android (sobre todo a partir de la 3.0) deberemos hacerlo mediante una tarea asíncrona. Tienes más información en el apartado anterior.

Como vemos, este modelo SAX alternativo simplifica la elaboración del handler necesario y puede ayudar a evitar posibles errores en el handler y disminuir la complejidad del mismo para casos en los que el documento XML no sea tan sencillo como el utilizado para estos ejemplos. Por supuesto, el modelo clásico es tan válido y eficiente como éste, por lo que la elección entre ambos es cuestión de gustos.

Puedes consultar y/o descargar el código completo de los ejemplos desarrollados en este artículo accediendo a la página del curso en GitHub.

En el siguiente artículo pasaremos ya a describir el siguiente de los métodos de lectura de XML en Android, llamado Document Object Model (DOM).

Curso de Programación Android en PDF

Este curso también está disponible en PDF. Descubre cómo conseguirlo…

¿Te ha sido de utilidad el Curso de Programación Android? ¿Quieres colaborar de forma económica con el proyecto? Puedes contribuir con cualquier cantidad, unos céntimos, unos euros, cualquier aportación será bienvenida. Además, si tu aportación es superior a una pequeña cantidad simbólica recibirás como agradecimiento un documento con la última versión del curso disponible en formato PDF. Sea como sea, muchas gracias por colaborar!

Más información:

También te puede interesar

14 comentarios

Tratamiento de XML en Android (I): SAX | sgoliver.net blog 19/01/2011 - 13:52

[…] que puede ayudar a simplicar algunas acciones y disminuir la complejidad del handler necesario. En este artículo puedes aprender a utilizar esta nueva variante de SAX para […]

Responder
Desarrollo en Android | sgoliver.net blog 31/01/2011 - 12:01

[…] Tratamiento de XML en Android (II): SAX simplicado […]

Responder
Slashhh 19/03/2011 - 2:20

Buenas noches…

Tengo dos problemas:
1.- Cuando el Dispositivo no tiene conexion, me salta un error en este codigo ¿Hay manera e que no salta el error?, se que con el permiso del STATUS o algo asi, se puede saber si tiene conexion o no, pero hay otra manera???
2.- Con este codigo, no se como puedo parsear las etiquetas «». Habría alguna forma??

Saludos y Muchas Gracias…

Responder
lgruz 20/05/2011 - 11:53

Precisamente me he quedado en el manejo del Array. ¿Como debemos obtener los datos una vez que tengamos generada la lista? Por más que he investigado no he logrado dar con la manera de obtener los datos de «noticias».

Gracias

Responder
guduchango 14/09/2011 - 2:56

Se puede hacer lo mismo para paginas en php? probe hacerlo con archivos .xml .php .aspx en un servidor apache y no funciono bueno hice pruebas rapidas, no me gusta mucho trabajar en windows, y con ese estilo de paginas solamente las puedo subir a un IIS(Internet Information Server) que viene con windows.

Responder
Tratamiento de XML en Android (IV): XmlPull | sgoliver.net blog 21/11/2011 - 20:06

[…] En los artículos anteriores dedicados al tratamiento de XML en aplicaciones Android (parte 1, parte 2, parte 3) dentro de nuestro tutorial de programación Android hemos comentado ya los modelos SAX y […]

Responder
Samuel 28/02/2012 - 19:37

Muy bueno el tutorial mas tengo un problema que no me sale nada por pantalla, le agrege una ListView para que me salga por pantalla, pero no sale nada! alguna solucion..
Gracias

Responder
Ger 08/05/2012 - 17:39

Grandioso código

El mas claro de todos los que hay en internet, incluso mejor que los de StackOverflow.

Me ha dado un error al obtener los feeds de EPI, basado en que, en la linea 98

Xml.parse(this.getInputStream(),
Xml.Encoding.UTF_8,
root.getContentHandler());

Espera por una codificacion UTF_8, mientras que estos trabajan en el formato iso-8859-1, reformado esto, ha funcionado como la seda.

Un saludo y un placer

Responder
Juan 03/09/2012 - 11:55

Hola, sólo una pregunta, cuando se ejectua este código:

item.getChild(«guid»).setEndTextElementListener(
new EndTextElementListener(){
public void end(String body) {
noticiaActual.setGuid(body);
}
});

¿se podría leer un atributo que está en la etiqueta guid? ¿Cómo?

Muchas gracias.

Responder
Ds 03/01/2013 - 18:40

Da un NetworkOnMainThreadException al try
{
Xml.parse(this.getInputStream(),
Xml.Encoding.UTF_8,
root.getContentHandler());
}

Responder
admin 03/01/2013 - 18:46

Ese error se produce porque estarás ejecutando el código del tutorial en una versión de Android 3.0 o superior. Si es así, la descarga y parseo del XML deberás realizarlos en otro hilo que no sea el proncipal de la aplicación, por ejemplo mediante una AsynTask. Saludos.

Responder
How to parse XML content of a URL in android : Android Community - For Application Development 06/04/2013 - 9:59

[…] Code snippet from: a very usefull spanish blog […]

Responder
Pablo 29/04/2013 - 15:05

Hola.

Una pregunta….como puedo recoger el atribudo de enclosure(url, length,type) o guid(isPermaLink,)?

Espero tu respuesta, para poder completar bien la lectura de este xml mostrando las imagenes.

muchas gracias por anticipado.

Responder
Curso Programación Android por Salvador Gómez – Indice de Contenidos | Miguel Moyetones 17/06/2015 - 17:53

[…] Tratamiento de XML en Android (II): SAX simplicado [v3] […]

Responder

Responder a Curso Programación Android por Salvador Gómez – Indice de Contenidos | Miguel Moyetones Cancelar respuesta

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información. Aceptar Más Información

Política de Privacidad y Cookies