Sei sulla pagina 1di 38

Android

Web Services
(Tratamiento de XML)

Software Engineer: Israel Rosas Soria Twitter:@ssnova24 Correo: israel.rosas@joedayz.pe

Tratamiento XML
Para el manejo exclusivo de XML, tendremos 4 maneras de tratarlos, los cuales los mencionamos a continuacin:

1. 2. 3. 4.

Tratamiento de XML con SAX. Tratamiento de XML con SAX Simplificado. Tratamiento de XML con DOM. Tratamiento de XML con XmlPull.

Tratamiento XML
Utilizaremos el archivo llamado primerXml.xml, de nuestra carpeta XMLS Como podemos observar el xml se compone de un elemento principal <channel> y posteriormente una lista de elementos <item> para cada noticia con sus datos asociados. Para poder trabajar, procederemos a crear nuestro modelo; llamado Noticia, al cual le colocaremos los siguiente atributos, y generaremos sus mtodos de acceso.

private String titulo; private String link; private String descripcion; private String guid; private String fecha;

(*) Definiremos a todos los mtodos como String para no complicarnos en el desarrollo del laboratorio.

Ahora, que ya sabemos con que estructura y que clase auxiliar vamos a trabajar procederemos a detallar cada modelo, cualquiera de los mencionados anteriormente pueden tratar XML de manera online como local, pero dependiendo del contexto veremos cual resulta mas eficiente para ciertos escenarios. Como estamos viendo Servicios Web, nos centraremos en xml Online.

Tratamiento XML
Puntos a seguir, para el tratamiento XML:

1. 2. 3. 4.

Tratamiento de XML con SAX. Tratamiento de XML con SAX Simplificado. Tratamiento de XML con DOM. Tratamiento de XML con XmlPull.

Tratamiento XML - SAX


SAX (Simple API for XML)
El tratamiento se basa en un analizador (parser), que lee secuencialmente el documento y a su vez genera eventos con la informacin de cada elemento.
Entonces, por ejemplo:

<title> Texto dentro de la etiqueta


Los mtodos principales son:

-> startElement() -> characters()

startDocument(): comienza el documento XML. endDocument(): termina el documento XML. startElement(): comienza una etiqueta XML. endElement(): termina una etiqueta XML. characters(): fragmento de texto.

Lista Completa:

http://developer.android.com/reference/org/xml/sax/helpers/DefaultHandler.html

Tratamiento XML - SAX


Para poder hacer uno de los mtodos mencionados debemos extender de la clase DefaultHandler, ahora crearemos una clase llamada NoticiaHandler que extienda de DefaultHandler. A dicha clase declararemos los siguientes atributos:

private List<Noticia> noticias; private Noticia noticiaActual; private StringBuilder sbTexto;

Generaremos el mtodo de acceso get, para la variable tipo List

Vamos a generar un Listado de Noticias, y con el mtodo getNoticias() [Lo realizaremos con el mtodo de acceso para get()] obtendremos las noticias tras el termino de lectura del documento. Ahora comencemos con los eventos SAX necesarios.

Tratamiento XML - SAX


Comencemos por startDocument(), este evento indica que se ha comenzado a leer el documento XML, por lo que lo aprovecharemos para inicializar la lista de noticias y las variables auxiliares.
noticias = new ArrayList<Noticia>(); sbTexto = new StringBuilder();

Ahora procederemos con el evento startElement() se lanza cada vez que se encuentra una nueva etiqueta de apertura. En nuestro caso, la nica etiqueta que nos interesar ser <item>, momento en el que inicializaremos un nuevo objeto auxiliar de tipo Noticia donde almacenaremos posteriormente los datos de la noticia actual.
if (localName.equals("item")) { noticiaActual = new Noticia(); }

Tratamiento XML - SAX


El siguiente evento relevante es characters(), que se lanza cada vez que se encuentra un fragmento de texto en el interior de una etiqueta. La tcnica aqu ser ir acumulando en una variable auxiliar, sbTexto, todos los fragmentos de texto que encontremos hasta detectarse una etiqueta de cierre. if (this.noticiaActual != null) { sbTexto.append(ch, start, length);

}
Por ltimo, en el evento endElement(), lo que haremos ser almacenar en el objeto noticiaActual (que conoceremos por el parmetro localName devuelto por el evento) el texto que hemos ido acumulando en la variable sbTexto y limpiaremos dicha variable para comenzar a acumular el siguiente dato. El nico caso especial ser cuando detectemos el cierre de la etiqueta <item>, que significar que hemos terminado de leer todos los datos de la noticia y por tanto aprovecharemos para aadir la noticia actual a la lista de noticias que estamos construyendo.

Tratamiento XML - SAX


if (this.noticiaActual != null) { if (localName.equals("title")) { noticiaActual.setTitulo(sbTexto.toString()); } else if (localName.equals("link")) { noticiaActual.setLink(sbTexto.toString()); } else if (localName.equals("description")) { noticiaActual.setDescripcion(sbTexto.toString()); } else if (localName.equals("guid")) { noticiaActual.setGuid(sbTexto.toString()); } else if (localName.equals("pubDate")) { noticiaActual.setFecha(sbTexto.toString()); } else if (localName.equals("item")) { noticias.add(noticiaActual); } sbTexto.setLength(0); }

Tratamiento XML - SAX


Ahora crearemos una clase que nos ayude a realizar el Parser, la llamaremos NoticiaParserSax. Esta clase tendr nicamente un constructor que reciba como parmetro la URL del documento a parsear, y un mtodo pblico llamado parse() para ejecutar la lectura del documento, y que devolver como resultado una lista de noticias. Parmetro URL: private URL noticiaUrl;

Constructor

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

El constructor de la clase se limitar a aceptar como parmetro la URL del documento XML a parsear a controlar la validez de dicha URL, generando una excepcin en caso contrario.

Tratamiento XML - SAX


Mtodo pblico parse()

public List<Noticia> parse(){ SAXParserFactory factory = SAXParserFactory.newInstance(); try{ SAXParser parser = factory.newSAXParser(); NoticiasHandler handler = new NoticiasHandler(); parser.parse(this.getInputStream(), handler); return handler.getNoticias(); }catch (Exception e){ throw new RuntimeException(e); } }

Ser el encargado de crear un nuevo parser SAX mediante su fbrica correspondiente y de iniciar el proceso pasando al parser una instancia del handler que hemos creado anteriormente y una referencia al documento a parsear en forma de stream.

Tratamiento XML - SAX


Mtodo getInputStream()

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

Se encarga de abrir la conexin con la URL especificada mediante openConnection() y obtener el stream de entrada

Ahora solamente en nuestro Activity nos falta enviarle el url al momento de crear un nuevo ParserSax; y no nos olvidemos del permiso hacia internet. NoticiaParserSax saxparser = new NoticiaParserSax("http://www.e-linguasac.com/primerXml.xml"); List<Noticia> noticias = saxparser.parse();

<uses-permission android:name="android.permission.INTERNET" />

Tratamiento XML
Puntos a seguir, para el tratamiento XML:

1. 2. 3. 4.

Tratamiento de XML con SAX. Tratamiento de XML con SAX Simplificado. Tratamiento de XML con DOM. Tratamiento de XML con XmlPull.

Tratamiento XML SAX Simplificado


En las diapositivas anteriores vimos como consumir un XML con SAX Clsico, vimos como utilizar un handler SAX , donde se definan las acciones a realizar tras recibirse cada uno de los posibles eventos generados por el parser XML. Desventajas del SAX Clsico: Definir una clase independiente para el handler. Los eventos SAX definidos no estn ligados de ninguna forma a etiquetas concretas del documento XML sino que se lanzarn para todas ellas. Tener que colocar condicionales en el mtodo endElement(), En primer lugar tenamos que comprobar la condicin 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>. Si esto no se valida correctamente para un documento un poco mas complejo, se puede complicar, y generar errores.

Tratamiento XML SAX Simplificado


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.

Ahora generaremos una clase llamada NoticiasParserSax2, en ella declararemos 2 atributos:


private URL noticiaUrl; private Noticia noticiaActual;

En el constructor por defecto, Recibiremos una url para validar:

try{
this. noticiaUrl = new URL(url); } catch (MalformedURLException e){ throw new RuntimeException(e); }

Tratamiento XML SAX Simplificado


Ahora en nuestro mtodo parser(), ya no declararemos un parser factory, sino esta vez especificaremos directamente a la raz y los elementos.

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"); //Aqu comenzaremos a leer el documento en si. }

Tratamiento XML SAX Simplificado


Para inicializar la lectura del documento, procedemos a realizar setStartElementListener(), y luego procedemos a inicializar el atributo noticiaActual

item.setStartElementListener(new StartElementListener(){ public void start(Attributes attrs) { noticiaActual = new Noticia(); } });
Para finalizar la lectura del documento, procedemos a realizar setEndElementListener(), y luego procedemos a agregar a la lista noticias, los objetos noticiaActual.

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

Tratamiento XML SAX Simplificado


Para poder extraer los elementos de nuestro archivo xml, procedemos a hacer uso del mtodo: item.getChild(nombre del elemento").setEndTextElementListener(), para nuestro ejemplo vamos a tener 5 elementos: title, link, description, guid, pubDate.

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); } });

Tratamiento XML SAX Simplificado


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); } });

Tratamiento XML SAX Simplificado


Antes de terminar realizaremos el parser, con ayuda de la clase Xml, que nos permitir establecer un Stream para la lectura del xml; el mtodo parser recibir 3 parmetros: la conexin para el acceso con el Stream, el tipo de codificacin y finalmente

try{

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


Una vez realizado procederemos a retornar el listado de noticias.; Como vemos nos pedir realizar un mtodo llamado getInputStream(), el cual nos devolver la conexin para poder entrar a la estructura del xml.

Tratamiento XML SAX Simplificado


Mtodo getInputStream():

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

Como ya sabemos este mtodo es el que nos permitir crear el acceso o la entrada al Stream.

Tratamiento XML SAX Simplificado - Importante


Puede que en ocasiones el servicio de internet, se corte y despus de un momento regrese, cuando esto sucede, la aplicacin puede que pierda el hilo del proceso, cuando esto sucede, puede que genere error de conexin, para evitar estos problemas futuros vamos a definir una poltica de hilo en modo estricto, de manera que la app, mantenga el hilo en uso.

if (android.os.Build.VERSION.SDK_INT > 9) {

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy);


}

Colocar esta validacin en el mtodo onCreate(), del Activity

Tratamiento XML
Puntos a seguir, para el tratamiento XML:

1. 2. 3. 4.

Tratamiento de XML con SAX. Tratamiento de XML con SAX Simplificado. Tratamiento de XML con DOM. Tratamiento de XML con XmlPull.

Tratamiento XML DOM


Los dos modelos vistos anteriormente nos realizaban una lectura del xml de manera secuencial, por otro lado con DOM, el documento XML se lee completamente antes de poder realizar ninguna accin en funcin de su contenido. El parser DOM devuelve todo su contenido en forma de una estructura de tipo rbol, donde vemos la jerarqua padre-hijo.

<noticias> <noticia> <titulo>T1</titulo> <link>L1</link> </noticia> <noticia> <titulo>T2</titulo> <link>L2</link> </noticia> <noticias>
Como vemos, este rbol conserva la misma informacin contenida en el fichero XML pero en forma de nodos y transiciones entre nodos, de forma que se puede navegar fcilmente por la estructura.

Tratamiento XML DOM


Ventajas Sustanciales: Este rbol se conserva persistente en memoria una vez ledo el documento completo. A diferencia de SAX podemos procesarlo en cualquier orden y tantas veces como sea necesario.

Ahora comenzaremos a realizar el parser mediante DOM para poder realizar la comparativa con SAX. Para esto crearemos la clase NoticiaParseDom. Como hasta el momento hemos visto siempre manejamos una ruta, en este caso tambin tendremos que definirla.
Parmetro URL: Constructor private URL noticiaUrl;

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

Tratamiento XML DOM


Como ya conocemos definiremos nuestro mtodo parser(), donde instanciaremos de la clase DocumentBuilderFactory.

public List<Noticia> parse(){ //Instanciamos la fbrica para DOM DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); List<Noticia> noticias = new ArrayList<Noticia>(); //Aqu comenzaremos a leer el documento en si. }

Simplemente instanciamos para crear nuestro factory con el cual utilizaremos para crear nuestro parser.

Tratamiento XML DOM


Ahora procederemos a crear nuestro parser

try{ //Creamos un nuevo parser DOM DocumentBuilder builder = factory.newDocumentBuilder(); //Realizamos la lectura completa del XML Document dom = builder.parse(this.getInputStream()); //Nos posicionamos en el nodo principal del rbol (<rss>) Element root = dom.getDocumentElement(); //Localizamos todos los elementos <item> NodeList items = root.getElementsByTagName("item"); //AQU CONTINUAREMOS REALIZANDO LA LECTURA }catch (Exception ex){ throw new RuntimeException(ex); } return noticias;

Tratamiento XML DOM


Comenzaremos a leer la lista de las noticias (items)

//Recorremos la lista de noticias for (int i=0; i<items.getLength(); i++){ Noticia noticia = new Noticia(); //Obtenemos la noticia actual Node item = items.item(i); //Obtenemos la lista de datos de la noticia actual NodeList datosNoticia = item.getChildNodes();

Sabemos que items, es el que va almacenar las noticias del xml, entonces procedemos a recorrerlo. Hay que tener presente que NodeList, reconoce todos los elementos que le coloquemos y los almacena en memoria para su posterior utilizacin.

Tratamiento XML DOM


Una vez, recorrido todas las noticias procedemos a obtener el contenido de cada noticia y la asignamos a nuestro modelo, finalmente el modelo lo agregaremos a la lista.

for (int j=0; j<datosNoticia.getLength(); j++){ Node dato = datosNoticia.item(j); String etiqueta = dato.getNodeName(); if (etiqueta.equals("title")){ String texto = obtenerTexto(dato); noticia.setTitulo(texto); }else if (etiqueta.equals("link")){ noticia.setLink(dato.getFirstChild().getNodeValue()); }else if (etiqueta.equals("description")){ String texto = obtenerTexto(dato); noticia.setDescripcion(texto); }else if (etiqueta.equals("guid")){ noticia.setGuid(dato.getFirstChild().getNodeValue()); }else if (etiqueta.equals("pubDate")){ noticia.setFecha(dato.getFirstChild().getNodeValue()); } } noticias.add(noticia);

Tratamiento XML DOM


Vemos 2 casos especiales:

if (etiqueta.equals("title")){ String texto = obtenerTexto(dato); noticia.setTitulo(texto); }else if (etiqueta.equals("description")){ String texto = obtenerTexto(dato); noticia.setDescripcion(texto); }
Como vimos en el ejemplo grfico de rbol DOM, el texto de un nodo determinado se almacena como nodo hijo. Este nodo de texto suele ser nico, por lo que la forma habitual de obtener el texto de un nodo es obtener su primer nodo hijo y obtener su valor:

String texto = nodo.getFirstChild().getNodeValue();

Tratamiento XML DOM


Pero en ocasiones el texto del nodo viene fragmentado en varios nodos hijos, esto sucede porque se utilizan entidades HTML; por ejemplo &quot; () . En este caso hay que recorrer todos los nodos hijos e ir concatenando para obtener el texto completo.

private String obtenerTexto(Node dato){ StringBuilder texto = new StringBuilder(); NodeList fragmentos = dato.getChildNodes(); for (int k=0;k<fragmentos.getLength();k++){ texto.append(fragmentos.item(k).getNodeValue()); } return texto.toString(); }
En nuestro mtodo de obtenerTexto vamos a enviar el Nodo del cual vamos a comenzar a concatenar y realizamos el mismo procedimiento como si estuviramos leyendo cualquier NodeList.

Finalmente instanciaremos a nuestra clase NoticiaParserDom desde el Activity Main, y ya tenemos el tratamiento XML con DOM.

Tratamiento XML
Puntos a seguir, para el tratamiento XML:

1. 2. 3. 4.

Tratamiento de XML con SAX. Tratamiento de XML con SAX Simplificado. Tratamiento de XML con DOM. Tratamiento de XML con XmlPull.

Tratamiento XML XmlPull


Ahora vamos a ver el ltimo mtodo, el cual es una versin similar al modelo StAX (Streaming API for XML), que en esencia es muy parecido al modelo SAX ya comentado.

Entonces en donde radica la diferencia??


En el SAX no podiamos intervenir una vez iniciada la lectura secuencial del XML, en cambio en XmlPull podremos indicarle de forma explicita la lectura del siguiente elemento del XML.

Crearemos nuestra clase NoticiaParserPull, en la cual como ya sabemos crearemos nuestro mtodo de validacin de URL.
En nuestro mtodo parser, definiremos estos 2 atributos, y los inicializarlos List<Noticia> noticias = null; XmlPullParser parser = Xml.newPullParser();

Creamos nuestro try catch que venimos utilizando y retornamos la lista de noticias.

Tratamiento XML XmlPull


Comenzaremos a definir los siguientes atributos, donde el getInputStream como ya sabemos establece la conexin, el evento nos generara un tipo e instanciamos un objeto de tipo noticia: parser.setInput(this.getInputStream(), null); int evento = parser.getEventType(); Noticia noticiaActual = null;

Nos centraremos principalmente en el evento, el cual nos indicar si estamos iniciando el documento, tambin el inicio de los tag y dems. Comenzaremos con crear un while, con dicha estructura vamos a recorrer el documento. while (evento != XmlPullParser.END_DOCUMENT){ String etiqueta = null; //comenzaremos a recorrer las etiquetas
evento = parser.next(); }

Tratamiento XML XmlPull


Mientras el evento sea diferente a Fin del Documento. Generaremos un switch para los dems casos. switch (evento) { //cases. } En primer lugar veremos si estamos posicionndonos en el inicio del documento: case XmlPullParser.START_DOCUMENT: noticias = new ArrayList<Noticia>(); break;

Ahora procederemos a leer los tag:


case XmlPullParser.START_TAG: etiqueta = parser.getName(); //ANALIZAREMOS LAS ETIQUETAS break;

Tratamiento XML XmlPull


Ahora comenzaremos a analizar si la primera etiqueta es item, si es la etiqueta inicializamos el objeto noticia para poder comenzar a llenarlo con el contenido del item. if (etiqueta.equals("item")){ noticiaActual = new Noticia(); }

Caso contrario es cuando ya no item y son las dems etiquetas que pueden ser su contenido, propiamente dicho: else if (noticiaActual != null){ //analizar las demas etiquetas //title, description y dems }

Tratamiento XML XmlPull


Ahora comenzaremos a analizar si la primera etiqueta es item, si es la etiqueta inicializamos el objeto noticia para poder comenzar a llenarlo con el contenido del item.
if (etiqueta.equals("link")){ noticiaActual.setLink(parser.nextText()); }else if (etiqueta.equals("description")){ noticiaActual.setDescripcion(parser.nextText()); }else if (etiqueta.equals("pubDate")){ noticiaActual.setFecha(parser.nextText()); }else if (etiqueta.equals("title")){ noticiaActual.setTitulo(parser.nextText()); }else if (etiqueta.equals("guid")){ noticiaActual.setGuid(parser.nextText()); }

Comenzaremos a leer las etiquetas y comparamos para setear el valor en el objeto Noticia.

Tratamiento XML XmlPull


Finalmente validaremos si es el final del tag:

case XmlPullParser.END_TAG: etiqueta = parser.getName(); if (etiqueta.equals("item") && noticiaActual != null){ noticias.add(noticiaActual); } break;

El ltimo case de nuestro switch nos indicar que ya hemos terminado el tag y agregamos el objeto tipo Noticias a nuestro listado llamado noticias. (*) No nos olvidemos de agregarlo en nuestro Activity.

Potrebbero piacerti anche