Inicio > Java > XPath en Java

XPath en Java

Hola! Bueno, hacia un buen buen rato que no me sentaba a preparar bien un post, no por falta de ganas ni de temas (de hecho tengo uno sobre los botones de facebook en borrador desde hace un buen rato) sino por falta de tiempo. El overbooking me esta matando. Pero al mismo tiempo me ha permitido conocer varias cosas a compartir. Actualmente me la he pasado inmerso en archivos XML en los cuales debo recuperar ciertas informaciones, y la verdad es que nada más cómodo que hacerlo con XPath. Los comandos XPath pueden ser usados para parsear un archivo XML dentro de una XSL, o incluso, como lo pienso mostrar a continuación, con Java.

Consideremos la siguiente estructura XML

<library>
---<authors>
------<author id="1">Antoin de Saint-Exupéry</author>
------<author id="2">Arturo Perez-Reverte</author>
---</authors>
---<books>
------<book>
---------<title>Le Petit Prince</title>
---------<author_id>1</author_id>
------</book>
------<book>
---------<title>La Reina del Sur</title>
---------<author_id>2</author_id>
------</book>
---</books>
</library>

Vamos a parsear este árbol XML para formatear la sálida, mostrando 1) El total de libros que están en la Biblioteca, 2) Por cada libro, su títlo y su autor.

Clases XPath en Java


Una primera solución sería de leer el archivo de manera secuencial, pero obvio, no es lo más adecuado. Entonces, se puede preguntar uno ¿Y si existiera una manera de hacerle una serie de consultas como en SQL al archivo? Bueno, precisamente para eso es XPath. Y Java contiene en su paquete javax.xml.xpath una serie de clases para este fin. Entre ellas, XPathFactory que permite crear una instancia XPath, y con esta instancia podemos crear objetos de la clase XPathExpression, que son precisamente las consultas que evaluaremos en el archivo XML.

//Creando la Instacia xPath
XPath xPath = XPathFactory.newInstance().newXPath();
//Creando la expresión con la QUERY en sintaxis XPath
XPathExpression expression = xPath.compile( QUERY );
//Ejecutando la consulta y recuperando el resultado
TYPE value = (TYPE) expression.evaluate(DOCUMENTO_XML, XPathConstants.TYPE);

Hagamos un alto para mirar los tipos que pueden ser retornados por la consultas, ejecutadas vía el método evaluate de XPathExpression. Estos tipos son definidos en el Enum XPathConstants y son: NUMBER, STRING, BOOLEAN, (que es obvio lo que devuelven) , NODE que me devuelve un objeto de tipo org.w3c.dom.Node representado el nodo XML con sus atributos y nodos hijos, y NODESET que es una lista de Node, imbricada en el objeto org.w3c.dom.NodeList.

Consultas XPath


Ahora bien, para el que no esté familiarizado con XPath, consiste en una cadena que contiene la estructura de nodos donde vamos a buscar, seperados con “/”. Por ejemplo

  • /library/authors -> Me retornará el Nodo <authors> con todos sus nodos hijos.
  • /library/descedant::/title -> Me retornará toda la lista de nodos <title> sean hijos, nietos, bisnietos … es decir, todos los del documento, sin importar el nivel.
  • /library/books/book/title -> Me retornará la lista de todos los nodos <title> que están dentro de los nodos <book>. (¿Si notan la diferencia con respecto al anterior?)
  • count(/library/descedant::/author) -> Cuenta cuántos autores hay.
  • /library/descendant::author[ @id = 1 ] -> El nodo author que tiene el atributo id = 1. Es como hace un SQL con un WHERE.

Solución Java y XPath


Entonces, para recuperar la información en el formato que especificamos, consideremos que tenemos un método gettingBooksInformation que recibe el documento XML a parsear. Entonces:

public static void gettingBooksInformation(Document xml){
---String countBooks = "count(/library/descendant::book)";
---String getBooks = "/library/descendant::book";
---String getAuthorWithId = "/library/descendant::author[@id = ";

---XPath xPath = XPathFactory.newInstance().newXPath();
---try {
------XPathExpression expression = xPath.compile(countBooks);
------Number countNodes = (Number) expression.evaluate(xml, XPathConstants.NUMBER);
------System.out.println("Number of books: " + countNodes.intValue());

------expression = xPath.compile(getBooks);
------NodeList books = (NodeList) expression.evaluate(xml, XPathConstants.NODESET);
------for(int i = 0; i < books.getLength(); i++){

---------System.out.println( "Book #" + (i+1) );

---------NodeList bookAttributs = books.item(i).getChildNodes();
---------System.out.println( "Title: " + bookAttributs.item(0).getTextContent() );

---------expression = xPath.compile(getAuthorWithId + bookAttributs.item(1).getTextContent() + "]" );
---------Node author = (Node) expression.evaluate(xml, XPathConstants.NODE);

---------System.out.println( "Author: " + author.getTextContent() );
------}
---} catch (Exception e) {
------System.out.println(e.getMessage());
------e.printStackTrace(System.out);
---}
}

En este vínculo se encuentra el código del proyecto maven completo con el ejemplo : https://docs.google.com/open?id=0B5P2dpgKBUCFbk16Z21pSkJLR3c

Categorías:Java Etiquetas: , ,
  1. Aún no hay comentarios.
  1. No trackbacks yet.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Hype Driven Development

coz' geeks love new stuff !

My experiments with SCRUM

Site to discuss Agile (Scrum, XP, etc) concepts and ideas.

CommitStrip

Mi propia cheatsheet...

Chris Aniszczyk's (zx) diatribe

work. life. open source. diatribes.

GermanTrevi

repositorio de mi mente...

A %d blogueros les gusta esto: