Consultas en XPath

Las consultas en XPath permiten acceder y extraer información específica de un documento XML de manera eficiente. Este lenguaje ofrece una amplia variedad de funciones, como operaciones numéricas, selección de nodos, manejo de posiciones y mucho más. Además, es posible crear consultas anidadas para resolver casos más complejos. ¡Es hora de empezar!

Fichero de ejemplo

Los ejemplos que presentaré a continuación se ejecutarán utilizando la herramienta gratuita BaseX, y para ello emplearé el archivo XML de ejemplo introducido en artículos anteriores. Esta herramienta es ideal para explorar y practicar con consultas en XPath y XQuery de manera sencilla.

Localización

El direccionamiento, o localización, en un documento XML consiste en definir una ruta de nodos que permita acceder a las partes específicas de su contenido. Este enfoque facilita seleccionar únicamente los elementos o atributos que resulten relevantes.

Existen dos tipos principales de direccionamiento:

  • Absoluto: Siempre parte desde el nodo raíz del documento, especificando la ruta completa.
  • Relativo: No requiere indicar el nodo raíz y permite trabajar con rutas basadas en el contexto actual.

Para ello, se utilizan las siguientes expresiones:

ExpresiónDefinición
nodoElemento que tiene por nombre nodo
/nodoSe encuentra en la raíz del documento
nodo1/nodo2Nodo2 es hijo directo nodo1
nodo1//nodo2Nodo 2 es hijo de nodo1, pero puede haber otros intermedios
//nodoNodo puede estar en cualquier lugar debajo de nodo raiz
@atributoAtributo que tiene por nombre atributo
*Cualquier elemento
@*Cualquier atributo
.Nodo actual
..Nodo padre

Ejemplos

Para mostrar todo el contenido del archivo XML de la biblioteca, basta con escribir el nombre del nodo raíz en la consulta. Este método permite visualizar todos los datos almacenados en el documento. Por ejemplo:

biblioteca

En este ejemplo de consultas en XPath, se utiliza una localización absoluta para acceder a los elementos específicos dentro del nodo raíz biblioteca. La consulta selecciona todos los libros y, dentro de ellos, sus respectivos autores:

/biblioteca/libro/autor

Se puede obtener exactamente el mismo resultado utilizando una localización relativa. Esto resulta útil cuando no es necesario partir explícitamente del nodo raíz. Por ejemplo:

//libro/autor
//autor

Ambas consultas buscan directamente todos los nodos autor, ya sea a partir de los nodos libro o desde cualquier parte del documento XML. Estas expresiones relativas simplifican las consultas al no requerir que se especifique la ruta completa desde el nodo raíz.

Si se desea obtener el ID, que es un atributo del nodo libro (diferente a los elementos hijos de este nodo), se utiliza la siguiente expresión:

/biblioteca/libro/@id

Esta consulta accede específicamente al atributo id de cada nodo libro dentro del nodo raíz biblioteca. Al ejecutarla en BaseX, se devolverán únicamente los valores de los atributos id, sin incluir el contenido de los elementos libro.

Otra opción es mostrar todos los atributos presentes en todos los nodos del documento XML. Para ello, se utiliza la siguiente expresión:

//@*

Esta consulta selecciona todos los atributos (@*) de cualquier nodo (//) dentro del documento. Al ejecutarla en BaseX, se devolverá una lista con todos los atributos y sus valores, independientemente del nodo al que pertenezcan.

Otra opción muy útil es mostrar los resultados sin las etiquetas correspondientes, obteniendo únicamente el contenido de los nodos. Para esto, se utiliza la función text(), que extrae el valor del nodo sin incluir las etiquetas. Por ejemplo, si queremos mostrar únicamente los nombres de los autores, la consulta sería:

/biblioteca/libro/autor/text()

Al ejecutar esta consulta en BaseX, se obtendrán los valores de los nodos autor (es decir, los nombres de los autores) sin incluir las etiquetas <autor>. Esto es especialmente útil cuando solo se necesita el texto contenido en los nodos, sin la estructura XML.

Filtrar

También se puede filtrar el conjunto de nodos o la propia información utilizando condiciones. El filtro se debe especificar siempre entre corchetes y podemos utilizar los siguientes operadores y funciones (se muestran las más relevantes):

Operadores

OperadorDescripción
andY
orO
notNo es
=Igual
!=Diferente
<Menor que
>Mayor que
<=Menor o igual que
>=Mayor o igual que
toRango
+Suma
Resta
*Multiplicación
divDivisión
modResto de la división
|Unión de resultados

En este ejemplo vamos a mostrar tanto el título como el precio usando el operador de unión:

/biblioteca/libro/(titulo|precio)

Otro ejemplo utilizando operadores es mostrar los títulos de los libros cuyo año sea anterior a 2023. Para lograrlo, se utiliza la siguiente consulta:

/biblioteca/libro[fecha<2023]/titulo

En esta expresión, se aplica un filtro que selecciona únicamente los nodos libro cuyo valor en el nodo fecha sea menor a 2023. Luego, se accede al nodo titulo para obtener el nombre de esos libros. Al ejecutarla en BaseX, se mostrarán los títulos de los libros publicados antes de 2023.

Funciones de cadena

FunciónDescripciónEjemplo
starts-with()Cadena comienzastarts-with(‘XML’, ‘X’) = true
ends-with()Cadena terminaends-with(‘XML’, ‘X’) = false
substring()Extracción de cadenasubstring(‘MiguelTroyano’, 1, 6) = Miguel
contains()La cadena contienecontains(‘XML’, ‘ML’) = true
normalize-space()Espacios normalizadosnormalize-space(‘ Doc XML ‘) = ‘Doc XML’
string-length()Contar caracteresstring-length(‘MiguelTroyano’) = 13
upper-case()Convertir en minusculasupper-case(‘xml’) = ‘XML’
lower-case()Convertir en mayúsculaslower-case(‘XML’) = ‘xml’
translate()Sustitución de cadenatranslate(‘Doc XML’, ‘XML’, ‘XPAth’) = ‘Doc XPAth’

Funciones numéricas

FunciónDescripciónEjemplo
round()Redondeoround(3.88) = 3
abs()Valor absolutoabs(-8) = 8
floor()Redondeo hacia abajofloor(8.3) = 8
ceilingRedondeo hacia arribaceiling(8.3) = 9

Funciones de posición de elementos

FunciónDescripción
position() = nNodo que se encuentra en la posición ‘n’
elemento[n]Nodo en la posición ‘n’ de los que se llaman nodo
last()El último nodo de un conjunto
last() – iEl último menos i nodos

En este ejemplo, se utiliza una condición de posición para mostrar el título del libro que ocupa la tercera posición en el nodo biblioteca. La consulta es la siguiente:

/biblioteca/libro[position()=3]/titulo

Esta expresión selecciona el nodo libro que está en la tercera posición y, dentro de él, accede al nodo titulo. Al ejecutarla en BaseX, se devolverá únicamente el título del tercer libro presente en el documento XML.

No es necesario limitarse a una sola posición, también es posible seleccionar un rango de posiciones. En este ejemplo, se seleccionan los títulos de los libros que ocupan las posiciones 2 y 3 dentro del nodo biblioteca:

/biblioteca/libro[position()=2 to 3]/titulo

Esta consulta utiliza el rango 2 to 3 para filtrar los nodos libro comprendidos entre la segunda y la tercera posición. Luego, accede al nodo titulo para mostrar los títulos correspondientes. Al ejecutarla en BaseX, se devolverán los nombres de los libros ubicados en esas posiciones específicas.

Funciones de nodos

FunciónDescripción
comment()Comentarios del nodo
empty()Si el nodo está vacío o no
exists()Si existe el nodo o no
name()Nombre del nodo actual
node()Nodos descendientes del actual
processing-instruction()Instrucciones de procesamiento
root()Elemento raíz
text()Contenido textual del nodo

En este ejemplo, se muestra únicamente el nombre de los nodos descendientes del nodo actual. Para ello, se utiliza la siguiente consulta:

/biblioteca/libro/node()/name()

Esta consulta selecciona todos los nodos hijos del nodo libro utilizando node(), y luego aplica la función name() para obtener el nombre de cada nodo. Al ejecutarla en BaseX, se devolverá una lista con los nombres de los nodos descendientes dentro de cada libro, como titulo, autor, precio, entre otros.

Funciones de agregación

FunciónDescripción
avg()Media
count()Contar
max()Valor máximo
min()Valor mínimo
sum()Suma

En este ejemplo, se realiza la suma de los precios de todos los libros dentro del nodo biblioteca. La consulta es la siguiente:

sum(/biblioteca/libro/precio/text())

La función sum() toma como entrada el conjunto de valores extraídos de los nodos precio mediante la expresión /biblioteca/libro/precio/text(). Al ejecutarla en BaseX, se calculará y devolverá la suma total de los precios de todos los libros presentes en el documento XML.

Consultas combinadas

Con todo lo anterior, es posible crear consultas mucho más complejas, como las consultas anidadas. Estas permiten resolver casos avanzados combinando varias condiciones dentro de una misma expresión. En el siguiente ejemplo, se busca primero el autor del libro titulado «Datos en la Web» y, posteriormente, se listan todos los libros escritos por ese autor:

/biblioteca/libro[autor=/biblioteca/libro[titulo="Datos en la Web"]/autor/text()]/titulo

La consulta funciona de la siguiente manera:

  1. La expresión interna /biblioteca/libro[titulo="Datos en la Web"]/autor/text() obtiene el nombre del autor del libro con el título especificado.
  2. Luego, en la expresión externa, se filtran todos los libros cuyos nodos autor coincidan con el resultado obtenido en el paso anterior.
  3. Finalmente, se seleccionan los títulos de esos libros utilizando /titulo.

Al ejecutar esta consulta en BaseX, se mostrará una lista con los títulos de todos los libros escritos por el autor de «Datos en la Web».

Escribir un comentario