XPath és un llenguatge que em permet navegar pels diferents nodes del meu document XML.
XPath utilitza expressions per a navegar dins la informació emmagatzemada en documents XML.
A més, disposa d'una sèrie de funcions que ens permeten fer diferents operacions amb les dades.

Expressions XPath

Una expressió XPath defineix un patró per a poder seleccionar un node o un conjunt de nodes d'un document XML.

Per a mostrar el funcionament de XPATH utilitzarem el següent document XML

Nom Fitxer: univers.xml

<?xml version="1.0" ?>
<planets>
    <planet id="3">
        <name>A Place</name>
    <value>3000</value>
        <xcood>-125.18</xcood>
        <ycood>274.88</ycood>
        <faction>LA</faction>
        <factionChange id="8">
            <date>3040-01-01</date>
            <faction>FC</faction>
        </factionChange>
        <factionChange id="12">
            <date>3057-12-01</date>
            <faction>ARDC</faction>
        </factionChange>
        <factionChange id="16">
            <date>3067-04-24</date>
            <faction>LA</faction>
        </factionChange>
    </planet>
    <planet id="21">
        <name>Abadan</name>
    <value>3200</value>
        <xcood>-70.94</xcood>
        <ycood>-96.76</ycood>
        <faction>FWL</faction>
    </planet>
    <planet id="27">
        <name>Abagnar</name>
    <value>2800</value>
        <xcood>383.64</xcood>
        <ycood>317.65</ycood>
        <faction>DC</faction>
    </planet>
    <planet id="33">
        <name>Abbadiyah</name>
    <value>4300</value>
        <xcood>-320.78</xcood>
        <ycood>248.8</ycood>
        <faction>LA</faction>
        <factionChange id="38">
            <date>3040-01-01</date>
            <faction>FC</faction>
        </factionChange>
        <factionChange id="42">
            <date>3057-09-18</date>
            <faction>LA</faction>
        </factionChange>
    </planet>
    <planet id="47">
        <name>Abbeville</name>
    <value>3300</value>
        <xcood>611.32</xcood>
        <ycood>-40.16</ycood>
        <faction>FS</faction>
        <factionChange id="52">
            <date>3040-01-01</date>
            <faction>FC</faction>
        </factionChange>
        <factionChange id="56">
            <date>3067-01-01</date>
            <faction>FS</faction>
        </factionChange>
    </planet>
    <planet id="61">
        <name>Abejorral</name>
    <value>3900</value>
        <xcood>-302.01</xcood>
        <ycood>128.57</ycood>
        <faction>LA</faction>
        <factionChange id="66">
            <date>3040-01-01</date>
            <faction>FC</faction>
        </factionChange>
        <factionChange id="70">
            <date>3057-09-18</date>
            <faction>LA</faction>
        </factionChange>
    </planet>
    <planet id="75">
        <name>Aberystwyth</name>
    <value>2500</value>
        <xcood>-434.75</xcood>
        <ycood>59.2</ycood>
        <faction>LA</faction>
        <factionChange id="80">
            <date>3040-01-01</date>
            <faction>FC</faction>
        </factionChange>
        <factionChange id="84">
            <date>3057-09-18</date>
            <faction>LA</faction>
        </factionChange>
    </planet>
    <planet id="89">
        <name>Abiy Adi</name>
    <value>4500</value>
        <xcood>352.6</xcood>
        <ycood>317.39</ycood>
        <faction>DC</faction>
        <spectralClass>G</spectralClass>
        <subtype>2</subtype>
        <luminosity>V</luminosity>
        <sysPos>3</sysPos>
        <gravity>1.2</gravity>
        <pressure>3</pressure>
        <temperature>45</temperature>
        <climate>4</climate>
        <percentWater>18</percentWater>
        <hpg>b</hpg>
        <lifeform>0</lifeform>
        <satellite>Amarigna</satellite>
        <socioIndustrial>C-B-C-C-C</socioIndustrial>
        <landmass>Tsechi (Tigray)</landmass>
        <landmass>Simien</landmass>
        <landmass>Adwa</landmass>
        <desc>Abiy Adi is a largely desert world in the Pesht Military District. The industy on the planet uses so much of the planet's indigenous water that the locals depend on imported water.</desc>
    </planet>
    <planet id="112">
        <name>Abramkovo</name>
    <value>3400</value>
        <xcood>-333.82</xcood>
        <ycood>-28.95</ycood>
        <faction>LA</faction>
        <factionChange id="117">
            <date>3040-01-01</date>
            <faction>FC</faction>
        </factionChange>
        <factionChange id="121">
            <date>3057-09-18</date>
            <faction>LA</faction>
        </factionChange>
    </planet>
</planets>

Llenguatge de consultes XPATH

  1. XPath és un llenguatge que em permet navegar pels diferents nodes del meu document XML. Utilitzem XQuery conjuntament amb XPath per a realitzar les consultes a la nostra base de dades XML.
  2. XPath és una sintaxis per a definir parts d'un document XML
  3. Utilitza expressions per a navegar dins la informació emmagatzemada en documents XML
  4. XPath disposa de més de 100 funcions amb diferents funcionalitats.

Com fer consultes a un fitxer XML

Per a fer una consulta XML ho podem fer de dues formes diferents:

  1. Tenint en compte la posició del node.
  2. Amb independència de la posició del node.

Tenint en compte la posició del node

Si la nostra consulta fa referència a un node que està en una determinada posició, hem d'indicar tot el camí fins arribar a aquest node. Utilitzarem la / per a indicar que volem partir del node inicial. També utilitzem la / per a separar cada un dels nodes.

Per exemple , si vull obtenir el nom dels planetes utilitzarem l'expressió:

/planets/planet/name

planets és el node arrel del document XML. Dins d'aquest node arrel volem accedir al node planet i finalment al node name . Per tant, la consulta ens retornaria tots els noms dels planetes del document XML anterior.

Si enlloc del planeta volem obtenir els satèl·lits de cada un dels planetes, utilitzarem l'expressió

/planets/planet/satellite

Cas pràctic

Utiltizarem el llenguatge Ruby per a executar les consultes utilitzant XPath. En aquest cas utilitzarem la classe REXML. Un primer exemple seria:

#!/usr/bin/ruby -w

require 'rexml/document'
include REXML

xmlfile = File.new("univers.xml")
xmldoc = Document.new(xmlfile)

puts xmldoc.elements.to_a("/planets/planet/name")

Independentment de l'ubicació del node

Per a realitzar la consulta de forma independent a la ubicació del node, utilitzem //.

Així, per exemple, les dues consultes anteriors, utilitzant el nostre document XML, serien equivalents a:

//name
//satellite

Utilitzant el nostre script de Ruby:

#!/usr/bin/ruby -w

require 'rexml/document'
include REXML             # per evitar utilitzar el prefix ::REXML en tots els mètodes d'aquesta classe


xmlfile = File.new("univers.xml")
xmldoc = Document.new(xmlfile)

puts xmldoc.elements.to_a("//name")

Exercici

1.- Obtenir tots els valors de l'etiqueta "faction" de l'arxiu univers.xml

2.- Obtenir tots els valors de l'etiqueta "faction" associats a l'arxiu univers.xml que són fills de l'etiqueta planet

3.- Si cada vegada que fem una consulta, hem d'incloure en el nostre programa la lectura del fitxer, la seva conversió a XML,... la realització de consultes és una mica lenta. Per aquest motiu, es proposa crear una funció que ens retorni els resultats d'una consulta, enviant-li el nom del fitxer i la consulta a realitzar. L'execució de consultes, per tant, queda simplificada tal i com es mostra en la imatge. Cal , però , dissenyar la funció. Observeu que el nom del fitxer és opcional!!

Utilitzant la classe XPATH

El mètode elements, utilitzat en els exercicis anteriors és un bon sistema per a introduir-se al món de les consultes XPATH.

Per a poder aprofundir més, ens cal utilitzar la classe XPATH de Ruby. Anem a veure un exemple de com seria la nova funció

Llegint atributs

En un document XML, apart de la informació emmagatzemada en nodes, també disposem d'informació emmagatzemada en atributs. Per a referenciar un atribut, primer hem de referenciar el node que conté l'atribut o un antecessor del mateix. Amb el símbol @ indiquem que la referència és relativa a un atribut. Veiem un exemple:

Exercicis

4.- Obtenir l'atribut id de l'etiqueta factionChange.
5.- Obtenir tots els atributs id independentment de l'etiqueta a què pertanyen

Funcions

Amb la nova funció que acabem de definir podem ampliar les consultes aplicant funcions de XPath.

count

La funció count retorna el total de nodes retornats per una consulta XPATH. Així, per exemple, l'expressió count(//name) ens retornarà el valor 9 ja que l'etiqueta name apareix 9 vegades en el nostre document XML. Cal tenir en compte que aquesta funció només contabilitza les vegades que apareix l'etiqueta especificada. Així, per exemple, la consulta count(/planets) retornarà el valor 1, ja que l'etiqueta planets només apareix una vegada en el document XML.

text

La funció text ens permet obtenir el texte d'un node, sense la informació de les etiquetes. Cal tenir en compte que aquesta funció només funciona quan l'etiqueta sobre la que es realitza la consulta conté text. Per tant, només podrem aplicar aquesta funció en aquelles etiquetes que tinguin text

sum

Retorna la suma dels nodes especificats. Per exemple, l'expressió sum(//value) retorna la suma de tots els nodes etiquetats amb "value".

Exercicis

6.- Contabilitza el total de satèl·lits, considerant tots els planetes
7.- Retorna el nom de tots els satèlits: sense informació associada a l'etiqueta

Filtres

En una consulta XPATH podem filtrar la informació per a un o varis nodes. Podem utilitzar etiquetes o atributs per a realitzar els diferents filtres. El criteri pel qual volem filtrar la informació sempre s'ha d'incloure entre clàudators.

Exemples

/planets/planet[name='Abbadiyah']

La consulta anterior em retorna la informació del planeta que tingui per nom 'Abbadiyah'. Observem que per a fer la comparació utilitzem el símbol = . Un altre exemple de consulta seria:

//planet[name='Abagnar']

L'expressió anterior em retorna el node planet de tots aquells planetes que el seu nom sigui 'Abagnar'. L'ubicació del filtre de cerca és important, ja que els resultats, segons on posem la condició, seran diferents. Així, una forma més correcte d'expressar l'expressió XPATH és: obtenir la informació del node planet que tingui un node fill (no descendent) de nom name associat al valor 'Abagnar'.

Per a determinar la importància de l'ubicació de la condició utilitzem un parell d'exemples més.

//planets[name='Abagnar']
//planets[//name='Abagnar']

En el primer exemple, l'expressió es correspon a: obtenir la informació del node planets que tingui un node fill (no descendent) de nom name i associat al valor 'Abagnar'. L'expressió no ens retornarà cap resultat, ja que planets no té cap node fill amb el nom de name; tots els nodes fills són planet.

La segona expressió indica que es vol obtenir tota la informació del node planets que tingui algun node descendent name associat al valor 'Abagnar'. Donat que hi ha un node name dins del node planets associat al valor 'Abagnar', la segona expressió ens retornarà tota la informació del document XML: el node planets és el node arrel del document.

/planets/planet[name='Abagnar']/value

L'expressió anterior em retornarà el valor del node value associat al planeta 'Abagnar'.

Utilització operadors "." i ".."

Podem simplificar les nostres consultes utilitzant l'operador "." i ".." . Utilitzem l'operador "." per a especificar el node actual. Amb l'operador ".." es referencia al node pare.

Exemples

/planets/planet/name[.='Abbadiyah']

En l'expressió anterior , el símbol "." substitueix al node name. Podem escriure la mateixa consulta, tot i que d'una forma més llarga i probablement menys entenedora utilitzant: l'expressió:

/planets/planet[name='Abbadiyah']/name

La consulta ens retorna "Abbadiyah" sempre i quan hi hagi un planeta que tingui aquest nom. Un altre exemple de consulta utilitzant l'operador "." i ".." podria ser:

/planets/planet/factionChange/date[../faction='LA']

La consulta anterior tot i que simplificable, demostra la utilització del ".." per a obtenir la informació d'un node pare a l'element sol·licitat. Aquesta consulta equival a la consulta

/planets/planet[faction='LA']/factionChange/date

Operadors de comparació

Apart d'utilitzar = com a comparador d'igualtat, també podem utilitzar els operadors de comparació clàssics en la majoria de llenguatges:

<, > , != , = (igual valor)

Exemples

/planets/planet[xcood>100]/xcood
/planets/planet/xcood[.>100]

Les dues expressions anteriors són equivalents, però en aquest cas , en la segona expressió, s'ha utilitzat el símbol "." per a referenciar el valor del node actual.

Exercicis

8.- Obtenir la informació de tots els planetes que el seu valor (value) sigui superior a 3000. Cal retornar tota la informació del planeta
9.- Obtenir el nom de tots els planetes que el seu valor (value) sigui superior a 3000
10.- Fer un programa en Ruby que m'escrigui "Existeix" si una determinada condició XPATH retorna un o més nodes.

Operadors booleans

Podem concatenar diferents filtres, incloent cada un d'ells entre els seus respectius clàudators. Així, per exemple, per a obtenir

Així, per exemple, per a obtenir tots els noms de planetes que tenen un node value associat superior a 4000 i

/planets/planet/value[.<3000 or .>4000]

Quan es vol fer un filtre d'un node que compleix diferents condicions, cal incloure cada una de les condicions en un clàudator específic. Així, per exemple, la següent expressió

/planets/planet[value>3000][value<4000]/name

retornarà com a resultat tots els noms de planetes que el seu valor estigui comprès entre 3000 i 4000.

Exercicis

11.- Obtenir el nom de tots els planetes que les seves coordenades x estiguin entre 100 i 400 o la seva lluminositat sigui de tipus V.
12.- Obtenir la data (date) o dates de "factionChange" de tots els planetes que comencin per "Abbe".
13.- Obtenir la data (date) o dates de "factionChange" de tots els planetes que comencin per "Abbe". Cal incloure el filtre com a última expressió de la consulta.
14.- Obtenir el nom de tots els planetes que tinguin més de 2 nodes de tipus factionChange
15.- Obtenir el nom de tots els planetes que tinguin un faction fill de factionChange amb valor de LA o de DC.
16.- Obtenir l'identificador de tots els planetes que tinguin un faction fill de factionChange amb valor de LA o de DC.

Filtres amb atributs

Per a realitzar filtres també podem utilitzar els atributs. Així, per exemple, per a obtenir tota la informació del planeta amb associat a l'identificador (id) 33, utilitzarem l'expressió:

/planets/planet[@id='33']

Exercicis

17.- Obtenir la gravetat de tots els planetes que el seu identificar estigui comprès entre els valors 0 i 100, ambdós inclosos.
18.- Obtenir la informació de tots els planetes que tinguin algun node amb un atribut "id" superior a 100

Nodes segons posició

En una consulta XPATH podem filtrar per la posició del node. Així, per exemple, si una consulta retorna el nom de tots els planetes podem obtenir el planeta de la posició X, indicant aquest valor entre clàudators: de forma similar a com ho fem amb un array.


/planets/planet[1]/name    # Retorna el nom del primer planeta. Si el node planet tingués més d'una node name els retornaria tots els nodes name
/planets/planet[3]/name    # Retorna el nom del tercer planeta. Si el node planet tingués més d'una node name els retornaria tots els nodes name

En canvi, l'expressió següent és totalment diferent

/planets/planet/name[1] # Retorna el primer node name de tots els planetes

results matching ""

    No results matching ""