Tutorial de XPath
Versión: 1.0, Enero, 2001

Autor: Victor Manuel Rivas Santos
Web: http://wwwdi.ujaen.es/~vrivas, Mail: vrivas.at.ujaen.es

(C) GeNeura Team
Web: http://www.geneura.org, Mail: tutti.at.geneura.ugr.es

1. Introducción

Qué es y para qué sirve

Todo el procesamiento realizado con un fichero XML está basado en la posibilidad de direccionar o acceder a cada una de las partes que lo componen, de modo que podamos tratar cada uno de los elementos de forma diferenciada.

El tratamiento del fichero XML comienza por la localización del mismo a lo largo del conjunto de documentos existentes en el mundo. Para llevar a cabo esta localización de forma unívoca, se utilizan los URI (Unifom Resource Identifiers), de los cuales los URL (Unifom Resource Locators) son sin duda los más conocidos.

Una vez localizado el documento XML, la forma de seleccionar información dentro de él es mediante el uso de XPath, que es la abreviación de lo que se conoce como XML Path Language. Con XPath podremos seleccionar y hacer referencia a texto, elementos, atributos y cualquier otra información contenida dentro de un fichero XML.

XPath en sí es un lenguaje sofisticado y complejo, pero distinto de los lenguajes procedurales que solemos usar (C, C++, Basic, Java...). Además, como casi todo en el mundo de XML, aún está en estado de desarrollo, por lo que no es fácil encontrar herramientas que incorporen todas sus funcionalidades.

XPath es a su vez la base sobre la que se han especificado nuevas herramientas que aprovehcar para el tratamiento de documentos XML. Herramientas tales como XPointer, XLink y XQL (el lenguaje que maneja los documentos XML como si de una base de datos se tratase), que también están en estado de desarrollo, pero que sin duda cambiarán el modo en que actualmente concebimos la navegación por la Web. Así, XPath sirve para decir cómo debe procesar una hoja de estilo el contenido de una página XML, pero también para poder poner enlaces o cargar en un navegador zonas determinadas de una página XML, en vez de toda la página.

2. El modelo de datos de XPath

Construcción del Árbol de Nodos

Un documento XML es procesado por un analizador (o parser) construyendo un árbol de nodos. Este árbol comienza con un elemento raíz, que se diversifica a lo largo de los elementos que cuelgan de él y acaba en nodos hoja, que contienen solo texto, comentarios, intrucciones de proceso o incluso que están vacíos y solo tienen atributos

La forma en que XPath selecciona partes del documento XML se basa precisamente en la representación arbórea que se genera del documento. De hecho, los "operadores" de que consta este lenguaje nos recordarán la terminología que se utiliza a la hora de hablar de árboles en informática: raíz, hijo, ancestro, descendiente, etc...

Un caso especial de nodo son los nodos atributo. Un nodo puede tener tantos atributos como desee, y para cada uno se le creará un nodo atributo. No obstante, dichos nodos atributo NO se consideran como hijos suyos, sino más bien como etiquetas añadidas al nodo elemento.

A continuación se muestra un ejemplo de cómo se convierte en árbol un documento XML. Este mismo ejemplo será usado a lo largo de todo el tutorial. En primer lugar se muestra el documento XML y a continuación el árbol que genera.

Página XML
:

<libro>

<titulo>Dos por tres calles</titulo>

<autor>Josefa Santos</autor>

<capitulo num="1">

La primera calle

<parrafo>

Era una sombría noche del mes de agosto...

</parrafo>

<parrafo destacar="si">

Ella, inocente cual

<enlace href="http://www.enlace.es">mariposa</enlace>

que surca el cielo en busca de libaciones...

</parrafo>

</capitulo>

<capitulo num="2" public="si">

La segunda calle

<parrafo>Era una obscura noche del mes de septiembre...</parrafo>

<parrafo>

Ella, inocente cual

<enlace href="http://www.abejilla.es">abejilla</enlace>

que surca el viento en busca del néctar de las flores...

</parrafo>

</capitulo>

<apendice num="a" public="si">

La tercera calle

<parrafo>

Era una densa noche del mes de diciembre...

</parrafo>

<parrafo>

Ella, cándida cual

<enlace href="http://www.pajarillo.es">abejilla</enlace>

que surca el espacio en busca de bichejos para comer...

</parrafo>

</apendice>

</libro>

Árbol generado
:

/

|

+---libro

|

+---titulo

| |

| +---(texto)Dos por tres calles

|

+---autor

| |

| +---(texto)Josefa Santos

|

+---capitulo [num=1]

| |

| +---(texto)La primera calle

| |

| +---parrafo

| | |

| | +---(texto)Era una sombría noche ...

| +---parrafo

| |

| +---(texto)Ella, cual inocente mariposa...

|

+---capitulo [num=2]

|

+---(texto)La segunda calle

|

+---parrafo

| |

| +---(texto)Era una obscura noche ...

+---parrafo

|

+---(texto)Ella, cual inocente abeja...

Tipos de Nodos

Existen distintos tipos de nodos en un árbol generado a partir de un documento XML, a saber: raíz, elemento, atributo, texto, comentario e instrucción de procesamiento (respectivamente; root, elements, attribute, text, comment y processing instruction).

Nodo Raíz

Se identifica por /. No se debe confundir el nodo raíz con el elemento raíz del documento. Así, si el documento XML de nuestro ejemplo tiene por elemento raíz a libro, éste será el primer nodo que cuelgue del nodo raíz del árbol, el cual es: /.

Insisto: / hace referencia al nodo raíz del árbol, pero no al elemento raíz del documento XML, por más que un documento XML solo pueda tener un elemento raíz. De hecho, podemos afirmar que el nodo raíz del árbol contiene al elemento raíz del documento.

Nodo Elemento

Cualquier elemento de un documento XML se convierte en un nodo elemento dentro del árbol. Cada elemento tiene su nodo padre. El nodo padre de cualquier elemento es, a su vez, un elemento, excepto el elemento raíz, cuyo padre es el nodo raíz. Los nodos elemento tienen a su vez hijos, que son: nodos elemento, nodos texto, nodos comentario y nodos de intrucciones de proceso. Los nodos elemento también tienen propiedades tales como su nombre, sus atributos e información sobre los "espacios de nombre" que tiene activos.

Cualquier elemento de un documento XML se convierte en un nodo elemento dentro del árbol. Cada elemento tiene su nodo padre. El nodo padre de cualquier elemento es, a su vez, un elemento, excepto el elemento raíz, cuyo padre es el nodo raíz. Los nodos elemento tienen a su vez hijos, que son: nodos elemento, nodos texto, nodos comentario y nodos de intrucciones de proceso. Los nodos elemento también tienen propiedades tales como su nombre, sus atributos e información sobre los "espacios de nombre" que tiene activos.

Una propiedad interesante de los nodos elemento es que pueden tener identificadores únicos (para ello deben ir acompañados de un DTD que especifique dicho atributotoma valores únicos), esto permite referenciar a dichos elementos de una forma mucho más directa.

Nodos texto

Por texto vamos a hacer refrenecia a todos los caracteres del documento que no está marcados con alguna etiqueta. Un nodo texto no tiene hijos, es decir, los distintos caracteres que lo forman no se consideran hijos suyos.

Nodos atributo

Como ya hemos indicado, los nodo atributo no son tanto hijos del nodo elemento que los contiene como etiquetas añadidas a dicho nodo elemento. Cada nodo atributo consta de un nombre, un valor (que es siempre una cadena) y un posible "espacio de nombres".

Aquellos atributos que tienen por valor el valor por defecto asignado en el DTD se tratarán como si el valor se le hubiese al escribir el documento XML. Al contrario, no se crea nodo para atributos no especificados en el documento XML, y con la propiedad #IMPLIED definida en su DTD. Tampoco se crean nodos atributo para las deficiones de los espacios de nombre. Todo esto es normal si tenemos en cuenta que no es necesario tener un DTD para procesar un documento XML.

Nodos comentario y de instrucciones de proceso

Aparte de los nodos indicados, en el árbol también se generan nodos para cada nodo con comentarios y con intrucciones de proceso. Al contenido de estos nodos se puede acceder con la propiedad string-value.

3. Los Location Paths

Conceptos Básicos

Expresiones

Una "instrucción" en lenguaje XPath se denomina una expresión. Y pongo entre comillas lo de "instrucción" porque XPath es un lenguaje declarativo, por lo que las intrucciones no son exactamente como estamos acostumbrados a ver.

Dichas expresiones pueden incluir cierta variedad de operaciones sobre distintos tipos de operanods. En nuestro caso nos vamos a ceñir a dos tipos de oprandos: llamadas a funciones y location paths (algo así como caminos de localización).

Un location path es la más importante de los tipos de expresiones que se pueden especificar en notación XPath. La sintaxis de un location path es simliar a la usada a la hora de describir los directorios que forman una unidad de disco en Unix o Linux (y similar a la de los sistemas basados en MS-DOS y Windows, si exceptuamos la unidad de disco -C:, A:- y que las barras usadas son / en vez de las típicas \ de estos últimos sistemas operativos).

Sin embargo, solo la sintaxis es lo similar al sistema de archivos. El significado de las expresiones es totalmente diferente.

Por ejemplo, el siguiente path en Unix:

/usr/home/pepeillo/docs

hace referencia a un único directorio: docs el cual cuelga de el conjunto de directorios /usr/home/pepeillo.

Sin embargo, la siguiente expresión en XPath:

/libro/capitulo/parrafo

hace referencia a TODOS los elementos parrafo que cuelguen directamente de CUALQUIER elemento capitulo que cuelgue de CUALQUIER elemento libro que, finalmente, cuelguen del nodo raíz, /. Bueno, el último "TODOS" sobra dado que solo puede haber un elemento raíz: libro.

Hay que tener en cuenta que una expresión en XPath no devuelve los elementos que cumplen con el patrón que representa dicha expresión, sino que devuelve una referencia a dichos elementos; es decir, una expresión XPath nos devuelve una lista de apuntadores a los elementos que encajan en el patrón. Dicha lista puede estar vacía o contener uno o más nodos.

Nodo contexto

Un location path siempre tiene un punto de partida llamado nodo contexto. Para enterdernos es como el directorio actual si nos referimos a un sistema de ficheros. Así, si estando en Unix, damos una orden ls obtendremos los ficheros que existen en el directorio actual, mientras que si decimos ls /usr/bin obtendremos el listado de los ficheros existentes en el directorio /usr/bin con independencia del directorio en que estemos colocados al dar la orden.

En los location path ocurre lo mismo. A menos que se indique un camino explícito, se entenderá que el location path parte del nodo que en cada momento se esté procesando.

El concepto de "nodo contexto" es imprescindible para comprender cómo se lleva a cabo la elección de los nodos que ajustan con el patrón indicado en el location path. para explicar esto, veamos cómo actuaría un motor de evaluación de expresiones XPath al leer la siguiente expresión aplicada al documento XML que manejamos desde el principio del turtorial:

/libro/capitulo/parrafo

(Aviso: lo que viene a continuación requiere de pausada lectura, descansito para ir al frigorífico a por algo de beber y pequeño masaje en los ojos... como mínimo)

En primer lugar comienza por leer /, lo cual le dice que debe seleccionar el nodo raíz, independientemente del nodo contexto que en ese momento exista. En el momento en que el evaluador de XPath localiza el nodo raíz, éste pasa a ser el nodo contexto de dicha expresión.

Siguiendo con nuestro ejemplo, el analizador leería ahora libro, lo cual le dice que seleccione TODOS los elementos que cuelgan del nodo contexto (que atendiendo al párrafo anterior es el nodo raíz) que se llamen libro. Bueno... en este caso solo hay uno... porque (otra vez) solo puede haber un elemento raíz.

Sigamos avanzando con nuestro ejemplo. A continuación el analizador leería capitulo, lo cual le dice que seleccione TODOS los elementos que cuelgan del nodo contexto (que atendiendo al párrafo anterior es el nodo libro).

En un disco sería imposible que hubiera dos directorios con el mismo nombre colgando de un mismo directorio padre. Sin embargo, en nuestro documento XML podemos ver como hay dos elementos capitulo colgando del elemento raíz libro. Por tanto, en estos momentos hay dos elementos que encajan con el patrón /libro/capitulo.

¡Y ahora viene lo mejor! El analizador continua leyendo la expresión XPath que le hemos dado y llega a parrafo. Con ello le estamos diciendo que seleccione TODOS los elementos parrafo que cuelgan del nodo contexto...¡¡pero NO hay un nodo contexto, sino DOS!! Bueno, no pasa nada, cada uno de los nodos de ese conjunto de nodos va a tener su momento de gloria, de forma que el evaluador de expresiones lo va a recorrer uno por uno haciendo que, mientras evalúa un determinado nodo, ése sea el nodo contexto de ese momento.

En otras palabras, para localizar todos los elementos parrafo tal y como deseamos, se procesa el primer elemento capitulo y de él se extraen todos los parrafo que contenga. A continuación se pasa al próximo elemento capitulo del cual se vuelven a extraer todos los de tipo parrafo que tenga... y así sucesivamente. El resultado final es un nuevo conjunto de nodos (o para ser más precisos, conjunto de punteros a nodo) que encajan con el patrón buscado.

Predicados

Por lo poco que llevamos visto, podemos pensar que XPath es un gran mecanismo para seleccionar muchos nodos a la vez, lo cual es muy útil. ¿Pero qué pasa si solo queremos seleccionar un nodo que cumple ciertas características? ¿o más de un nodo que cumple con un patrón pero no todos los que lo cumplen, sino solo aquellos con un atributo que les hemos añadido para saber que los puede ver todo el mundo? Bueno, pues para todo esto se utilizan los predicados.

Los predicados se incluyen dentro de un location path utilizando los corchetes, como poe ejemplo:

/libro/capitulo[@num="1"]/parrafo

Mediante el anterior location path estamos indicando que se escojan todos los elementos parrafo de todos los elementos capitulo que tengan un atributo llamado num al cual se le haya asignado el valor "1" (recordemos que en XML todos los atributos tienen valores de tipo cadena).

Atendiendo a nuestro ejemplo, solo hay un capitulo que cumpla dichas condiciones, por lo que solo los elementos parrado que él contiene serán seleccionados.

Posteriormente, veremos qué tipo de cosas se pueden poner en un predicado.

Axes(¿Hachas?¿Ejes?)

La verdad es que no sabía muy bien como traducir el término axes que significa algo así como cercenar o podar, aunque también hacha. Lo voy a traducir por hacha que seguro que después de un par de párrafos se convierte en algo normal.

Digamos que un hacha incluída en un location path realiza una selección de nodos dentro del árbol (o mejor dicho, dentro del subárbol que cuelga del nodo o conjunto de nodos contexto) de acuerdo con algún patrón.¡¡Bingo!!, cada vez que hemos usado la barra / (salvo para denominar el nodo raíz) estábamos usando un hacha.

Veamos las distintas hachas que podemos usar para recorrer el arbolito.

Cómo hago los ejemplos

Antes de empezar, será bueno decir cómo vamos a ver el resultado de los ejemplos que se citana a continuación. En primer lugar podríamos usar alguna herramienta de visualización de expresiones XPath. Dichas herramientas permiten especificarles un fichero XML, generan el árbol asociado al mismo y posteriormente nos dejan introducir expresiones XPath y las evalúan dando el resultado. Una de ellas es la realizada (en Java) por Khun Yee Fung, denominada XPath VisualTool. El sitio original para bajársela es http://www.wireoptional.com/XML/xslt.html (está al final de la página), aunque también la puedes encontrar aquí comprimido en formato zip. Yo la he probado y no me ha convencido mucho, la verdad.

Por ello, el método que voy a usar es utilizar las Extensible Stylesheet Language Transformations (o XSLT), cuya explicación escapa al ámbito de éste tutorial, pero de las que se puede hallar más información en http://geneura.ugr.es/~jmerelo/XSLT.

Para poder usarlas, en primer lugar, necesitamos un analizador de XSLT como Xalan o XP y por supuesto uno de XML, como Xerces o XT. Si tenemos instalado Cocoon, entonces ya tenemos tanto Xalan como Xerces.

Lo siguiente es llamar a Xalan indicándole qué fichero .xml debe tomar, qué fichero .xsl debe aplicar y qué fichero .html (en nuestro caso) debe generar. Yo me he creado un ficherito bash que lo he llamado xsl para reducir el proceso. Tiene la siguiente pinta:

#! /bin/bash /usr/local/jdk1.2.2/bin/java -cp /usr/local/xalan-j_1_2_2/xalan.jar:/usr/local/xalan-j_1_2_2/xerces.jar \ org.apache.xalan.xslt.Process -in $1 -xsl $2 -out $3

Hay que tener en cuenta que posiblemente el ejecutable java esté en otro directorio, e igual ocurrirá con Xerces y Xalan. Esto me permite hacer llamadas como la siguiente:

xsl ejemplo.xml ejemplo.xsl ejemplo.html

El fichero .xml que vamos a usar es el anteriormente indicado (el de los libros, capítulos, etc), al cual vamos a llamar ejemplo.xml. El fichero .xsl tiene el siguiente formato:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!--

==========================================================================

| File..........: ejemplos.xsl

| Author........: Victor Manuel Rivas Santos, vrivas@ujaen.es

| (C) GeNeura Team, 2000

| http://www.geneura.org, todos@geneura.ugr.es

| Date..........: 26-Dec-2000

| Description...: XSL for tutorials

==========================================================================

-->

<xsl:stylesheet version="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="libro">

<HTML>

<HEAD>

<TITLE>Ejemplos en XPath</TITLE>

</HEAD>

<BODY>

<H1>Resultados:</H1>

<PRE>

<xsl:apply-templates select="/libro/capitulo/text()"/>

</PRE>

</BODY>

</HTML>

</xsl:template>

</xsl:stylesheet>

Lo que vamos a hacer cada vez que veamos un ejemplo es substituir la parte en rojo por el ejemplo (dejándole el /text() final para que muestre el contenido de los elementos seleccionados). Una vez substituido, lo grabamos como ejemplo.xsl, y llamamos al ficherillo xsl dándole los ficheros según:

xsl ejemplo.xml ejemplo.xsl ejemplo.html

Y a continuación visualizamos en cualquier navegador la página ejemplo.html. Fácil, ¿no?

En la sección 4. Ejerccios, puedes acceder a una página web que te permitirá hacer ejercicios de XPath mucho más fácilmente.

Child

Es el hacha utilizada por defecto. Se corresponde con la barra, / (aunque tiene una forma más larga que es: /child::).

Seleccionar todos los titulo de un libro:
/libro/titulo

Attribute

Se corresponde con el signo de la arroba, @ (o en su forma larga que es: attribute::).

Mediante este operador podemos seleccionar aquellos nodos atributos que deseemos, especialmente indicando el nombre. Nótese, que para seleccionar los nodos elemento que muestran dichos atributos, lo que se ha de usar es un predicado (como se ha indicado ya anteriormente)

Para seleccionar el atributo num que posean los elementos capitulo
/libro/capitulo/@num

Para seleccionar todos los elementos hijo de los capitulo que posean el atributo public
/libro/capitulo[@public]/*

Para seleccionar todos los elementos hijo de parrafo cuyo atributo destacar sea igual a "si".
/libro/titulo/parrafo[@destacar="si"]

Descendant

Se especifica poniendo una doble barra: // (en su forma larga: descendant::).

Sirve para seleccionar TODOS los nodos que descendiendan del conjunto de nodos contexto. Es decir, no solo los hijos de los nodos contexto, sino también los hijos de los hijos, y los hijos de estos, etc.

Para seleccionar todos los parrafo de un libro:
/libro//parrafo

Para seleccionar todos los descendientes de parrafo que tienen un atributo href.
//parrafo//*[@href]

Para ver el valor del atributo href del caso anterior:.
//parrafo//*[@href]/@href

Para seleccionar todos los elementos descendientes de capitulo
/libro/titulo//*

Self

Se especifica mediante el ..

Es muy útil pues sirve para seleccionar el nodo contexto. Por ejemplo, supongamos que deseamos seleccionar todos los parrafo descendientes del nodo contexto. No podemos escribir //parrafo, dado que seleccionaría todos los descendientes del nodo raíz. Por ello, la forma correcta es: .//parrafo

Parent

Al igual que en los sistemas de ficheros, se utilizan los dos puntos para identificarlo: ..

El comportamiento de este hacha es un poco extraño al principio dado que realiza un paso hacia atrás en el árbol de nodos

Seleccionar todos los nodos que tienen algún hijo de tipo parrafo:
//parrafo/..

Seleccionar todos los nodos capitulo que tienen algún hijo de tipo parrafo:
//parrafo/../../capitulo

O bien:
//capitulo/parrafo/..

Ancestor

De todas las hachas que podemos usar, esta es la única que no tiene ninguna forma de abreviación, sino que hay que ponerla como ancestor::

Ancestor es a parent lo que descendant es a child. Es decir, devuelve todos los elementos de los cuales el nodo contexto es descendiente.

Seleccionar todos los elementos que tienen entre sus descendientes algún parrafo
//ancestor::parrafo/ancestor::*

Seleccionar todos los capitulos que tienen entre sus descendientes alguno con el atributo href
//*[@href]/ancestor::capitulo

Nodos Test

Los nodos test son algo así como funciones que nos van a ayudar a restringir un poquito lo que nos devuelve una expresión XPath. Ya hemos visto algunos de estos nodos test en los ejemplos anteriores. Pero ahora vamos a verlos con más detenimiento.

En primer lugar hemos de distinguir entre las hachas de contenido (content axis) de las que no lo son. Las hachas de contenio son básicamente todas las vistas excepto attibute y namespace (es como attribute pero para obtener el "espacio de nombres" asociado al elemento).

Nodos test aplicables a TODAS las hachas

*

El nodo test * devuelve todos los nodos de tipo prinicpal (es decir, elemento, atributo o espacio de nombres), pero no nodos de texto, comentarios, y de instrucciones de proceso.

Seleccionar todos los nodos principales descendientes de los parrafo:
//parrafo/*

node()

El nodo test nod() devuelve todos los nodos de todos los tipos.

Seleccionar todos los nodos descendientes de los parrafo:
//parrafo/node()

Nodos Test aplicables SOLO a la hachas de contenido

text()

Cualquier nodo de tipo texto.

Seleccionar el texto de todos los nodos parrafo:
//parrafo/text()

Seleccionar TODO el texto que cuelga de todos los nodos parrafo:
//parrafo//text()

comment()

Cualquier nodo de tipo comentario.

processing-instruction()

Cualquier nodo de tipo de instrucción de proceso, independientemente de su destino.

processing-instruction( destino )

Cualquier nodo de tipo de instrucción de proceso relativo al destino especificado.

processing-instruction( cursor )

Cualquier nodo de tipo de instrucción de proceso con el destino cursor

Predicados

Ya hemos hablado algo de los predicados en párrafos anteriores. Básicamente, un predicado permite restringir el conjunto de nodos seleccionados por un hacha a aquellos que cumplen cierta condición. Dicha condición es una expresión XPath y se expecifíca entre corchetes.

Seleccionar todos los elementos que tengan el atributo num:
//*[@num]

Seleccionar todos los capitulo que tengan un parrafo que tenga algún elemento con atributo href:
//capitulo[parrafo/*[@href]]

Los predicados se pueden suceder uno a otro haciendo el efecto de la operación AND. Como en el siguiente ejemplo.

Seleccionar todos los capitulo que tengan un parrafo que tenga algún elemento con atributo href y que ellos mismos (los capitulo tengan el atributo public a valor si:
//capitulo[parrafo/*[@href]][@public='si']

Aunque también se puede hacer uso del operador and encenrrando entre paréntesis los distintos predicados logicos.

Ejemplo similar al anterior
//capitulo[ (parrafo/*[@href]) and (@public='si')]

También se puede hacer uso de la operación or.

Esiste otro tipo de operacion or que utiliza la barra vertical: | separando no dos predicados, sino dos expresiones XPath.

Seleccionar todos los capitulo que tengan un parrafo que tenga algún elemento con atributo href o todos los apendice:
//capitulo[parrafo/*[@href]]|//apendice

Por último, también podemos especificar con not la negación de alguna de las negaciones del predicado.

Seleccionar todos los capitulo que no tengan el atributo public
//capitulo[not(@public)]

Predicados con funciones de cardinalidad

Existen, por último, ciertas funciones que nos van a servir para restringir el conjunto de nodos devueltos en una expresión XPath basándose en la posición del elemento devuelto. Tales funciones son: position(), last() e id().

position()

Seleccionar el segundo capitulo:
//capitulo[position()=2]

Esta función se puede simular poniendo simplemente el número entre corchetes.

Mismo ejemplo anterior: seleccionar el segundo capitulo:
//capitulo[2]

last()

Seleccionar el último capitulo:
//capitulo[last()]

Seleccionar todos los capitulo menos el último:
//capitulo[not(position()=last())]

Estas funciones se pueden usar con expresiones matemáticas, como en el siguiente ejemplo.

Seleccionar el penúltimo capitulo:
//capitulo[last()-1]

id()

Seleccionar los parrafo hijos del elemento con id="capitulo_1":
id( "capitulo_1" )/parrafo

Hay que tener en cuenta un detalle. Solo se podrá usar en aquellos ficheros XML que sean validados por un DTD en el que se especifique que el atributo id es único.

4. Ejercicios

Hemos creado una dirección web en la que puedes hacer ejercicios de XPath: ejercicios_xpath.html

El fichero XML sobre el que tratan los ejercicios es: ejercicios_xpath_xml.html. Deberías tenerlo a la vista para poder hacer los ejercicios.

5. Referencias

Libros

Para realizar este tutorial me he basado en el siguiente libro:

- Charles F. Goldbarg, Paul Prescod. The XML handbook. Ed. Prentice Hall PTR, 2000. (ISBN: 0-13-014714-1) (En Inglés)

El siguiente es también bastante bueno:

- Elliotte Rusty Harold. XML Bible. Ed. Hungry Minds, Inc, 1999. (ISBN: 0764532367) (En Inglés)

Direcciones WEB

Las siguientes direcciones también pueden ser de gran ayuda:

* Utilidades para XPath en el sitio de XMLSoftware: http://www.xmlsoftware.com/xpath/

* Recomendaciones del W3C sobre XPath (en Septiembre de 1999): http://www.w3.org/TR/xpath

* Un par de páginas (en PDF) con una Referencia Rápida sobre XSLT y XPath. La versión original está en http://www.mulberrytech.com/quickref/, aunque también te lo puedes descargar desde aquí en formato pdf o en formato postscript.

* Un tutorial en plan presentación con diapositivas: http://www.brics.dk/~amoeller/XML/

* Ejemplos de expresiones en XPath : http://www.zvon.org/HTMLonly/XPathTutorial/General/examples.html

* Tutorial de XPath : Sitio original: http://www.zvon.org/. Aquí lo tienes comprimido en formato zip.

* Una utilidad para visulizar el resultado de expresiones XPath. Realizada en Java por Khun Yee Fung. El sitio original para bajársela es http://www.wireoptional.com/XML/xslt.html (está al final de la página), aunque también la puedes encontrar aquí comprimido en formato zip.

* Se puede practicar también con las expresiones XPath utlizando analizadores de XML y XSL, como por ejemplo: Xerces y Xalan, del Apache Project (http://xml.apache.org/). O con XT y XP, del sitio http://www.jclark.com/xml/. Las copias locales son las que siguen.

* Xerces (inclue su firma PGP) y Xalan (inclue su firma PGP).

* XT y XP. También existe una versión directamente ejecutable para Windows 95, xt-win32.zip, que se ejecuta según el patrón xt source stylesheet result name=value....