SDK de Android: Desarrolla un analizador SAX simple
Spanish (Español) translation by Steven (you can also view the original English article)
Analizar datos de un archivo XML es un objetivo muy común en las aplicaciones móviles. Este tutorial te proporcionará un enfoque práctico para leer datos XML con un analizador SAX. SAX es una abreviatura de "API simple para XML" y es una herramienta muy poderosa para leer XML.
Pros y contras del analizador SAX
Una de las mayores ventajas que ofrecen los analizadores SAX es una huella de memoria reducida. Analizan cada línea de datos XML a la vez y, en consecuencia, no necesitan cargar todo el documento XML en la memoria antes de hacer que los datos sean accesibles. Se trata de un aumento significativo del rendimiento, y esto realmente se hace visible cuando se trabaja con documentos XML de gran tamaño.
Una de las desventajas de usar un analizador SAX es que debes definir una API dirigida por eventos que responderá a cada elemento a medida que se reciba. Esto puede llevar mucho tiempo desarrollarlo, pero si estás dispuesto a dedicar un poco más de tiempo para hacerlo bien, el resultado valdrá la pena.
Comprendiendo el XML
XML es un medio para almacenar y transportar datos. Una de las principales cosas que necesitarás saber para este tutorial es la estructura de un documento XML. XML está hecho de una serie de etiquetas, al igual que HTML. Un ejemplo de una etiqueta de apertura sería <example> y una etiqueta de cierre complementaria sería </example>. Entre estas etiquetas encontraremos los datos contenidos por la etiqueta de ejemplo (también llama a un elemento). En ciertos casos, podemos tener etiquetas con atributos que necesitamos manejar en nuestro analizador SAX. Un ejemplo de esto que ocurre en XML sería <example attr='value'>.
Paso 1: Configurar la aplicación
Deberás crear un nuevo proyecto en Eclipse. Dado que estamos trabajando con XML y utilizaremos Internet para la transferencia de datos, debemos otorgar permiso a la aplicación para acceder a Internet. Para hacer esto, debe abrir el archivo de manifiesto de la aplicación y agregar esta línea de código en la parte inferior, justo antes de la etiqueta de cierre </manifest>:
1 |
<uses-permission android:name="android.permission.INTERNET"></uses-permission> |
Mientras estés en tu archivo de manifiesto, también debes hacer que tu aplicación sea depurable. Esto se puede hacer agregando la siguiente línea de código en la etiqueta de tu aplicación:
1 |
android:debuggable='true' |
Ahora que la aplicación tiene acceso a Internet y se puede depurar, podemos comenzar a implementar el analizador SAX.
Paso 2: Creación de clases y UI
Primero, necesitarás crear tres clases. La primera clase que debe crearse cuando creaste el proyecto será la de actividad (Activity). En esta clase, todos los datos obtenidos se utilizarán y se mostrarán en la pantalla. La segunda clase requerida será el manejador, en esta clase se realizará toda la extracción y configuración de datos. La tercera clase contendrá todos los captadores y definidores que necesitamos para configurar los datos y recuperarlos.
El main.xml en tu carpeta de recursos debe modificarse como se muestra a continuación:
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" |
3 |
android:layout_width="fill_parent" |
4 |
android:layout_height="fill_parent" |
5 |
android:orientation="vertical" |
6 |
android:id="@+id/layout"> |
7 |
|
8 |
<TextView
|
9 |
android:layout_width="fill_parent" |
10 |
android:layout_height="wrap_content" |
11 |
android:text="@string/hello" |
12 |
android:textSize="15dp" |
13 |
android:gravity="center_horizontal" |
14 |
android:id="@+id/layout_string"/> |
15 |
|
16 |
</LinearLayout>
|
Paso 3: El controlador de contenido
El controlador de contenido es donde necesitamos manejar cada uno de los eventos entrantes del XML. Entonces, básicamente, lo que hará el controlador de contenido es leer el XML hasta que llegue al final.
Cuando se alcanza una etiqueta de apertura como <example>, se llamará al controlador startElement. Cuando se alcanzan etiquetas de cierre como </example>, se llama a un método de cierre llamado endElement. Cuando el analizador SAX llega a las etiquetas de cierre, llama a un método llamado characters que obtendrá todo el contenido que se encuentra entre las etiquetas de apertura y cierre. Tenemos una cadena que se llama elementValue, que se establece en nulo. Cada vez que el analizador pasa por iniciar una etiqueta final, estableceremos la cadena elementValue con los datos entre esas etiquetas. También usaremos un valor booleano llamado elementOn. Usamos esto para realizar un seguimiento de dónde se pasa el XML, de modo que cuando se termina de leer una etiqueta y se extraen los datos, lo establecemos en falso para que podamos leer la siguiente etiqueta en el XML.
Tenemos sentencias if para verificar cuando llegamos a una etiqueta específica para usar establecedores y así establecer los datos en una lista de matriz, de modo que podamos mostrarla más tarde.
A continuación verás el código de muestra utilizado en el controlador de contenido:
1 |
|
2 |
package com.android.SAXParser; |
3 |
import org.xml.sax.Attributes; |
4 |
import org.xml.sax.SAXException; |
5 |
import org.xml.sax.helpers.DefaultHandler; |
6 |
|
7 |
public class XMLHandler extends DefaultHandler { |
8 |
|
9 |
String elementValue = null; |
10 |
Boolean elementOn = false; |
11 |
public static XMLGettersSetters data = null; |
12 |
|
13 |
public static XMLGettersSetters getXMLData() { |
14 |
return data; |
15 |
}
|
16 |
|
17 |
public static void setXMLData(XMLGettersSetters data) { |
18 |
XMLHandler.data = data; |
19 |
}
|
20 |
|
21 |
/**
|
22 |
* This will be called when the tags of the XML starts.
|
23 |
**/
|
24 |
@Override
|
25 |
public void startElement(String uri, String localName, String qName, |
26 |
Attributes attributes) throws SAXException { |
27 |
|
28 |
elementOn = true; |
29 |
|
30 |
if (localName.equals("CATALOG")) |
31 |
{
|
32 |
data = new XMLGettersSetters(); |
33 |
} else if (localName.equals("CD")) { |
34 |
/**
|
35 |
* We can get the values of attributes for eg. if the CD tag had an attribute( <CD attr= "band">Akon</CD> )
|
36 |
* we can get the value "band". Below is an example of how to achieve this.
|
37 |
*
|
38 |
* String attributeValue = attributes.getValue("attr");
|
39 |
* data.setAttribute(attributeValue);
|
40 |
*
|
41 |
* */
|
42 |
}
|
43 |
}
|
44 |
|
45 |
/**
|
46 |
* This will be called when the tags of the XML end.
|
47 |
**/
|
48 |
@Override
|
49 |
public void endElement(String uri, String localName, String qName) |
50 |
throws SAXException { |
51 |
|
52 |
elementOn = false; |
53 |
|
54 |
/**
|
55 |
* Sets the values after retrieving the values from the XML tags
|
56 |
* */
|
57 |
if (localName.equalsIgnoreCase("title")) |
58 |
data.setTitle(elementValue); |
59 |
else if (localName.equalsIgnoreCase("artist")) |
60 |
data.setArtist(elementValue); |
61 |
else if (localName.equalsIgnoreCase("country")) |
62 |
data.setCountry(elementValue); |
63 |
else if (localName.equalsIgnoreCase("company")) |
64 |
data.setCompany(elementValue); |
65 |
else if (localName.equalsIgnoreCase("price")) |
66 |
data.setPrice(elementValue); |
67 |
else if (localName.equalsIgnoreCase("year")) |
68 |
data.setYear(elementValue); |
69 |
}
|
70 |
|
71 |
/**
|
72 |
* This is called to get the tags value
|
73 |
**/
|
74 |
@Override
|
75 |
public void characters(char[] ch, int start, int length) |
76 |
throws SAXException { |
77 |
|
78 |
if (elementOn) { |
79 |
elementValue = new String(ch, start, length); |
80 |
elementOn = false; |
81 |
}
|
82 |
|
83 |
}
|
84 |
|
85 |
}
|
En startElement he incluido un comentario para mostrar cómo obtener el atributo de una etiqueta abierta.
Paso 4: Getters, Setters y Logcat
Esta es una clase muy simple que contiene listas de matrices, captadores y definidores. Aquí, las listas de matrices se establecen desde la clase de controlador de contenido llamando a sus respectivos métodos de establecimiento.
En este ejemplo, es simple porque básicamente estamos obteniendo tipos de cadenas. Sin embargo, en otros archivos XML, es posible que debas obtener otros tipos, como la fecha o la URL, y deberás realizar los ajustes necesarios. Toma la fecha, por ejemplo: es posible que debas usar un formateador de fecha para darle formato a la fecha correctamente antes de configurarla.
En cada uno de los métodos de establecimiento, he agregado registros como el siguiente:
1 |
Log.i('This is the value:', example); |
Esto es muy útil ya que puedes usar Logcat que se encuentra en la perspectiva DDMS para rastrear todos los datos que estás obteniendo para XML. Una gran ventaja de hacer esto es que si tu código falla, sabrás exactamente en qué etiqueta está fallando el analizador y podrás realizar los ajustes necesarios.
A continuación se muestra un fragmento de código de la clase getters y setters que muestra solo uno de los métodos getter y setter:
1 |
public class XMLGettersSetters { |
2 |
private ArrayList<String> company = new ArrayList<String>(); |
3 |
public ArrayList<String> getCompany() { |
4 |
return company; |
5 |
}
|
6 |
public void setCompany(String company) { |
7 |
this.company.add(company); |
8 |
Log.i("This is the company:", company); |
9 |
}
|
A continuación se muestra una imagen de Logcat que muestra todos los datos obtenidos.


Paso 5: Visualización de los datos obtenidos
En la clase de actividad, necesitaremos crear una instancia del analizador SAX. También necesitamos crear el controlador para cada una de las etiquetas XML. También tenemos la URL del XML que debemos pasar al controlador. Aquí está el código utilizado para implementar esto:
1 |
try { |
2 |
/**
|
3 |
* Create a new instance of the SAX parser
|
4 |
**/
|
5 |
SAXParserFactory saxPF = SAXParserFactory.newInstance(); |
6 |
SAXParser saxP = saxPF.newSAXParser(); |
7 |
XMLReader xmlR = saxP.getXMLReader(); |
8 |
|
9 |
|
10 |
URL url = new URL("http://www.xmlfiles.com/examples/cd_catalog.xml"); // URL of the XML |
11 |
|
12 |
/**
|
13 |
* Create the Handler to handle each of the XML tags.
|
14 |
**/
|
15 |
XMLHandler myXMLHandler = new XMLHandler(); |
16 |
xmlR.setContentHandler(myXMLHandler); |
17 |
xmlR.parse(new InputSource(url.openStream())); |
18 |
|
19 |
} catch (Exception e) { |
20 |
System.out.println(e); |
21 |
}
|
El último paso es mostrar los datos a una actividad. Para cada categoría de datos, necesitamos crear una matriz TextView diferente. Por ejemplo:
1 |
TextView example[]; |
Al hacer esto, podremos agregar todos los datos obtenidos a estos TextViews. Necesitamos hacer que la longitud de TextView sea del tamaño de TextView, la siguiente línea de código establecerá la longitud de TextView en el tamaño de la matriz TextView:
1 |
example = new TextView[data.getExample().size()]; |
Necesitamos obtener el diseño de la Actividad para configurar todos los TextViews que se crean para ella mediante programación. Usando una vista podemos hacer esto simplemente. A continuación se muestra la línea de código que requerimos:
1 |
View layout = findViewById(R.id.layout); |
Ahora que tenemos la longitud del TextView, podemos simplemente ejecutar un bucle for para agregar los datos a estos TextViews. El ciclo for terminará cuando se alcance el final de la matriz TextView.
Aquí está el código utilizado para implementar el bucle for para establecer los datos en TextViews y luego establecer los TextViews en el diseño:
1 |
for (int i = 0; i < data.getExample().size(); i++) { |
2 |
|
3 |
example[i] = new TextView(this); |
4 |
example[i].setText("Example= "+data.getExample ().get(i)); |
5 |
|
6 |
example2[i] = new TextView(this); |
7 |
example2[i].setText("Example2 ="+data.get Example2().get(i)); |
8 |
|
9 |
((ViewGroup) layout).addView(example[i]); |
10 |
((ViewGroup) layout).addView(example2[i]); |
11 |
}
|
La última línea de código se usaría para configurar el diseño:
1 |
setContentView(layout); |
Conclusión
Ahora que todo está configurado correctamente, puedes ejecutar tu aplicación. Los resultados deben verse como la imagen de abajo. Si recibes un error, lo más probable es que no estés manejando el XML correctamente. La mejor manera de abordar la depuración es utilizando Logcat.





