En el apartado anterior del curso de programación para Android hablamos sobre SAX, el primero de los métodos disponibles en Android para leer ficheros XML desde nuestras aplicaciones. En este segundo apartado vamos a centrarnos en DOM, otro de los métodos clásicos para la lectura y tratamiento de XML.
Cuando comentábamos la filosofía de SAX ya vimos cómo con dicho modelo el tratamiento del fichero XML se realizaba de forma secuencial, es decir, se iban realizando las acciones necesarias durante la propia lectura del documento. Sin embargo, con DOM la estrategia cambia radicalmente. Con DOM, el documento XML se lee completamente antes de poder realizar ninguna acción en función de su contenido. Esto es posible gracias a que, como resultado de la lectura del documento, el parser DOM devuelve todo su contenido en forma de una estructura de tipo árbol, donde los distintos elementos del XML se representa en forma de nodos y su jerarquía padre-hijo se establece mediante relaciones entre dichos nodos.
Como ejemplo, vemos un ejemplo de XML sencillo y cómo quedaría su representación en forma de árbol:
Este XML se traduciría en un árbol parecido al siguiente:
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. Además, este árbol se conserva persistente en memoria una vez leído el documento completo, lo que permite procesarlo en cualquier orden y tantas veces como sea necesario (a diferencia de SAX, donde el tratamiento era secuencial y siempre de principio a fin del documento, no pudiendo volver atrás una vez finalizada la lectura del XML).
Para todo esto, el modelo DOM ofrece una serie de clases y métodos que permiten almacenar la información de la forma descrita y facilitan la navegación y el tratamiento de la estructura creada.
Veamos cómo quedaría nuestro parser utilizando el modelo DOM y justo después comentaremos los detalles más importantes.
Nos centramos una vez más en el método parse(). Al igual que hacíamos para SAX, el primer paso será instanciar una nueva fábrica, esta vez de tipo DocumentBuilderFactory, y posteriormente crear un nuevo parser a partir de ella mediante el método newDocumentBuilder().
Tras esto, ya podemos realizar la lectura del documento XML llamando al método parse() de nuestro parser DOM, pasándole como parámetro el stream de entrada del fichero. Al hacer esto, el documento XML se leerá completo y se generará la estructura de árbol equivalente, que se devolverá como un objeto de tipo Document. Éste será el objeto que podremos navegar para realizar el tratamiento necesario del XML.
Para ello, lo primero que haremos será acceder al nodo principal del árbol (en nuestro caso, la etiqueta <rss>) utilizando el método getDocumentElement(). Una vez posicionados en dicho nodo, vamos a buscar todos los nodos cuya etiqueta sea <item>. Esto lo conseguimos utilizando el método de búsqueda por nombre de etiqueta, getElementsByTagName("nombre_de_etiqueta"), que devolverá una lista (de tipo NodeList) con todos los nodos hijos del nodo actual cuya etiqueta coincida con la pasada como parámetro.
Una vez tenemos localizados todos los elementos <item>, que representan a cada noticia, los vamos a recorrer uno a uno para ir generando todos los objetos Noticia necesarios. Para cada uno de ellos, se obtendrán los nodos hijos del elemento mediante getChildNodes() y se recorrerán éstos obteniendo su texto y almacenándolo en el atributo correspondiente del objeto Noticia. Para saber a qué etiqueta corresponde cada nodo hijo utilizamos el método getNodeName().
Merece la pena pararnos un poco en comentar la forma de obtener el texto contenido en un nodo. Como vimos al principio del apartado en el ejemplo gráfico de árbol DOM, el texto de un nodo determinado se almacena a su vez como nodo hijo de dicho nodo. 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 de éste último obtener su valor:
Tras esto, ya podemos realizar la lectura del documento XML llamando al método parse() de nuestro parser DOM, pasándole como parámetro el stream de entrada del fichero. Al hacer esto, el documento XML se leerá completo y se generará la estructura de árbol equivalente, que se devolverá como un objeto de tipo Document. Éste será el objeto que podremos navegar para realizar el tratamiento necesario del XML.
Para ello, lo primero que haremos será acceder al nodo principal del árbol (en nuestro caso, la etiqueta <rss>) utilizando el método getDocumentElement(). Una vez posicionados en dicho nodo, vamos a buscar todos los nodos cuya etiqueta sea <item>. Esto lo conseguimos utilizando el método de búsqueda por nombre de etiqueta, getElementsByTagName("nombre_de_etiqueta"), que devolverá una lista (de tipo NodeList) con todos los nodos hijos del nodo actual cuya etiqueta coincida con la pasada como parámetro.
Una vez tenemos localizados todos los elementos <item>, que representan a cada noticia, los vamos a recorrer uno a uno para ir generando todos los objetos Noticia necesarios. Para cada uno de ellos, se obtendrán los nodos hijos del elemento mediante getChildNodes() y se recorrerán éstos obteniendo su texto y almacenándolo en el atributo correspondiente del objeto Noticia. Para saber a qué etiqueta corresponde cada nodo hijo utilizamos el método getNodeName().
Merece la pena pararnos un poco en comentar la forma de obtener el texto contenido en un nodo. Como vimos al principio del apartado en el ejemplo gráfico de árbol DOM, el texto de un nodo determinado se almacena a su vez como nodo hijo de dicho nodo. 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 de éste último obtener su valor:
Sin embargo, en ocasiones, el texto contenido en el nodo viene fragmentado en varios nodos hijos, en vez de sólo uno. Esto ocurre por ejemplo cuando se utilizan en el texto entidades HTML, como por ejemplo " . En estas ocasiones, para obtener el texto completo hay que recorrer todos los nodos hijos e ir concatenando el texto de cada uno para formar el texto completo.
Esto es lo que hace nuestra función auxiliar obtenerTexto():
Como vemos, el modelo DOM nos permite localizar y tratar determinados elementos concretos del documento XML, sin la necesidad de recorrer todo su contenido de principio a fin. Además, a diferencia de SAX, como tenemos cargado en memoria el documento completo de forma persistente (en forma de objeto Document), podremos consultar, recorrer y tratar el documento tantas veces como sea necesario sin necesidad de volverlo a parsear. En un apartado posterior veremos como todas estas características pueden ser ventajas o inconvenientes según el contexto de la aplicación y el tipo de XML tratado.
Saludos compañeros, aprovechen la información.
Saludos compañeros, aprovechen la información.
Twittear
No hay comentarios:
Publicar un comentario