XPath
Sumario
Expresións XPath
XPath (XML Path) é unha linguaxe para acceder ás distintas partes dun documento XML. Empregando XPath podemos seleccionar e facer referencia a texto, elementos, atributos e calquera outra información contida dentro dun documento XML. Non é unha linguaxe XML; ten a súa propia sintaxe.
Por exemplo, no documento XML anterior poderíamos empregar a seguinte expresión para obter o enderezo do cliente: /venda/cliente/enderezo
Existen tres versións de XPath. As tres son recomendacións (versións finais) desenvolvidas polo W3C:
- XPath 1.0 (novembro 1999) emprega DOM XML e aínda segue a ser con diferenza a versión máis empregada
- XPath 2.0 (decembro 2010) emprega o modelo XDM
- XPath 3.0 emprega XDM 3.0.
Imos centrarnos en XPath 1.0, e nos exemplos para avaliar as expresións XPath empregouse XPath Visualizer Tool e XPathBuilder, pero hai outras ferramentas que podedes usar, algunhas tamén en liña con exemplos precargados para facer probas (XPath Expression Testbed e Zvon XLab.
Exemplo
Por exemplo, o seguinte documento XML:
<?xml version="1.0" encoding="utf-8"?>
<venda>
<cliente cod="CL09384">
<nome>Uxío Fuentes Neira</nome>
<enderezo>Rúa Europa 24, 3ºA</enderezo>
</cliente>
<produtos>
<produto cod="LACT093">
<descrición>Leite enteira envase 1L</descrición>
</produto>
<produto cod="LACT012">
<descrición>Margarina vexetal tarrina 250g</descrición>
</produto>
</produtos>
<importe>16,34€</importe>
</venda>
Preséntase do seguinte xeito empregando o modelo DOM XML:
Nunha árbore DOM XML, o documento XML represéntase empregando nodos. Tódolos compoñentes dun documento XML son nodos. Parar crear a árbore debe terse en conta a or-de na que aparecen os elementos dentro do documento XML; por exemplo, o produto de código "LACT093" é anterior ao de código "LACT012". Non é relevante a orde dos atributos dentro dun elemento.
Cargando o arquivo anterior (preme "Alt" para abrir os menús), podemos avaliar a expresión anterior e obteremos o seguinte resultado:
En XPath 1.0, as expresións poden empregar e devolver os seguintes tipos de datos:
- Números en punto flotante.
- Valores booleanos (verdadeiro ou falso).
- Cadeas de carácteres codificadas en Unicode.
- Conxuntos de nodos, que poden conter cero, un ou máis nodos.
Tipos de nodos no modelo DOM XML
No modelo DOM XML, unha árbore correspondente a un documento XML está composta por nodos. Estes nodos poden ser de distintos tipos. Os principais nodos son:
- Document (Documento). Representa ao documento XML enteiro. Ten un único fillo de tipo elemento (o nodo raíz).
- Element (Elemento). Representa un elemento dun documento XML. Poden ter identificadores únicos (pódese especificar no documento de validación) para acceder a eles de xeito directo.
- Attr (Atributo). Representa un atributo dun elemento. Aínda que se lles denomina nodos, na estrutura de árbore considérase aos atributos como unha información engadida aos nodos "Elemento" e non como fillos deles.
- Text (Texto). Representa ao texto dun elemento. Contén todos os carácteres que non están dentro dalgunha etiqueta.
Tamén existen outros tipos de nodos, coma:
- Comment (Comentario).
- CDATASection (Sección CData).
- ProcessingInstruction (Instrución de Procesamento).
- Entity (Entidade).
As relacións entre os nodos dunha árbore DOM XML son as seguintes:
- Soamente existe un nodo raíz, de tipo "Elemento".
- Un nodo "Elemento" pode ter ou non nodos fillos. Un nodo "Elemento" sen fillos é un nodo folla. Os nodos dos outros tipos nunca teñen fillos.
- Tódolos nodos a excepción do raíz teñen un e soamente un nodo pai. Tampouco teñen pai os nodos de tipo "Atributo", que como xa dixemos cólganse na árbore do nodo "Elemento" que os contén, pero non se consideran fillos deste.
- Chámanse nodos irmáns a aqueles nodos "Elemento" que teñen o mesmo pai.
Expresións XPath
XPath (XML Path) é unha linguaxe para acceder ás distintas partes dun documento XML. Empregando XPath podemos seleccionar e facer referencia a texto, elementos, atributos e calquera outra información contida dentro dun documento XML. Non é unha linguaxe XML; ten a súa propia sintaxe.
Por exemplo, no documento XML anterior poderíamos empregar a seguinte expresión para obter o enderezo do cliente:
/venda/cliente/enderezo
Rutas de localización
O tipo máis común de expresión en XPath é a ruta de localización. Unha ruta de localización permite a selección dun conxunto de nodos, partindo dun nodo contexto no que se avaliará a expresión. O resultado de avaliar unha ruta de localización é sempre un conxunto de nodos (de distintos tipos, non soamente nodos "Elemento"). As rutas de localización poden ser absolutas ou relativas:
- Se empregamos XPath como parte doutra linguaxe como XSLT, podemos avaliar expresións cuxo contexto sexa un conxunto de nodos dun documento XML (ruta relativa). Es-tas rutas non comezan cunha barra "/". Por exemplo, poderíamos avaliar unha expresión tendo como contexto:
<produto cod="LACT012">
<descrición>Margarina vexetal tarrina 250g</descrición>
</produto>
De xeito que a expresión "produto/descrición" obteña o nodo "descrición" do produto.
- Se empregamos XPath sobre un documento XML, as expresións comezarán cunha barra "/" (ruta absoluta), o que indica que o contexto da expresión é o nodo "Documento" (o documento XML enteiro).
As expresións XPath tamén empregan a barra "/" para separar as diferentes partes das que se compoñen. Estas partes chámanse pasos de localización. Cada un dos pasos de localización vai refinando a procura de datos a través dos nodos da árbore.
Por exemplo, a ruta de localización "/venda/cliente/enderezo" componse de tres pasos de localización. O primeiro fai referencia ao nodo raíz "venda", que colga do nodo do-cumento "/"; o seguinte fai referencia ao nodo "cliente" que é fillo de "venda"; e o mesmo para o nodo "enderezo".
Pasos de localización
Os pasos de localización (location steps) son cada un dos elementos dunha ruta de localización. Co resultado obtido de avaliar un paso de localización, obtense o contexto do seguinte paso de localización. Constan dun eixo (axis), un test de nodo (node test) e opcionalmente dun predicado.
A sintaxe é a seguinte:
eixo::test-nodo[predicado]
Rutas de localización
Son as expresións que permiten seleccionar un nodo o un conxunto de nodos, indicando cal é a súa localización exacta (relativa ou absoluta)
Esta expresión absoluta devolveranos os nomes dos comerciales:
Esta expresión relativa devolverá todos os nodos que se chamen nome:
A seguinte táboa amosa algunhas das expresións XPath máis comúns:
Expresión | Resultado agardado | Sobre o exemplo |
---|---|---|
elemento | Elemento de nome elemento | comercial (Devolve todos os elementos do comercial) |
/elemento | Devolve o elemento ubicado na ráiz do documento | /empresa (Devolve todo o elemento empresa cos seus descendentes) |
e1/e2 | Elementos e2 que sean fillos directos de e1 | comercial/apelidos (Devolve os elementos apelidos cos seus valores) |
e1//e2 | Elmentos descendentes de e1 que se chamen e2 | empresa//nome (Devolve todos os elementos nome en todos os niveles a partir de empresa |
//elemento | Elemento de nome elemento ubicado en calquer nivl baixo a raíz do documento | //telefono (Devolve todos os elementos chamados teléfono) |
@atributo | O atributo e o seu valor de nome atributo | @matricula (Devolve todas as matrículas co seu nome e valor) |
* | Todos os elementos | |
@* | Todos os atributos | |
. | Nodo actual | |
-- | Nodo pai | |
espNom:* | Todos os nodos no espazo de nomes de prefixo espNom | pr:* |
@espNom:* | Todos os atrubitutos no espazo de nomes de prefixo espNom | @pr:* |
Eixos
Os eixos indican, con respecto ao nodo contexto, o conxunto de nodos sobre os cales se avaliará o test de nodo e o predicado se existe. Basicamente trátase de realizar un primeiro filtro de nodos da árbore para obter o resultado cos datos buscados.
Os eixos que podemos empregar en XPath 1.0 son:
- self. O propio nodo contexto.
- child. Os fillos do nodo contexto.
- parent. O pai do nodo contexto.
- ancestor. Os antepasados do nodo contexto.
- ancestor-or-self. O nodo contexto e os seus antepasados.
- descendant. Os descendentes do nodo contexto.
- descendant-or-self. O nodo contexto e os seus descendentes.
- following. Os nodos seguintes ao nodo contexto, sen descendentes.
- following-sibling. Os nodos do mesmo nivel que seguen ao nodo contexto.
- preceding. Os nodos anteriores ao nodo contexto, sen antepasados.
- preceding-sibling. Os nodos do mesmo nivel que preceden ao nodo contexto.
- attribute. Os nodos atributo do nodo contexto.
- namespace. Os nodos de espazo de nomes do nodo contexto.
IMPORTANTE. Se non se pon ningún, o eixo por defecto é child. Tamén se pode empregar o símbolo "@" no lugar do eixo attribute. Porén, as seguintes expresións son equivalentes: /venda/cliente/@cod e /child::venda/child::cliente/attribute::cod
INTERESANTE. Podes ver algúns exemplos para entender o funcionamento dos eixos
Tests de nodo
O test de nodo serve para, unha vez identificado un conxunto de nodos co eixo adecuado, especificar exactamente qué nodos dese conxunto son os que queremos. Os test de nodo poden ser:
- nome_dun_nodo. Selecciona todos os nodos co nome indicado.
- *. Selecciona todos os elementos e atributos.
- node(). Selecciona todos os nodos (de calquera tipo).
- text(). Selecciona o contido textual do nodo ou nodos de.
- data(). Selecciona o contido textual (valor do atributo)
- comment(). Selecciona os nodos de comentario.
- processing-instructions(). Selecciona os nodos de procesamento de instrucións.
Por exemplo, se quixéramos obter o conxunto de tódolos atributos do documento, poderiamos facer:
//descendant-or-self::node()/@*
Isto é, seleccionamos tódolos nodos do documento, e despois quedámonos cos seus atributos. Se quixeramos soamente os atributo de nome "cod", poderiamos facer: //descendant-or-self::node()/@cod
E calquera das seguintes formas é válida para obter os textos das descricións dos produtos: /venda/produtos/produto/descrición/text() /descendant-or-self::node()/descrición/text()
Obsérvese que non é o mesmo obter como resultado un conxunto de nodos sen filtrar ("/descendant-or-self::node()/descrición"):
Que indicar que queremos obter soamente os nodos de tipo "Texto" ("/descendant-or-self::node()/descrición/text()"):
Debido ao seu frecuente uso, existen abreviaturas para algunhas rutas de localización:
- "//" equivale a "descendant-or-self::node()"
- "." equivale a "self::node()"
- ".." equivale a "parent::node()"
Isto é, tamén poderíamos ter escrito a anterior expresión coma:
//descrición/text()
A partir de Xpath 2.0 pódese empregar tamén string() para devolver a información textual de nodos (elementos) e atributos.
Predicados
Os predicados son condicións opcionais nun paso de localización, e introdúcense entre cor-chetes despois do test de nodo. Axúdannos a axustar a busca no conxunto de nodos que nos interesan.
Cada predicado pode conter unha ruta de localización relativa ao nodo actual. Unha forma habitual que se emprega nos predicados fai uso dunha característica especial de XPath: calquera conxunto de nodos non baleiro é tratado de forma booleana como "verdadeiro", mentres que a un conxunto de nodos baleiro asígnaselle o valor booleano "falso". Desta forma, na expresión:
//produto[child::descrición]
O predicado filtra os produtos obtendo soamente aqueles que teñen un nodo elemento fillo de nome "descrición". O mesmo da seguinte forma abreviada:
//produto[descrición]
Tamén podemos poñer condicións ao resultado obtido pola ruta de localización indicada no predicado. Por exemplo, a seguinte expresión obtería os nodos "produto" cun atributo "cod" con valor "LACT012":
//produto[@cod="LACT012"]
E para obter os clientes cun nome concreto:
//cliente[nome/text()="Uxío Fuentes Neira"]
Un mesmo paso de localización pode conter cero, un ou varios predicados; neste último caso, poranse un a continuación doutro, cadanseu cos seus propios corchetes:
//produto[descrición][@cod="LACT012"]
Operadores
Nos predicados, ademais do operador "=", podemos utilizar outros operadores e funcións XPath para filtrar o conxunto de nodos en función do valor dalgunha estrutura do documen-to. XPath 1.0 define os seguintes operadores que se poden empregar nas expresións.
Operador | Tipo | Descrición | Exemplo |
---|---|---|---|
= | Booleano | Devolve verdadeiro se o valor dos dous operandos coincide, falso en caso contrario. | count(//produto) = 3 |
!= | Booleano | Devolve verdadeiro se o valor dos dous operandos non coincide, falso en caso contrario. | count(//produto) != 3 |
< | Booleano | Devolve verdadeiro se o valor do primeiro operando é menor que o valor do segundo, falso en caso contrario. | count(//produto) < 3 |
<= | Booleano | Devolve verdadeiro se o valor do primeiro operando é menor ou igual que o valor do segundo, falso en caso contrario. | count(//produto) <= 3 |
> | Booleano | Devolve verdadeiro se o valor do primeiro operando é maior que o valor do segundo, falso en caso contrario. | count(//produto) > 3 |
>= | Booleano | Devolve verdadeiro se o valor do primeiro operando é maior ou igual que o valor do segundo, falso en caso contrario. | count(//produto) >= 3 |
and | Booleano | Devolve verdadeiro se o valor de ambos operandos é verdadeiro, falso en caso contrario. | count(//produto) > 3 and count(//produto) < 7 |
or | Booleano | Devolve falso se o valor de ambos operandos é falso, verdadeiro en caso contrario. | count(//produto) < 3 or count(//produto) > 7 |
+ | Numérico | Devolve a suma dos operandos. | count(//produto) + 1 |
- | Numérico | Devolve a resta dos operandos. | count(//produto) - 1 |
* | Numérico | Devolve o produto dos operandos. | count(//produto) * 2 |
div | Numérico | Devolve a división dos operandos. | count(//produto) div 2 |
mod | Numérico | Devolve o resto da división enteira dos operandos. | count(//produto) mod 2 |
| | Conxunto de nodos | Une os operandos, que deben ser conxuntos de nodos, nun novo conxunto de nodos. | //produto | //cliente |
Funcións
XPath 3.1 define as seguintes funcións que se poden empregar nas expresións.
Función | Parámetros | Valor devolto | Descrición | Exemplo |
---|---|---|---|---|
round() | Numérico | Redondea o enteiro máis próximo | round(4.27)=4 | |
abs() | Numérico | Valor absoluto | abs (-4)= 4 | |
floor() | Numérico | Redondeo inferior | floor (4.3) = 4 | |
ceiling() | Numérico | Redondeo superior | celing (4.3) = 5 |
Función | Parámetros | Valor devolto | Descrición | Exemplo |
---|---|---|---|---|
substring() | Devolve a subcadea | |||
starts-with() | Deolve true se a cadea comeza co valor | |||
ends-with() | Deolve true se a cadea finaliza co valor | |||
contains() | Deolve true se a cadea contén o valor | |||
normalize-space() | Espazos normalizados | |||
translate() | Reemplaza caracteres nunha cadea | |||
string-length() | Lonxitue da cadea | |||
upper-case() | Cadea a maiúsculas | |||
lower-case() | Cadea a minúsculas |
Función | Parámetros | Valor devolto | Descrición | Exemplo |
---|---|---|---|---|
position() = n | Devolve o nodo que se atopa na posición n | |||
elemento(n) | Deovolve o nodo que se atopa na posición n | |||
last() | Devolve o último nodo dun conxunto | |||
last()-1 | Devolve o último menos i nodo dun conxunto |
Función | Parámetros | Valor devolto | Descrición | Exemplo |
---|---|---|---|---|
name() | Devolve o nome do nodo actual | |||
text() | Devolve o contido textual do nodo | |||
root() | Devolve o elemento raíz | |||
node() | Nodos descendentes do actual | |||
comment() | Devolve os comentarios do nodo | |||
processing-instruction() | Devolve as instruccións de procesamento | |||
exists() | Devolve si existe o nodo ou non | |||
empty() | Devikver se o nodo está baleiro ou non |
Función | Parámetros | Valor devolto | Descrición | Exemplo |
---|---|---|---|---|
count() | Conxunto de nodos | Numérico | Devolve o número de nodos do conxunto de nodos. | count(//produto) |
avg() | Conxunto de nodos | Numérico | Media do contido dos nodos | avg(//salario) |
max() | Conxunto de nodos | Numérico | Valor máximo do contido dos nodos | max(//salario) |
min() | Conxunto de nodos | Numérico | Valor mínimo do contido dos nodos | min(//salario) |
sum() | Conxunto de nodos | Numérico | Valor da suma de todos os valores do contido dos nodos | sum(//salario) |
IMPORTANTE Na W3C Recommendation tes detalladas todas as funcións existentes. No titorial de w3schools tes exemplos de uso de moitas delas
A función position() emprégase habitualmente no predicado para seleccionar o nodo correspondente a unha posición determinada dentro do conxunto de nodos do contexto. Isto pódese facer tamén de forma abreviada indicando a posición directamente no predicado, de tal xeito que ámbalas dúas expresións seguintes son equivalentes:
//produto[position()=2] é equivalente a //produto[2]
Outras expresións
Aínda que a ruta de localización é o tipo máis común de expresión en XPath, podemos empregar os operadores e funcións anteriores para crear diversos tipos de expresións (moitas delas non devolven un conxunto de nodos, e polo tanto non funcionarán en XPath Visualizer). Por exemplo:
- Contar o número de produtos dunha venda (devolve un número):
count(//produto)
- Comprobar se o número de produtos dunha venda cumple ou non certas condicións (devolve un valor booleano):
count(//produto) > 3 and count(//produto) < 7
- Obter os datos dun produto e os do cliente (devolve un conxunto de nodos):
//produto[2] | //cliente
- Comprobar o valor do código dun produto determinado (devolve un valor booleano):
//produto[2]/@cod = "LACT012"
- Comprobar se existe algún produto cun código determinado (devolve un valor booleano):
//produto/@cod = "LACT012"
- Obter o importe da venda, cambiando a coma por un punto (devolve unha cadea de texto):
substring(translate(/venda/importe,",","."),1,5)
XPath e espazos de nomes
Cando nun documento XML se definen espazos de nomes, empregaremos os prefixos respectivos onde corresponda dentro das expresións XPath.
Por exemplo:
<?xml version="1.0" encoding="utf-8"?>
<venda xmlns:pr="http://www.atendadepaco.com/espazosdenomes/produtos/">
<pr:produtos>
<pr:produto>
<pr:cod>LACT02330993</pr:cod>
<pr:descrición>Leite enteira envase 1L</pr:descrición>
</pr:produto>
<pr:produto>
<pr:cod>LACT00493112</pr:cod>
<pr:descrición>Margarina vexetal tarrina 250g</pr:descrición>
</pr:produto>
</pr:produtos>
<importe_total>16,34€</importe_total>
</venda>
A expresión correcta para obter o conxunto de nodos correspondente a todos os produtos será: //pr:produto
Cómo debemos facer cando temos un documento no que estea definido un espazo de nomes por defecto? Por exemplo:
<?xml version="1.0" encoding="utf-8"?>
<venda xmlns="http://www.atendadepaco.com/espazosdenomes/vendas/" xmlns:pr="http://www.atendadepaco.com/espazosdenomes/produtos/">
<pr:produtos>
<pr:produto>
<pr:cod>LACT02330993</pr:cod>
<pr:descrición>Leite enteira envase 1L</pr:descrición>
</pr:produto>
<pr:produto>
<pr:cod>LACT00493112</pr:cod>
<pr:descrición>Margarina vexetal tarrina 250g</pr:descrición>
</pr:produto>
</pr:produtos>
<importe_total>16,34€</importe_total>
</venda>
Especificaremos un prefixo para facer referencia ao espazo de nomes por defecto dentro das expresións XPath. Isto é, cando escribimos o nome dun elemento sen indicar un prefixo, como: /venda
XPath busca os elementos "venda" que non estean asociados a ningún espazo de nomes. E por tanto, non obtemos ningún resultado ("venda" está asociado ao espazo de nomes por defecto).
Necesitamos especificar dalgún xeito o prefixo que imos a empregar na expresión XPath para facer referencia ao espazo de nomes por defecto.
Cambiar o espazo de nomes en procesadores XPath
Todos os procesadores XPath permiten especificalo dalgún xeito, e tamén a maioría de aplicacións para avaliar expresións.
Por exemplo, en XPath Visualizer podemos despregar a sección namespaces and prefixes e modificar o prefixo a empregar para o espazo de nomes por defecto.
Ademais tamén podemos marcar un espazo de nomes por defecto dentro dunha expresión, de xeito que o empregue dentro da expresión se non empregamos ningún.
En XPath Builder, podemos ver pero non modificar o prefixo que asigna automaticamente a aplicación ao espazo de nomes por defecto. Teremos que empregar ese prefixo nas nosas expresións.
Resumo de XPath
- Linguaxe de rutas para XML (path language). Utiliza:
- unha sintaxe path like para identificar e navegar entre os nodos dun documento XML
- un analizador que crea unha árbore de nodos a partir dun documento XML
- expresións para seleccionar osnodos dun documento XML (seguindo unha serie de pasos ou ruta)
Referencias
- Tradución ao castelán da Recomendación do W3C "XML Path Language (XPath) Version 1.0".
- Lenguajes de marcas y sistemas de gestión de información (2.ª edición ampliada). Moreno Pérez, Juan Carlos · González Ruiz, Sergio Luis. ISBN: 9788491711759
- Transformación de documentos XML. Expresións XPath. Margarita Pin Rodríguez, Víctor M. Lourido Estévez. Traballo realizado durante unha licenza de formación retribuída pola Consellería de Cultura, Educación e Ordenación Universitaria. Licenza Creative Commons BY-NC-SA (recoñecemento - non comercial - compartir igual).