android - web services - xml

38
Software Engineer: Israel Rosas Soria Twitter:@ssnova24 Correo: [email protected] Android Web Services (Tratamiento de XML)

Upload: juliusss

Post on 29-Dec-2015

133 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Android - Web Services - XML

Software Engineer: Israel Rosas Soria

Twitter:@ssnova24

Correo: [email protected]

Android Web Services (Tratamiento de XML)

Page 2: Android - Web Services - XML

Tratamiento XML

1. Tratamiento de XML con SAX.

2. Tratamiento de XML con SAX Simplificado.

3. Tratamiento de XML con DOM.

4. Tratamiento de XML con XmlPull.

Para el manejo exclusivo de XML, tendremos 4 maneras de tratarlos, los cuales

los mencionamos a continuación:

Page 3: Android - Web Services - XML

Tratamiento XML

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 métodos de acceso.

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

(*) Definiremos a todos los

métodos 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.

Utilizaremos el archivo llamado “primerXml.xml”, de nuestra carpeta XMLS

Page 4: Android - Web Services - XML

Tratamiento XML

1. Tratamiento de XML con SAX.

2. Tratamiento de XML con SAX Simplificado.

3. Tratamiento de XML con DOM.

4. Tratamiento de XML con XmlPull.

Puntos a seguir, para el tratamiento XML:

Page 5: Android - Web Services - XML

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 información de cada elemento.

Entonces, por ejemplo:

<title> -> startElement() Texto dentro de la etiqueta -> characters()

Los métodos principales son: 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

Page 6: Android - Web Services - XML

Tratamiento XML - SAX

Para poder hacer uno de los métodos 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 método de acceso

get, para la variable tipo List

Vamos a generar un Listado de Noticias, y con el método getNoticias() [Lo

realizaremos con el método de acceso para get()] obtendremos las noticias tras el

termino de lectura del documento.

Ahora comencemos con los eventos SAX necesarios.

Page 7: Android - Web Services - XML

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

Page 8: Android - Web Services - XML

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 técnica 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 parámetro 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 añadir la noticia actual a la lista de noticias que estamos

construyendo.

Page 9: Android - Web Services - XML

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

}

Page 10: Android - Web Services - XML

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 parámetro la URL del

documento a parsear, y un método público llamado parse() para ejecutar la lectura del

documento, y que devolverá como resultado una lista de noticias.

private URL noticiaUrl; Parámetro URL:

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

}

Constructor

El constructor de la clase se limitará a aceptar como parámetro la URL del documento XML a parsear a controlar la validez de dicha URL, generando una excepción en caso contrario.

Page 11: Android - Web Services - XML

Tratamiento XML - SAX

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

}

Método público

parse()

Será el encargado de crear un nuevo parser SAX mediante su fábrica 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.

Page 12: Android - Web Services - XML

Tratamiento XML - SAX

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

Método

getInputStream()

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

}

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

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

Page 13: Android - Web Services - XML

Tratamiento XML

1. Tratamiento de XML con SAX.

2. Tratamiento de XML con SAX Simplificado.

3. Tratamiento de XML con DOM.

4. Tratamiento de XML con XmlPull.

Puntos a seguir, para el tratamiento XML:

Page 14: Android - Web Services - XML

Tratamiento XML – SAX

Simplificado

En las diapositivas anteriores vimos como consumir un XML con SAX Clásico, vimos como

utilizar un handler SAX , donde se definían las acciones a realizar tras recibirse cada uno

de los posibles eventos generados por el parser XML.

Desventajas del SAX Clásico:

Definir una clase independiente para el handler.

Los eventos SAX definidos no están ligados de ninguna forma a etiquetas concretas del

documento XML sino que se lanzarán para todas ellas.

Tener que colocar condicionales en el método endElement(), 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>.

Si esto no se valida correctamente para un documento un poco mas complejo, se puede

complicar, y generar errores.

Page 15: Android - Web Services - XML

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;

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

En el constructor por defecto,

Recibiremos una url para

validar:

Page 16: Android - Web Services - XML

Tratamiento XML – SAX

Simplificado

Ahora en nuestro método parser(), ya no declararemos un parser factory, sino esta vez

especificaremos directamente a la raíz 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.

}

Page 17: Android - Web Services - XML

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

});

Page 18: Android - Web Services - XML

Tratamiento XML – SAX

Simplificado Para poder extraer los elementos de nuestro archivo xml, procedemos a hacer uso del

método: 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); } });

Page 19: Android - Web Services - XML

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

Page 20: Android - Web Services - XML

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 método parser recibirá 3 parámetros: la

conexión para el acceso con el Stream, el tipo de codificación 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 método llamado getInputStream(), el cual nos devolverá la conexión para poder

entrar a la estructura del xml.

Page 21: Android - Web Services - XML

Tratamiento XML – SAX

Simplificado Método getInputStream():

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

}

Como ya sabemos este método es el que nos permitirá crear el acceso o la entrada al Stream.

Page 22: Android - Web Services - XML

Tratamiento XML – SAX

Simplificado - Importante Puede que en ocasiones el servicio de internet, se corte y después de un momento

regrese, cuando esto sucede, la aplicación puede que pierda el hilo del proceso, cuando

esto sucede, puede que genere error de conexión, para evitar estos problemas futuros

vamos a definir una política 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 validación en el método onCreate(), del Activity

Page 23: Android - Web Services - XML

Tratamiento XML

1. Tratamiento de XML con SAX.

2. Tratamiento de XML con SAX Simplificado.

3. Tratamiento de XML con DOM.

4. Tratamiento de XML con XmlPull.

Puntos a seguir, para el tratamiento XML:

Page 24: Android - Web Services - XML

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 acción en función de su contenido.

El parser DOM devuelve todo su contenido en forma de una estructura de tipo árbol,

donde vemos la jerarquía 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 información contenida en el fichero XML pero en forma de nodos y transiciones entre nodos, de forma que se puede navegar fácilmente por la estructura.

Page 25: Android - Web Services - XML

Tratamiento XML – DOM Ventajas Sustanciales:

Este árbol se conserva persistente en memoria una vez leído 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 también

tendremos que definirla.

private URL noticiaUrl; Parámetro URL:

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

}

Constructor

Page 26: Android - Web Services - XML

Tratamiento XML – DOM

Como ya conocemos definiremos nuestro método parser(), donde instanciaremos de la

clase DocumentBuilderFactory.

public List<Noticia> parse(){ //Instanciamos la fábrica 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.

Page 27: Android - Web Services - XML

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;

Page 28: Android - Web Services - XML

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 utilización.

Page 29: Android - Web Services - XML

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

Page 30: Android - Web Services - XML

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 gráfico 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();

Page 31: Android - Web Services - XML

Tratamiento XML – DOM

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

}

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.

En nuestro método de obtenerTexto vamos a enviar el Nodo del cual vamos a comenzar a concatenar y realizamos el mismo procedimiento como si estuviéramos leyendo cualquier NodeList.

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

Page 32: Android - Web Services - XML

Tratamiento XML

1. Tratamiento de XML con SAX.

2. Tratamiento de XML con SAX Simplificado.

3. Tratamiento de XML con DOM.

4. Tratamiento de XML con XmlPull.

Puntos a seguir, para el tratamiento XML:

Page 33: Android - Web Services - XML

Tratamiento XML – XmlPull

Ahora vamos a ver el último método, el cual es una versión 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 método de validación de URL.

En nuestro método 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.

Page 34: Android - Web Services - XML

Tratamiento XML – XmlPull

Comenzaremos a definir los siguientes atributos, donde el getInputStream como ya

sabemos establece la conexión, 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, también el inicio de los tag y demás.

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

Page 35: Android - Web Services - XML

Tratamiento XML – XmlPull

Mientras el evento sea diferente a Fin del Documento. Generaremos un switch para los

demás casos.

switch (evento) { //cases…. }

En primer lugar veremos si estamos posicionándonos 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;

Page 36: Android - Web Services - XML

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 demás etiquetas que pueden ser su

contenido, propiamente dicho:

else if (noticiaActual != null){ //analizar las demas etiquetas //title, description y demás }

Page 37: Android - Web Services - XML

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.

Page 38: Android - Web Services - XML

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.