4.2.1.2 - Navegació
Com que la representació interna del document XML per XPath serà un arbre, es pot navegar per ell especificant camins d’una manera semblant a com es fa en els directoris dels sistemes operatius.
El més important per tenir en compte a l’hora de crear una expressió XPath és saber quin és el node en el qual està situat el procés (node de context), ja que és des d’aquest que s’avaluarà l’expressió. El node de context al principi és el node arrel però es va movent a mesura que es van avaluant les expressions, i per tant podem expressar els camins XPath de dues maneres:
-
Camins absoluts
-
Camins relatius
Els camins absoluts són camins que sempre comencen en l’arrel de l’arbre. Es poden identificar perquè el primer caràcter de l’expressió sempre serà l’arrel ”/”. No importa quin siga el node de context si es fan servir camins absoluts, perquè el resultat sempre serà el mateix.
En canvi, els camins relatius parteixen des del node en el qual estem situats.
Per exemple, es pot obtenir el node <nom> del professor de l’exemple anterior fent servir l’expressió XPath següent:
/classe/professor/nom
Podem veure com s’avalua l’expressió en l’arbre XPath en la següent figura, marcat el camí en taronja:
Observeu que el resultat d’aquesta expressió no és només el contingut de l’element sinó tot l’element <nom>.
Mai no s’ha d’oblidar que l’expressió sempre intenta aconseguir el nombre màxim de camins correctes i, per tant, no necessàriament ha de retornar només un únic valor. Per exemple, si l’expressió per avaluar és la següent:
/classe/alumnes/alumne/nom
XPath l’avaluaria intentant aconseguir tots els camins que quadren amb l’expressió, tal com podeu veure visualment en la següent figura:
i per tant els resultats són (observeu que Joan es refereix al nom del tercer alumne, no del professor):
A pesar que en els exemples anteriors sempre s’han retornat nodes finals això no necessàriament ha de ser així, ja que XPath pot retornar qualsevol tipus d’element com a resultat.
/classe/alumnes
La navegació per l’arbre no difereix massa dels altres casos:
En aquest cas el resultat no és un element simple sinó que és tot un subarbre d’elements.
Si se sap que una expressió retornarà més d'un resultat però només se’n vol un d’específic, es pot fer servir un número envoltat per claudàtors quadrats ”[ ]” per indicar quin és el que es vol aconseguir. Per retornar només el primer alumne podeu fer el següent:
/classe/alumnes/alumne[1]
que tornarà el següent:
ja que dels tres nodes disponibles com a fills de <alumnes>, només se seleccionarà el primer:
Es poden fer servir els claudàtors en qualsevol lloc de l’expressió per fer determinar quina de les branques es triarà. Per exemple, es pot obtenir només el nom del segon alumne amb una expressió com aquesta:
/classe/alumnes/alumne[2]/nom
<nom>Bernat</nom>
Sempre s’ha d’anar amb compte en escriure les expressions XPath, ja que si el camí especificat no es correspon amb un camí real dins de l’arbre no es retornarà cap resultat.
Com que en arribar al node classe no n’hi trobarà cap d’anomenat <nom>, no retornarà cap resultat, com podeu veure si seguiu l’arbre:
Obtenir els atributs d'un element
Els valors dels atributs es poden aconseguir especificant el símbol @ davant del nom de l'atribut, quan s’haja arribat a l’element que el conté:
/classe/professor/@Especialitat
S’ha de tenir en compte que a diferència del que passa amb els elements, en obtenir un atribut no tindrem un element sinó només el seu valor:
Nota
Depenent de l'entorn en què ens trobem, podria ser que l'anterior no ens mostre res. La raó és perquè els atributs no es poden serialitzar, i per tant no es poden mostrar en un entorn de XML. No tindríem aquest problema si accedim des de Java. La manera de solucionar-lo des de l'entorn de eXist és utilitzar la funció data():
/classe/professor/data(@Especialitat)
Obtenir el contingut d'un element
Per a aquells casos en què només vulguem el contingut de l’element, s’ha definit la funció text() per obtenir aquest contingut. Això s’ha fet així perquè d’altra manera, com que els nodes de text no tenen nom, no s’hi podria accedir.
De manera que si a un element que tinga contingut de dades se li afegeix text():
/classe/professor/nom/text()
…retornarà el contingut del node sense les etiquetes:
Comodins
De la mateixa manera que en els sistemes operatius, es poden fer servir comodins diversos en les expressions XPath. Es poden veure els comodins en la taula següent.
Comodí | Significat |
---|---|
* | L’asterisc es fa servir per indicar tots els elements d’un determinat nivell. |
. | Com en els directoris dels sistemes operatius el punt serveix per indicar el node actual. |
.. | Es fa servir per indicar el pare del node en el qual estem. |
// | La doble barra indica que quadrarà amb qualsevol cosa des del node en el qual estem, es a dir que buscarà en tots els seus descendents. Pot ser un sol element o un arbre de nodes. |
Amb l’asterisc es poden obtenir tots els elements d’un determinat nivell. Amb aquesta expressió es poden obtenir tots els elements de dins del node professor.
/classe/professor/*
Aquesta expressió retornarà per separat els dos nodes fills de <professor> , <nom> i <cognom>.
O bé fer servir les dobles barres (//) per obtenir tots els elements <nom> del fitxer independentment del lloc on estiguen dins del document XML.
//nom
El resultat serà:
Observeu que apareix el nom Joan 2 vegades, ja que és tant el nom del professor com d'un dels alumnes
Nota
En realitat aquesta sentència XPath tornarà molts més resultats, ja que buscarà en tots els documents de la col·lecció, i en Rutes.xml hi ha molts elements nom: els noms de les rutes i els noms dels punts, a banda dels noms de professors i d'alumnes.
Es poden posar les dobles barres en qualsevol lloc dins de l’expressió per indicar que pot haver qualsevol cosa enmig a partir del lloc on apareguen.
/classe/alumnes//nom
Donarà els dos noms dels alumnes (ara sí només alumnes, ni professors ni noms de ruta ni de punts):
Tot i que facilita molt la creació d’expressions no és molt recomanable abusar del comodí // per motius d’eficiència. Les expressions amb aquest comodí requeriran molts més càlculs per ser avaluades, i per tant les expressions tardaran més a donar resultats.
Eixos XPATH
Per avaluar les expressions XPath s’explora un arbre, de manera que també es proporcionen una sèrie d’elements per fer referència a parts de l’arbre. Aquestos elements s’anomenen eixos XPath
Eix | Significat |
---|---|
self:: | El node en el qual està el procés (fa el mateix que el punt) |
child:: | Fill de l’element actual |
parent:: | El pare de l’element actual (idèntic a fer servir .. ) |
attribute:: | Es fa servir per obtenir un atribut de l’element actual (@) |
Alguns d’aquestos eixos pràcticament no es fan servir perquè generalment és més còmode i curt definir les expressions a partir del símbol. Tothom prefereix fer servir una expressió com aquesta:
Que no la seua versió equivalent fent servir els eixos:
A part dels vistos en la taula anterior n’hi ha d’altres, que en aquest cas no tenen cap símbol que els simplifique:
Eix | Significat |
---|---|
descendant:: | Tots els descendents del node actual |
desdendant-or-self:: | El node actual i els seus descendents |
ancestor:: | Els ascendents del node |
ancestor-or-self:: | El node actual i els seus ascendents |
preceding:: | Tots els elements precedents al node actual |
preceding-sibling:: | Tots els germans precedents |
following:: | Elements que segueixen el node actual |
following-sibling:: | Germans posteriors al node actual |
namespace:: | Conté l’espai de noms del node actual |
Condicions
Un apartat interessant de les expressions XPath és poder afegir condicions per a la selecció de nodes. A qualsevol expressió XPath se li poden afegir condicions per obtenir només els nodes que complesquen la condició especificada.
Per exemple, aquesta expressió selecciona només els professors que tinguen un element <nom> com a fill de <professor>:
Si s’aplica l’expressió a l’exemple que hem fet servir per fer la vista d’arbre, el resultat serà el node <professor> que té dins seu <nom> (i ens apareixerà l'únic professor que tenim, ja que sí que té un fill nom)
En el valor de l’expressió s’hi especifiquen camins relatius des del node que tinga la condició. Fent servir condicions es pot fer una expressió que només retorne el professor si té alumnes (i ens tornaria el mateix resultat que abans, ja que sí que té alumnes)
Normalment la complexitat de les condicions va més enllà de comprovar si el node existeix, i es fan servir per comprovar si un node té un valor determinat. Per exemple, per obtenir els alumnes que es diguen “Bernat”:
que donarà:
<alumne aprovat="no">
<nom>Bernat</nom>
<cognoms>Balaguer</cognoms>
<nota>3</nota>
</alumne>
Les condicions es poden posar en qualsevol lloc del camí i n’hi pot haver tantes com calga. Per obtenir el cognom del professor que es diu “Bernat” es pot fer servir una expressió com aquesta.
Que donarà de resultat:
De la mateixa manera que per obtenir-ne els valors, es poden fer comparacions amb els valors dels atributs especificant el seu nom després del símbol @. Per saber si un element té l’atribut ‘delegat’:
Retornarà:
mentre que en la mateixa sentència ens haguérem preguntat per l'atribut aprovat, ens apareixerien els 3 alumnes, ja que tots tres el tenen.
De la mateixa manera que amb els elements, es poden posar condicions als atributs per saber si el seu valor té un determinat valor, etc.
que ens donaria els dos alumnes que estan aprovats
<nom>Albert</nom>
<cognoms>Alegre</cognoms>
<nota>6</nota>
</alumne>
<alumne delegat="si" aprovat="si">
<nom>Joan</nom>
<cognoms>Centelles</cognoms>
<nota>8</nota>
</alumne>
Les condicions també poden ser de desigualtat:
La funció not() es fa servir per negar les condicions:
<alumne aprovat="si">
<nom>Albert</nom>
<cognoms>Alegre</cognoms>
<nota>6</nota>
</alumne>
<alumne aprovat="no">
<nom>Bernat</nom>
<cognoms>Balaguer</cognoms>
<nota>3</nota>
</alumne>
Es poden mesclar les expressions amb condicions sobre atributs i sobre elements per aconseguir expressions més complexes especificant-les una al costat de l’altra. Per exemple, podem obtenir l'alumne que té no té l’atribut delegat i que està aprovat:
<alumne delegat="si" aprovat="si">
<nom>Joan</nom>
<cognoms>Centelles</cognoms>
<nota>8</nota>
</alumne>
L’expressió pot ser tan complexa com calga. Per exemple es pot obtenir la llista dels cognoms dels alumnes del professor de l'especialitat “507” que es diu “Joan”:
Que retornarà els tres cognoms dels alumnes:
Documents
Si no especifiquem res, a banda de la ruta, eXist buscarà en tots els documents de la col·lecció en la qual estiguem situats.
Per a buscar únicament en un document, l'haurem d'especificar al principi de la ruta. I la manera d'especificar el document serà: doc(ruta_del_document). Si posem únicament el nom del document no el trobarà, i estarem obligats a posar tota la seua ruta que serà: /db/nom_col/nom_doc . És a dir, el següent no troba res:
La manera d'accedir serà:
En altres entorns potser sí que funcione posar únicament el nom del document, però en el que estem treballant nosaltres, haurem de posar tota la ruta del document en la Base de Dades.
D'aquesta manera podrem solucionar el problema de la següent sentència, que agafa tots els noms d'alumnes i de professors, però també de rutes i de punts:
//nom
que donarà un total de 32 resultats
Si només els volem d'un document:
doc("db/Tema9/classe.xml")//nom
<nom>Joan</nom>
<nom>Albert</nom>
<nom>Bernat</nom>
<nom>Joan</nom>
Llicenciat sota la Llicència Creative Commons Reconeixement SenseObraDerivada 4.0