lunes, 6 de noviembre de 2006

Introducción a XPath

XPath es una especificación de la World Wide Web Consortium W3C, que facilita enormemente la navegación y la lectura a través de un documento XML. Cuando comenzó la implantación de XML en los desarrollos, cada uno inventó sus librerías para parsear y acceder a los documentos XML. Esto dio lugar a un popurrí de librerías más o menos eficientes, pero cada una diferente en cuanto a filosofía y a tratamiento. Por otro lado, era arduo tener que parsear y montar un árbol de nodos y navegar a través de ello para extraer un simple dato, tal y como ocurre en la lectura de ficheros de configuración.

XPath tiene una filosofía muy simple, ya que se basa de utilizar expresiones al estilo de un path, como el de un directorio de disco, a través de los nodos del archivo XML. A ésto se le une una multitud de posibilidades, como búsqueda de ciertos elementos a partir de un valor o una máscara.

Pero para entender mejor todo ésto, lo mejor es utilizar un ejemplo e ir viendo poco a poco qué se puede hacer. Pero he de advertir que este artículo es una pequeña introducción a XPath, y en él no se ve ni una décima parte de las posibilidades que nos ofrece esta tecnología.

Comencemos por un archivo XML simple:



<?xml version="1.0" encoding="UTF-8" ?>
<libro>
<titulo>Neraclem</titulo>
<autor>Rafael Hernamperez</autor>
<fecha>8 de Octubre de 2006</fecha>
<capitulo num="1">
<parrafo num="1">
Julian creyo despertar de un extrano sueno cuando abrio sus pesados ojos.
</parrafo>
<parrafo num="2">
El aturdimiento entorpecia sus movimientos, y no se atrevio a ponerse de pie.
<enlace url="http://rafinguer.spaces.live.com">El Rincon de la Felicidad</enlace>
Cerro nuevamente sus ojos, e intento despejar su confusa mente. Todo parecia dar vueltas y estaba algo mareado.
</parrafo>
</capitulo>
<capitulo num="2">
<parrafo num="1">
Todo era blanco inmaculado. Ni frio ni calor. Ni ligero ni pesado. Cerro los ojos, reteniendo momentaneamente aquel blanco absoluto. Poco a poco, el blanco se fue haciendo gris y, por ultimo, negro.
</parrafo>
<parrafo num="2">
Abrio los ojos, descubriendo que se hallaba en una enorme sala, tan alta como la estancia que acababa de abandonar.
</parrafo>
<parrafo num="3">
Giro lentamente 360 grados, asombrado por la majestuosidad de aquella magnifica e impresionante biblioteca de miles de libros ancestrales, que descansaban en no menos majestuosas estanterias.
<enlace url="http://rafinguer.blogspot.com">Tecnologia</enlace>
Habia libros de todos los tamanos, colores y grosores. Todos tenian una encuadernacion artesana, de piel, con lomos trabajados en relieve y con titulos de oro. Alla donde Julian miraba, se perdaa en libros y mas libros.
</parrafo>
</capitulo>
</libro>



Es posible navegar a través de los elementos, utilizando la barra o slash:


/


Con ésto nos situamos en la raíz del documento (antes del elemento "libro").


/libro


Con ésto estamos situados en el directorio libro, que está bajo el nodo raíz (de un nodo raíz pueden colgar directamente varios nodos).

Es posible buscar y localizar un nodo a partir de un valor de un atributo determinado. Para ello, se utiliza una expresión con esta sintaxis:


[@atributo="valor"]


Por ejemplo:


/libro/capitulo[@num="2"]


Se situaría en el nodo capítulo 2.

Con la doble barra, se accede directamente al primer elemento o nodo que se llame así, a partir de la ubicación actual.


//parrafo


Acceso al párrafo 1 del nodo capítulo 2 (en la expresión anterior ya nos habíamos situado en dicho nodo).

Para obtener el valor de un determinado atributo, se utiliza una expresión como la siguiente:


@atributo


Como, por ejemplo:


/libro/capitulo[@num="1"]/parrafo[@num="2"]/enlace/@url


Si se desea obtener el texto de un determinado elemento, se utiliza la expresión


text()


Como en el siguiente ejemplo:


/libro/autor/text()


Las expresiones vistas hasta ahora se pueden combinar unas y otras, consiguiendo la mayor parte de accesos al documento XML. No obstante existen muchas más expresiones con las que poder sacar más provecho a esta tecnología (ver enlaces al final).


XPath en Java

Para el ejemplo aquí expuesto se han utilizado los IDE's JBuilder 2006 y NetBeans 5, con JSDK v1.5.

La primera operación a realizar es obtener el documento XML:


DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document XMLDoc = factory.newDocumentBuilder().parse(new InputSource(new
FileInputStream("c:\\demoXML.xml")));


A continuación, especificar que se trabaja en modo elemento:


Element element = XMLDoc.getDocumentElement();


El siguiente paso es crear un objeto de tipo XPath:


XPath xpath = XPathFactory.newInstance().newXPath();


Y un objeto para utilizar expresiones asociadas a dicho objeto:


XPathExpression exp;


A continuación se crean las expresiones, compilándolas de la siguiente manera:


exp = xpath.compile("/libro/titulo/text()");


Por último, para obtener el texto del elemento, se utilizaría la siguiente sentencia:


System.out.println((String) exp.evaluate(element, XPathConstants.STRING));


Por supuesto, todo ello encerrado en un try/catch, para capturar y controlar las excepciones.

El siguiente código muestra todo lo explicado:



import java.io.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;


public class DemoXPath {
public DemoXPath() {
}

public static void main(String[] args) {
DemoXPath demoxpath = new DemoXPath();

try {
XPath xpath = XPathFactory.newInstance().newXPath();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document XMLDoc = factory.newDocumentBuilder().parse(new InputSource(new
FileInputStream("c:\\demoXML.xml")));

Element element = XMLDoc.getDocumentElement();
XPathExpression exp;

exp = xpath.compile("/libro/titulo/text()");
System.out.println("1.-" + (String) exp.evaluate(element, XPathConstants.STRING));

exp = xpath.compile("//fecha/text()");
System.out.println("2.-" + (String) exp.evaluate(element, XPathConstants.STRING));

exp = xpath.compile("/libro/capitulo[@num=\"1\"]//parrafo/text()");
System.out.println("3.-" + (String) exp.evaluate(element, XPathConstants.STRING));

exp = xpath.compile("//capitulo[@num=\"1\"]/parrafo[@num=\"2\"]/text()");
System.out.println("4.-" + (String) exp.evaluate(element, XPathConstants.STRING));

exp = xpath.compile("//parrafo[@num=\"3\"]/text()");
System.out.println("5.-" + (String) exp.evaluate(element, XPathConstants.STRING));

exp = xpath.compile("/libro/capitulo[@num=\"2\"]//parrafo[@num=\"3\"]/enlace/@url");
System.out.println("6.-" + (String) exp.evaluate(element, XPathConstants.STRING));

exp = xpath.compile("/libro/capitulo[@num=\"2\"]//parrafo[@num=\"3\"]/enlace/text()");
System.out.println("7.-" + (String) exp.evaluate(element, XPathConstants.STRING));

}
catch (Exception ex) {
System.out.println("Error: " + ex.toString());
}
}

}



El resultado obtenido sería el siguiente:



1.-Neraclem
2.-8 de Octubre de 2006
3.-
Julian creyo despertar de un extrano sueno cuando abrio sus pesados ojos.

4.-
El aturdimiento entorpecia sus movimientos, y no se atrevio a ponerse de pie.

5.-
Giro lentamente 360 grados, asombrado por la majestuosidad de aquella magnifica e impresionante biblioteca de miles de libros ancestrales, que descansaban en no menos majestuosas estanterias.

6.-http://rafinguer.blogspot.com
7.-Tecnologia



El ejemplo visto se ha basado en la lectura del XML a partir de un fichero guardado en el disco. Si se quisiera tratar el documento XML desde una URL (como un servlet o un web service), la variación estaría en la obtención del documento XML, concretamente, en el objeto Document:


Document XMLDoc=factory.newDocumentBuilder().parse(new InputSource(new URL(uri).openStream()));



Espero que este artículo os sea de gran utilidad.


ENLACES:


XPath desde la W3C
API XPath
Artículo de Sun Microsystems
Artículo XPath en castellano
Tutorial de XPath en castellano
Otro tutorial en castellano