INTRODUCCIÓN A XPATH
Los
ejemplos de este tutorial están hechos con el siguiente
entorno de desarrollo:
-
Jboss Eclipse
IDE Milestone 5. -
JDK 1.5
visto a lo largo de estos últimos años
como XML se
ha ido imponiendo poco a poco, como un lenguaje válido para
intercambio de datos, debido entre otras cosas a su sencillez y
flexibilidad. También hemos visto aparecer gran cantidad de
estándares, herramientas, interfaces, librerías,
etc…,
todas ellas relacionadas con éste metalenguaje. Os
propongo en este tutorial dar a conocer un poco, otro
estándar
surgido alrededor de todo este mogollón y una
librería
que lo implementa.
XPath no es más que un lenguaje que nos permite buscar
información dentro de un XML, navegar entre etiquetas y
atributos de una manera relativamente sencilla, etc… , en definitiva,
algo que nos hará la vida más fácil a
la hora de
tratar con documentos XML. XPath es uno de los elementos principales
del estándar XSLT del W3C: http://www.w3.org/TR/xpath
XPath incluye:
- Una
sintáxis para definir las partes de un documento XML. - Un conjunto
de expresiones para seleccionar partes de un documento XML. - Un conjunto
de funciones estándar para tratamiento de cadenas, fechas,
valores numéricos, etc….
Alguno
quizá se esté preguntando todavía:
¿Pero para que sirve esto?
Lo mejor, es un ejemplo:
Supongamos que tenemos un documento XML de este tipo:
<libros> <libro> <autor>Soren Kierkegaard</autor> <titulo>Fear and Trembling</titulo> <precio>50.0</precio> </libro> <libro> <autor>Miguel de Unamuno</autor> <titulo>Niebla</titulo> <precio>40.0</precio> </libro> <libro> <autor>Miguel de Unamuno</autor> <titulo>La tía tula</titulo> <precio>23.0</precio> </libro> <libro> <autor>George Orwell</autor> <titulo>1984</titulo> <precio>20.0</precio> </libro> </libros>
Ahora, imaginad las siguientes preguntas:
- ¿
Qué libros son de Miguel de Unamuno? - ¿
Qué libros tienen un precio menor a 30 euros ? - ¿
Hay algún libro que tenga como parte del título
la palabra «Fear» ?
Seguro
que se os ocurren
muchas más, pero la pregunta es,
¿cómo lo
hacemos? Probablemente, nos recorreríamos todo el documento
mediante algun parser XML y buscaríamos cuales de ellos
cumplen
las condiciones. Si hiciesemos la analogía con una consulta
SQL en una tabla de base de datos, hacer esto sería como
hacer un SELECT * FROM LIBROS y posteriormente recorrer todos los
registros para ver cuales son aquellos que cumplen las condiciones
(poco eficiente me atrevería a decir). Pero, ¿no
hay algo entonces que lo haga por nosotros? la
respuesta es fácil: XPath.
Nota: No debemos confundir no obstante
XPath con XQuery, y no explico nada más porque lo
dejaré para tutoriales posteriores, aunque ya os digo que
XQuery es a XML lo que SQL a tablas de base de datos, y
la confusión puede venir debido a que XQuery se
apoya en XPath.
ENTRANDO EN MATERIA
Vamos a preparar primero lo necesario para empezar. Primero nos
crearemos un nuevo proyecto dentro de eclipse que llamaremos XPATH:
Después
necesitaremos alguna librería java que nos implemente todo este
mogollón, me voy a google y busco «xpath + java».
El primer resultado de la búsqueda nos remite al api de Java 5: javax.xml.xpath.
Pensaba haceros los ejemplos con la solución de apache (dentro
de xalan) que ya he utilizado con éxito, pero probemos la otra
(así aprendemos todos).
Vamos a escribir primero una clasecita de utilidades para facilitarnos
el trabajo. La llamamos UtilidadesXML: (esta os la regalo)
package autentia.tutoriales.xml; import java.io.StringWriter; import java.net.URL; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; public class UtilidadesXML { /** * Este método busca un fichero de tipo XML en el classpath crea un objeto * de tipo org.w3c.dom.Document. * @param fichero: El nombre del fichero a procesar. * @return * @throws Exception */ public static Document File2Document(String fichero) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); ClassLoader loader=(UtilidadesXML.class).getClassLoader(); URL urlfichero=loader.getResource(fichero); Document XMLDoc=factory.newDocumentBuilder().parse(new InputSource(urlfichero.openStream())); return XMLDoc; } /** * Este método convierte un objeto de tipo org.w3c.dom.Node a String * @param nodo * @return * @throws Exception */ public static String Node2String (Node nodo) throws Exception { StringWriter sw = new StringWriter(); StreamResult sR=new StreamResult(sw); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.ENCODING, “UTF-8″); transformer.setOutputProperty(OutputKeys.INDENT, “yes”); transformer.transform(new DOMSource(nodo),sR); return sw.toString(); } /** * Este método convierte un objeto de tipo org.w3c.dom.NodeList a String * Este método solo sirve para pintar los resultados. * @param nodo * @return * @throws Exception */ public static String Nodes2String (NodeList nodes) throws Exception { StringBuffer lista = new StringBuffer(); for(int i=0;iTEXTO * @param n * @return */ public static String getTexto (Node n) { NodeList nl = n.getChildNodes(); Node act=null; for (int i=0; i < nl.getLength(); i++) { act = nl.item(i); if (act == null) return null; if ((act.getNodeType() == Node.CDATA_SECTION_NODE)||(act.getNodeType() == Node.TEXT_NODE)) return act.getNodeValue(); } return “”; } /** * Devuelve el valor del atributo “nombre” de un nodo * @param nombre * @param nodo * @return */ public static String dameAtributoNodo(String nombre, Node nodo) { NamedNodeMap mapa = nodo.getAttributes(); String valor = null; if(mapa!=null) { Node nodoAt = mapa.getNamedItem(nombre); if(nodoAt!=null) valor = nodoAt.getNodeValue(); } return valor; } }
Ahora nos crearemos otra clase de utilidades que denominaremos
UtilidadesXPath, que nos servirá de base para nuestros ejemplos:
Nos creamos un XML como el que pusimos de ejemplo (el de los libros) y
lo colocamos en el classpath (directamente sobre src para que lo copie
a bin) y le llamamos libros.xml:
Empecemos con una pequeña prueba para comprobar que nos
funcionan algunos métodos de la clase UtilidadesXML (vamos a
leer el fichero libros.xml y lo vamos a imprimir en la consola):
package autentia.tutoriales.xml.xpath; import org.w3c.dom.Document; import autentia.tutoriales.xml.UtilidadesXML; public class UtilidadesXPath { public static void main(String[] args) { try { Document doc = UtilidadesXML.File2Document(“libros.xml”); System.out.println(UtilidadesXML.Node2String(doc.getDocumentElement())); } catch (Exception e) { e.printStackTrace(); } } }
Ejecutamos y mostramos la consola:
Empecemos a usar XPath. Primero vamos a recordar las preguntas que nos hicimos:
- ¿
Qué libros son de Miguel de Unamuno? - ¿
Qué libros tienen un precio menor a 30 euros ? - ¿
Hay algún libro que tenga como parte del título
la palabra "Fear" ?
Traduzcamos a expresiones XPath:
- /libros/libro[autor="Miguel de Unamuno"]
- /libros/libro[precio < 30.0]
- /libros/libro[contains(titulo,"Fear")]
Nota: Mi
intención no es explicar exhaustivamente todas las posibilidades
de las expresiones, operadores y funciones de XPath, sino hacer
aparecer en el lector el deseo de aprenderlas al contemplar
lo que facilita el trabajo.
Usemos las expresiones:
¿
Qué libros son de Miguel de Unamuno?:
public static void main(String[] args) { try { Document doc = UtilidadesXML.File2Document(“libros.xml”); XPath xpath = XPathFactory.newInstance().newXPath(); String expression = “/libros/libro[autor=\”Miguel de Unamuno\”]”; NodeList nodes = (NodeList) xpath.evaluate(expression, doc.getDocumentElement(), XPathConstants.NODESET); System.out.println(UtilidadesXML.Nodes2String(nodes)); } catch (Exception e) { e.printStackTrace(); } }
Ejecutamos y mostramos la consola:
¿
Qué libros tienen un precio menor a 30 euros ?
public static void main(String[] args) { try { Document doc = UtilidadesXML.File2Document(“libros.xml”); XPath xpath = XPathFactory.newInstance().newXPath(); String expression = “/libros/libro[precio < 30.0]”; NodeList nodes = (NodeList) xpath.evaluate(expression, doc.getDocumentElement(), XPathConstants.NODESET); System.out.println(UtilidadesXML.Nodes2String(nodes)); } catch (Exception e) { e.printStackTrace(); } }
Ejecutamos y mostramos la consola:
Hay algún libro que tenga como parte del título
la palabra "Fear" ?
public static void main(String[] args) { try { Document doc = UtilidadesXML.File2Document(“libros.xml”); XPath xpath = XPathFactory.newInstance().newXPath(); String expression = “/libros/libro[contains(titulo,\”Fear\”)]”; NodeList nodes = (NodeList) xpath.evaluate(expression, doc.getDocumentElement(), XPathConstants.NODESET); System.out.println(UtilidadesXML.Nodes2String(nodes)); } catch (Exception e) { e.printStackTrace(); } }
Ejecutamos y mostramos la consola:
Creo que con esto es suficiente para hacernos una idea de lo que se puede hacer con XPath.
Nos hemos dejado muchos operadores por usar, no hemos buscado en los
atributos, no hemos usado "axes", pero eso lo dejo para la inquietud
del lector, yo ya me lo sé.
Si necesitas que te echemos una mano, pues ya sabes, a eso nos dedicamos en Autentia.
Gracias por la informacion muy detallado y exacto, lo que buscaba.
MUY WENAS,
EXCELENTE EXPLICACION.
¿COMO SERÍA LA BUSQUEDA MEDIANTE ATRIBUTOS CON ID POR EJEMPLO?. ESTOY TENIENDO PROBLEMAS CON ELLO.
UNA AYUDA POR FAVOR.
SALUDOS
Gracias por el tutorial, me ayudara en la implementacion de un Cliente WS …
Hola,
¿Seria posible juntar dos extracciones de Xpath en una misma celda? y tres partes o más ? y cada una de esas partes se podrían separar con una coma «,» ?
estoy intentando obtener ese resultado pero no encuentro la forma
Ejemplo:
extracción 1 coche
extracción 2 BMV
quiero que en 1 celda aparezca : Coche , BMV
Como se escribiria ese Xpath?
Buenos dias, excelente tutorial. Sería posible algún ejemplo mostrando la transformación de un parametro xml (viene en texto plano) transformado a imagen y como mostrarla en el informe ?
Gracias