Conversió i adaptació de documents XML

A pesar que l’XML és un format relativament llegible en ser visualitzat, aquest no és un dels seus objectius principals, i menys si es té en compte que als humans els agrada llegir les dades col·locades en determinats formats que els facin la lectura més agradable –mentre que l’especificació XML exposa que en cap cas no s’ha d’incloure informació sobre la visualització en els documents.

En determinats casos pot caldre transformar els documents XML perquè siguin més fàcils de visualitzar, o també adaptar-los perquè puguin ser llegits per programes específics.

XML està pensat sobretot per a emmagatzemar i intercanviar informació, de manera que si cal representar les dades d’una manera diferent per optimitzar un procés o per millorar-ne la visualització hi haurà diverses possibilitats:

  1. Desenvolupar un programa: com que és relativament senzill treballar amb XML, es podria desenvolupar un programa que agafi les dades XML i generi la sortida tal com la volem. Això té l’inconvenient que caldrà tenir coneixements de programació i que pot representar molta feina encara que el que calgui fer sigui trivial.
  2. Fer servir CSS: en molts casos una solució senzilla seria fer servir CSS per representar la informació de manera més amigable fent servir un navegador. Però només serveix per canviar la visualització, no per canviar el document.
  3. Transformar el document: una solució alternativa consisteix a transformar el document en un altre que estigui pensat per ser visualitzat. Hi ha molt formats que estan pensats sobretot per ser visualitzats: PDF, HTML, XHTML, etc.

Ús de CSS

En molts casos si l’objectiu és que el document sigui visualitzat d’una manera més agradable la solució més senzilla pot ser visualitzar-lo mitjançant CSS.

CSS és interessant sobretot quan es vulguin fer adaptacions senzilles. Si es té un document XML com aquest:

  1. <?xml version="1.0" ?>
  2. <professor>
  3. <nom>Marcel</nom>
  4. <cognom>Garcia</cognom>
  5. <departament>Departament d'Informàtica</departament>
  6. <carrecs>
  7. <carrec>Cap de Departament</carrec>
  8. <carrec>Tutor</carrec>
  9. </carrecs>
  10. </professor>

…i es vol representar com una targeta de vista, es pot fer servir un document CSS que contingui aquestes línies:

  1. professor {
  2. padding: 30px;
  3. margin: 30px;
  4. border: 4px black solid;
  5. width: 40%;
  6. }
  7.  
  8. nom,cognom {
  9. font-size:30px;
  10. }
  11.  
  12. departament {
  13. padding-top:20px;
  14. display:block;
  15. font-weight:bold;
  16. }
  17.  
  18. carrec{
  19. font-style: italic;
  20. padding-left:10px;
  21. }
  22.  
  23. carrec:after { content:","; }

Així, es representarà el document XML com en la figura.

Figura Resultat de la transformació

Malgrat això, CSS té moltes limitacions a l’hora de presentar la informació:

  1. La informació no pot ser reordenada con vulguem. L’única manera de simular el canvi d’ordre és fer servir posicionaments absoluts.
  2. Els atributs es poden mostrar però hi ha moltes limitacions per fer-ho.
  3. No es poden afegir estructures noves producte de càlculs o de procés de les dades del document.
  4. No té maneres senzilles de formatar les dades en pàgines de text per ser impreses.

Si l’objectiu final no és simplement decorar el fitxer sinó transformar-lo en un altre document totalment diferent, CSS no serveix. CSS no transforma el document sinó que simplement canvia la manera com es visualitza.

Transformació de documents

Per intentar aconseguir fer tot allò que CSS no podia fer es va crear un nou llenguatge de plantilles: XSL (extensible stylesheet language).

Inicialment es van concentrar a poder representar la informació de manera que pogués ser mostrada en documents impresos i en pantalla però després es va acabar definint un sistema per fer transformacions genèriques de documents XML en altres coses: documents de text, documents XML, pàgines web, etc.

Actualment XSL és una família de llenguatges que serveixen per definir transformacions i presentacions de documents XML.

La família XSL està formada per tres llenguatges:

  • XSL-FO (XSL formatting objects): un llenguatge per definir el format que s’ha d’aplicar a un document.
  • XSLT (XSL transformations): un llenguatge per transformar documents XML.
  • XPath: un llenguatge per accedir a parts dels documents XML.

XSL-FO

XSL-FO és un llenguatge basat en XML que està pensat per donar format als documents XML, però a diferència d’altres llenguatges amb objectius similars, com CSS o XHTML, està pensat per generar sortides tant per a formats de pantalla com per a formats paginats.

XSL-FO és un llenguatge que:

  • Permet especificar amb molta precisió el contingut d’un document (paginació, organització, estil, etc.).
  • Permet crear documents d’alta qualitat.
  • És ideal per generar documents amb dades que canvien sovint.

XSL-FO sobretot es fa servir per generar documents en formats pensats per ser impresos com PDF o Postcript.

Generació de PDF

Un dels processadors d’XSL-FO més populars és l’Apache FOP, que permet crear documents en PDF a partir de documents XSL-FO.

És corrent que la generació del document es faci en dues fases (figura):

  1. Transformació del document XML en un document XSL-FO amb el llenguatge de transformacions XSLT.
  2. Transformació del document XSL-FO en el format que volem amb un processador XSL-FO.
Figura Transformació d’un document XML en PDF i HTML

Per tant, els processadors XSL-FO s’encarreguen de generar el format que volem a partir de les dades especificades en els documents XSL-FO.

Processadors XPath o XSLT

En general els processadors XPath o XSLT es proporcionaran per mitjà de biblioteques que podran ser cridades des dels programes.

Això permet simplificar tot el procés de creació de programes que facin servir XPath o XSLT, ja que quan una aplicació es vulgui aprofitar de les característiques d’algun d’aquests llenguatges no ho haurà d’implementar tot de nou sinó simplement fer servir les biblioteques.

Biblioteques

En alguns casos les biblioteques tindran suport tant per a XSLT com per a XPath, i en d’altres casos s’haurà de recórrer a dues biblioteques diferents. Per exemple, en el cas del suport XML del projecte Gnome, per poder tenir suport XPath i XSLT hem de recórrer a dues biblioteques diferents:

  • libxml2: ofereix suport per processar XML i XPath.
  • libxslt: agafa de base libxml2 per permetre fer transformacions XSLT.

Mentre que amb Saxon el suport XPath i XSLT està en la mateixa biblioteca.

Les biblioteques més usades són:

  • libxml2 i libxslt
  • Apache Xalan
  • Saxon
  • MSXML

A l’hora de triar una biblioteca o una altra cal tenir clar si necessitem el suport per a les versions 2.0 d’aquests llenguatges, ja que no hi sol haver gaire problemes per fer transformacions amb les versions 1.0, i tots els processadors les solen suportar; no sempre passa el mateix amb les versions 2.0.

libxml2 i libxslt

Del projecte GNOME han sortit les biblioteques libxml2 i libxslt, que són biblioteques que permeten tenir suport per a XML, XPath i transformacions XSLT.

La utilitat xmllint de libxml2 permet executar expressions XPath de dues maneres. De manera interactiva amb el paràmetre –shell. Amb aquest paràmetre entrem en un entorn d’ordres que ens permet executar ordres contra el fitxer.

Una de les ordres possibles dins d’aquest entorn és xpath, que ens donarà informació sobre com seran els resultats.

  1. $ xmllint --shell persones.xml
  2. / > xpath //nom
  3. Object is a Node Set :
  4. Set contains 4 nodes:
  5. 1 ELEMENT nom
  6. 2 ELEMENT nom
  7. 3 ELEMENT nom
  8. 4 ELEMENT nom

Per veure els resultats d’una manera més amigable és més útil fer servir cat.

  1. $ xmllint --shell persones.xml
  2. / > cat //nom
  3. -------
  4. <nom>Marcel Puig</nom>
  5. -------
  6. <nom>Frederic Pi</nom>
  7. -------
  8. <nom>Filomeno Garcia</nom>
  9. -------
  10. <nom>Manel Puigdevall</nom>

L’altra possibilitat consisteix a especificar l’expressió XPath en la línia d’ordres fent servir el paràmetre –xpath:

  1. $ xmllint --xpath //nom persones.xml
  2. <nom>Marcel Puig</nom>
  3. <nom>Frederic Pi</nom>
  4. <nom>Filomeno Garcia</nom>
  5. <nom>Manel Puigdevall</nom>

La biblioteca libxslt porta una utilitat des de l’entorn d’ordres que permet fer transformacions XSLT, que s’anomena xsltproc.

Amb xsltproc es pot transformar un fitxer en un altre passant-li com a paràmetres el fitxer per transformar i la plantilla.

  1. $ xsltproc fitxer.xml fitxer.xsl -o sortida

Es poden trobar versions d’xsltproc compilades per a Windows i que funcionaran de la mateixa manera.

Apache Xalan

Apache Xalan és un intent de fer unes biblioteques de C++ i de Java de qualitat comercial, lliures i multiplataforma.

En els exemples que vénen amb la biblioteca es pot trobar un programa d’exemple amb el qual es poden fer transformacions XPath anomenat XPathResolver.

En el mateix paquet es pot trobar una utilitat d’entorn d’ordres que permet fer transformació de documents.

  1. $ xalan -in fitxer.xml -xsl fitxer.xsl -out sortida
Saxon

Saxon és el processador més complet de tots, ja que està desenvolupat per un dels especificadors d’XSLT, i per tant segueix fidelment l’estàndard.

Hi ha dues versions de Saxon, una per a Java i una per a .NET. Té una versió de les biblioteques de codi obert, Saxon-HE (Home Edition), i dues de comercials, Saxon-PE (Professional Edition) i Saxon-EE (Enterprise Edition).

Amb la biblioteca es poden trobar exemples d’ús que es poden fer servir per fer proves i transformacions.

En sistemes basats en Debian, com l’Ubuntu, després d’instal·lar el paquet libsaxonb-java es pot executar una consulta XPath passant l’expressió amb echo a saxonb-xquery.

  1. $ echo //nom | saxonb-xquery -s persones.xml -

Es poden fer transformacións XSLT amb l’ordre saxonb-xslt passant-hi el fitxer XML i el fitxer de plantilles XSLT

  1. $ saxonb-xslt -o sortida persones.xml persones.xsl
Microsoft XML Parser

Es tracta del més usat en el món de la programació en .NET. Es pot descarregar des del web de Microsoft.

L’execució des de consola no difereix gaire de les dels altres processadors. Per exemple, per fer transformacions podem fer:

  1. c:\> msxml fitxer.xml fitxer.xsl -o sortida

XPath

XPath (XML path language) és una manera d’especificar parts d’un document XML que té eines per manipular el contingut de les dades de text, numèriques, etc.

XPath és una recomanació del W3C (www.w3.org/TR/xpath), que tot i que serveix per treballar amb XML no és un llenguatge XML. La idea és que en no estar basat en XML es podrà incloure en altres llenguatges XML sense haver de preocupar-se de si el resultat està ben format o no.

La base del funcionament d’XPath és l’avaluació d’expressions. Una expressió que s’avaluarà contra un document XML i ens donarà un resultat que pot ser de diferents tipus:

  1. Un boleà: cert o fals
  2. Un nombre
  3. Una cadena de caràcters
  4. Un grup d’elements

XPath està desenvolupat pels comitès de creació d’XSL i XQuery i s’ha convertit en un component essencial per a diferents llenguatges XML com XLinks, XSLT i XQuery, com es pot veure en la figura.

Figura Relació d’XPath amb diferents llenguatges XML

La versió 2.0 d’XPath està tan integrada dins d’XQuery que qualsevol expressió XPath és també automàticament una expressió XQuery correcta.

Vista d'arbre

XPath tracta tots els documents XML des del punt de vista d’un arbre de nodes en què hi ha una arrel que no es correspon amb l’arrel del document, sinó que és el document i es representa amb el símbol “/”.

A part de l’arrel també hi ha nodes per representar els elements, els atributs, els nodes de dades, els comentaris, les instruccions de procés i els espais de noms.

L’exemple següent XML:

  1. <?xml version=”1.0” ?>
  2. <classe>
  3. <assignatura>Llenguatges de marques</assignatura>
  4. <professor Especialitat="507">
  5. <nom>Marcel</nom>
  6. <cognoms>Puig</cognoms>
  7. </professor>
  8. <alumnes>
  9. <alumne>
  10. <nom>Frederic</nom>
  11. <cognoms>Pi</cognoms>
  12. </alumne>
  13. <alumne>
  14. <nom>Filomeno</nom>
  15. <cognoms>Garcia</cognoms>
  16. </alumne>
  17. </alumnes>
  18. </classe>

Es representarà en XPath amb un arbre com el de la figura.

Figura Arbre XPath

En un arbre XPath els atributs no són considerats nodes fills sinó que són “propietats” del node que els conté i els nodes de dades són nodes sense nom que només contenen les dades.

Programari per avaluar XPath

Molts programes permeten executar una consulta XPath contra un document XML. Hi ha programes específics, editors XML, components dels navegadors web, pàgines web online, etc.

És impossible mostrar tots els programes que permeten treballar amb XPath i, per tant, només se’n mostraran alguns exemples.

"xpath"

La instal·lació per defecte d’Ubuntu instal·la automàticament una ordre basada en Perl anomenada xpath que permet comprovar les ordres XPath des de la consola. L’expressió es posa rere el paràmetre -e.

  1. $ xpath -q -e //nom persones.xml
  2. <nom>Marcel Puig</nom>
  3. <nom>Frederic Pi</nom>
  4. <nom>Filomeno Garcia</nom>
  5. <nom>Manel Puigdevall</nom>

XPath Checker

Una utilitat molt interessant és un component del Firefox anomenat XPath Checker, que permet fer consultes XPath interactivament, tant en pàgines HTML com en documents XML que s’hagin visualitzat en el navegador.

Un cop instal·lat el component i carregat el document per avaluar amb el botó dret del ratolí, es tria l’opció “View XPath” (figura).

Figura Engegar XPath Checker

S’obrirà una finestra nova on es poden anar executant expressions XPath i també es mostra el resultat de la consulta en la part inferior de manera interactiva (figura).

Figura Els resultats van canviant en funció de l’expressió que s’especifiqui

Editors XML

L’opció més professional és fer servir algun dels editors especialitzats en XML. Aquests editors permeten avaluar expressions XPath des d’un entorn gràfic amb tot tipus d’assistències en la creació de les expressions, possibilitats de depuració, etc. En la imatge següent es pot veure un exemple de l’assistent de l’oXygen XML Editor (figura).

Figura Assistent de creació d’expressions XPath

Navegació

Com que la representació interna del document XML per XPath serà un arbre, s’hi pot navegar especificant-hi camins d’una manera semblant a com es fa en els directoris dels sistemes operatius.

Expressar camins en XPath s’assembla tant a com ho fan els sistemes operatius que fins i tot es fan servir símbols semblants.

El més important per tenir en compte a l’hora de crear una expressió XPath és saber 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 en l’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 sigui 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 que hem especificat anteriorment fent servir l’expressió XPath següent:

/classe/professor/nom

Podem veure com s’avalua l’expressió en l’arbre XPath en la figura.

Figura Avaluació de l’expressió /classe/professor/nom

Cal tenir en compte que el resultat d’aquesta expressió no és només el contingut de l’element sinó tot l’element <nom>.

  1. <nom>Marcel</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 sol valor. Per exemple, si l’expressió per avaluar fos la següent:

/classe/alumnes/alumne/nom

XPath l’avaluaria intentant aconseguir tots els camins que quadrin amb l’expressió, tal com podeu veure visualment en la figura.

Figura Avaluació de l’expressió /classe/alumnes/alumne/nom

El resultat seran els dos resultats possibles:

  1. <nom>Frederic</nom>
  2. <nom>Filomeno</nom>

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 gaire dels altres casos (figura):

Figura Avaluació de l’expressió /classe/alumnes

En aquest cas el resultat no és un element simple sinó que és tot un subarbre d’elements.

  1. <alumnes>
  2. <alumne>
  3. <nom>Frederic</nom>
  4. <cognom>Pi</cognom>
  5. </alumne>
  6. <alumne>
  7. <nom>Filomeno</nom>
  8. <cognom>Garcia</cognom>
  9. </alumne>
  10. </alumnes>

Si se sap que una expressió retornarà diversos resultats però només se’n vol un d’específic es pot fer servir un nombre 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]

Dels dos nodes disponibles com a fills de <alumnes>, només se seleccionarà el primer (figura).

Figura Avaluació de l’expressió /classe/alumnes/alumne/nom

O sigui:

  1. <alumne>
  2. <nom>Frederic</nom>
  3. <cognom>Pi</cognom>
  4. </alumne>

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

Sempre s’ha d’anar en 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.

  1. /classe/nom

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 (figura).

Figura Avaluació de l’expressió /classe/alumnes

Obtenir els atributs d'un element

Els valors dels atributs es poden aconseguir especificant el símbol @ davant del nom un cop s’hagi arribat a l’element que el conté (figura).

/classe/professor/@especialitat
Figura Avaluació de l’expressió /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:

507

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 tingui contingut de dades se li afegeix text():

/classe/professor/nom/text()

…retornarà el contingut del node sense les etiquetes:

  1. Marcel

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.

Taula: Comodins en XPath
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.
/ / Les dobles barres indiquen que quadrarà amb qualsevol cosa des del node en el qual estem. 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>).

  1. <nom>Marcel</nom>
  2. <cognoms>Puig</cognoms>

O bé fer servir les dobles barres (//) per obtenir tots els elements <nom> del fitxer independentment del lloc on siguin dins del document XML.

//nom

El resultat serà:

  1. <nom>Marcel</nom>
  2. <nom>Frederic</nom>
  3. <nom>Filomeno</nom>

Es poden posar les dobles barres en qualsevol lloc dins de l’expressió per indicar que hi pot haver qualsevol cosa enmig a partir del lloc on apareguin.

/classe/alumnes//nom

Donarà els dos noms dels alumnes:

  1. <nom>Frederic</nom>
  2. <nom>Filomeno</nom>

Tot i que facilita la creació d’expressions no és gaire 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 trigaràn 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. Aquests elements s’anomenen eixos XPath (taula).

Taula: 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’aquests 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:

/classe/professor/nom

Que no pas la seva versió equivalent fent servir els eixos:

/child::classe/child::professor/child::nom

A part dels vistos en la taula n’hi ha d’altres, que en aquest cas no tenen cap símbol que els simplifiqui (taula).

Taula: Eixos XPath
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
prededint:: 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 compleixin la condició especificada.

La selecció de nodes es fa especificant un predicat XPath dins de claudàtors.

Per exemple, aquesta expressió selecciona només els professors que tinguin un element <nom> com a fill de <professor>:

/classe/professor[nom]

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>.

  1. <professor especialitat="507">
  2. <nom>Marcel</nom>
  3. <cognoms>Puig</cognoms>
  4. </professor>

En el valor de l’expressió s’hi especifiquen camins relatius des del node que tingui la condició. Fent servir condicions es pot fer una expressió que només retorni el professor si té alumnes.

  1. /classe/professor[../alumnes/alumne]

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 professors que es diguin “Marcel”:

/classe/professor[nom="Marcel"]

Les condicions es poden posar en qualsevol lloc del camí i n’hi pot haver tantes com calgui. Per obtenir el cognom del professor que es diu “Marcel” es pot fer servir una expressió com aquesta.

/classe/professor[nom="Marcel"]/cognoms

Que donarà de resultat:

  1. <cognoms>Puig</cognoms>

De la mateixa manera que per obtenir-ne els valors, es poden fer comparacions amb els valors dels atributs especificant el seu nom rere el símbol @. Per saber si un element té l’atribut ‘especialitat’:

/classe/professor[@especialitat]

Retornarà:

  1. <professor especialitat="507">
  2. <nom>Marcel</nom>
  3. <cognom>Puig</cognom>
  4. </professor>

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.

/classe/professor[@especialitat="507"]
/classe/professor[@especialitat>=507]

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 el professor que té l’atribut especialitat a “507” i que es diu “Marcel” amb l’expressió:

/classe/professor[@especialitat="507"][nom="Marcel"]

La funció not() es fa servir per negar les condicions:

/classe/professor[not(@especialitat)]

L’expressió pot ser tan complexa com calgui. Per exemple es pot obtenir la llista dels cognoms dels alumnes del professor de tipus “507” que es diu “Marcel”:

/classe/professor[@Especialitat="507"][nom="Marcel"]/../alumnes/alumne/cognoms

Que retornarà els dos cognoms:

  1. <cognoms>Pi</cognoms>
  2. <cognoms>Garcia</cognoms>

Seqüències

Una seqüència és una expressió XPath que retorna més d’un element. S’assemblen bastant a les llistes d’altres llenguatges:

  • Tenen ordre
  • Permeten duplicats
  • Poden contenir valors de tipus diferent en cada terme

La creació dinàmica de seqüències funciona a partir d’XPath 2.0.

És fàcil crear seqüències, ja que només cal tancar-les entre parèntesi i separar cada un dels termes amb comes. L’expressió següent aplicada a qualsevol document:

(1,2,3,4)

Retorna la seqüència de nombres d’un en un:

  1. 1
  2. 2
  3. 3
  4. 4

També es poden crear seqüències a partir d’expressions XPath. En aquest cas s’avaluarà primer la primera expressió, després la segona, etc.

(//nom/text(), //cognoms/text())

Aplicat al nostre exemple retornarà primer tots els noms i després tots els cognoms:

  1. Marcel
  2. Frederic
  3. Filomeno
  4. Puig
  5. Pi
  6. Garcia

Unió, intersecció i disjunció

També es pot operar amb les seqüències d’elements. Una manera seria fer servir els operadors d’unió (union), intersecció (intersec) o disjunció (except).

Per exemple, l’expressió següent ens retornaria els cognoms dels alumnes que coincideixin amb els d’un professor:

(//alumne/nom) intersect (//professor/nom)

Amb la unió es poden unir les llistes de manera que en quedi una de sola sense duplicats:

(//alumne/nom) union (//professor/nom)

I amb la disjunció obtenim els noms de la primera seqüència que no surten en la segona:

(//alumne/nom) except (//professor/nom)

Funcions

XPath ofereix una gran quantitat de funcions destinades a manipular els resultats obtinguts.

Les funcions que ofereix XPath es classifiquen en diferents grups:

  • Per manipular conjunts de nodes: es pot obtenir el nom dels nodes, treballar amb les posicions, comptar-los, etc.
  • Per treballar amb cadenes de caràcters: permeten extreure caràcters, concatenar, comparar… les cadenes de caràcters.
  • Per fer operacions numèriques: es poden convertir els resultats a valors numèrics, comptar els nodes, fer-hi operacions, etc.
  • Funcions boleanes: permeten fer operacions boleanes amb els nodes.
  • Funcions per dates: permeten fer operacions diverses amb dates i hores.

És impossible especificar-les totes aquí, de manera que el millor és consultar l’especificació XPath (http://www.w3.org/TR/xpath-functions) per veure quines funcions es poden fer servir.

Entre totes les funcions podem destacar les que surten en la taula.

Taula: Funcions XPath destacades
Funció Ús
name() Retorna el nom del node
sum() Retorna la suma d’una seqüència de nodes o de valors
count() Retorna el nombre de nodes que hi ha en una seqüència
avg() Fa la mitjana dels valors de la seqüència
max() Retorna el valor màxim de la seqüència
min() Dóna el valor mínim de la seqüència
position() Diu en quina posició es troba el node actual
last() Retorna si el node actual és l’últim
distinct-values() Retorna els elements de la seqüència sense duplicats
concat() Uneix dues cadenes de caràcters
starts-with() Retorna si la cadena comença amb els caràcters marcats
contains() Ens diu si el resultat conté el valor
string-length() Retorna la llargada de la cadena
substring() Permet extreure una subcadena del resultat
string-join() Uneix la seqüència amb el separador especificat
current-date() Ens retornarà l’hora actual
not() Inverteix el valors booleans

Amb les funcions es podran fer peticions que retornin valors numèrics. Per exemple, “quants alumnes tenim?”:

count(/classe/alumnes/alumne)

Que tornarà el nombre d’alumnes del fitxer:

2

O bé retornar cadenes de caràcters. Per exemple, unir tots els noms separant-los per una coma:

string-join(//nom,",")

Que retornarà en un únic resultat els noms separats per una coma:

Marcel,Frederic,Filomeno

També es poden posar les funcions en els predicats. Per exemple, aquesta expressió ens retornarà els alumnes amb cognom que comenci per p.

/classe/alumnes/alumne[starts-with(cognoms,"P")]

En aquesta expressió volem obtenir el segon alumne de la llista:

/classe/alumnes/alumne[position()=2]

XSLT

XSLT (extensible stylesheet language for transformations) és un llenguatge de plantilles basat en XML que permet convertir l’estructura dels elements XML en altres documents.

Es tracta d’una recomanació del W3C (World Wide Web Consortium), com ho és CSS, però XSLT va molt més enllà, ja que supera moltes de les limitacions de CSS.

Amb XSLT es poden fer transformacions que canviïn totalment l’estructura del document, pot reordenar la informació del document XML, afegir-hi informació nova on sigui, prendre decisions en funció de la informació que s’hi trobi, fer càlculs, etc.

XSLT es recolza en altres tecnologies XML per funcionar:

  • Fa servir XPath per determinar les plantilles per aplicar en cada moment (i per tant s’integra en XQuery).
  • Suporta XML Schemas per definir els tipus de dades.

Tot i que hi ha la versió 2.0 d’XSLT, la que es fa servir més és la 1.0.

La versió 2.0 de XSLT afegeix tota una sèrie de característiques que encara fan més potent XSLT:

  • Suporta els tipus de dades d’XML Schemas
  • Inclou elements nous que permeten agrupar resultats, etc.
  • Pot generar múltiples sortides en una sola transformació
  • Afegeix un grup de funcions noves a més de les d’XPath 2.0
  • Pot processar fitxers que no siguin XML

Cada vegada es fan servir més les plantilles XSLT per generar vistes personalitzades d’un document XML per ser visualitzades en diferents destinacions (impressora, pantalla d’ordinador, telèfon mòbil…). D’aquesta manera n’hi ha prou només tenint el document XML original, i els altres es crearan sota demanda (figura).

Figura L’ús més corrent és transformar documents en funció de la destinació

Una de les limitacions d’XSLT és que el document d’entrada ha de ser sempre XML, a pesar que la sortida no té aquesta limitació i pot acabar essent en qualsevol format: text, HTML, XML, etc.

Programes

A pesar que les biblioteques XSLT tenen utilitats que es poden fer servir en temps de creació per provar que la plantilla fa el que ha de fer, normalment les transformacions es faran internament des de programes. És per aquest motiu que la majoria de les implementacions XSLT estan en forma de biblioteques.

Uns dels programes d’ús corrent que tenen incorporades biblioteques XSLT són els navegadors web (Firefox, Internet Explorer, Google Chrome, i d’altres). Si es carrega un document XML que té associada una transformació XSLT en un navegador web es transformarà automàticament i s’hi mostrarà el resultat transformat.

Les plantilles XSLT són documents XML que es poden crear fent servir editors de text o bé editors especialitzats en XML. En la creació de plantilles XSLT, els avantatges que ofereixen els editors XML són tan importants (depuradors d’expressions, ajudes…) que els fan una eina molt valuosa per treballar-hi professionalment (figura).

Figura El depurador XSLT incorporat a l’oXygen XML Editor

El procés de transformació

Una transformació XSLT consisteix a passar un document XML i una plantilla per un processador XSLT, el qual aplicarà les regles que trobi en la plantilla al document per generar un document nou (figura). El fitxer de resultat de la transformació pot ser tant un document XML com en qualsevol altre format.

Per associar un document XML a una plantilla XSLT específica es fa servir l’etiqueta <?xml-stylesheet ?>.

Per exemple si volem associar la plantilla XSLT alumnes.xsl a un document cal editar-lo i afegir-hi l’etiqueta <?xml-stylesheet ?> rere la declaració xml:

  1. <?xml-stylesheet href="alumnes.xsl" type="text/xsl" ?>
Figura Processar XSLT

L'arrel del document XSLT

Les plantilles XSLT són documents XML, i per tant, han de complir les regles dels documents XML. Això vol dir que han de tenir un element arrel:

L’arrel de les plantilles XSLT és l’element <stylesheet>.

L’element arrel <stylesheet> ha de tenir obligatòriament dos atributs:

  • L’atribut version, que especificarà quina és la versió d’XSLT que s’ha fet servir per crear la plantilla i que es farà servir per fer la transformació.
  • L’espai de noms de XSLT, que normalment s’associa amb l’àlies ‘xsl’.

Per exemple, per a la versió 2.0 d’XSLT la definició de l’arrel seria una cosa com aquesta:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3. xmlns:xs="http://www.w3.org/2001/XMLSchema"
  4. version="2.0">
  5.  
  6. </xsl:stylesheet>

Dins de l’arrel es definiran les plantilles que determinaran quina és la transformació que es vol fer en el document original.

Crear una plantilla

El procés de transformació es farà intentant aplicar alguna plantilla als nodes del document original.

Qualsevol element que no es pugui processar amb una plantilla es transformarà amb el funcionament per defecte:

  • Si el node té contingut es retornarà el contingut del node
  • Si el node no té contingut es retornarà sense escriure res

Per tant l’element bàsic per fer les transformacions són les plantilles. Les plantilles es defineixen amb l’element <xsl:template>.

L’element de plantilla pot tenir diversos atributs però el més corrent és match. L’atribut match serveix per determinar a quins nodes s’ha d’aplicar aquesta plantilla per mitjà d’una expressió XPath.

En el contingut de l’element de plantilla s’especificarà quina és la transformació que cal aplicar als elements. La transformació més senzilla consisteix a escriure un text literal. Per exemple, en la plantilla següent s’està definint que en arribar algun element <nom> es desi en el fitxer de destinació la lletra A:

  1. <xsl:template match="nom">
  2. A
  3. </xsl:template>

Per tant si s’aplica la plantilla anterior a aquest document:

  1. <persona>
  2. <nom>Pere Garcia</nom>
  3. </persona>

El processador anirà analitzant els nodes del document original i primer intentarà buscar una plantilla per a l’element <persona>, i com que no en trobarà cap recorrerà al comportament per defecte i escriurà una línia en blanc.

Després intentarà trobar una plantilla per a l’element <nom> que, segons la plantilla, s’ha de transformar en una lletra A.

Com que no hi ha més nodes el resultat serà aquest:

_
    A

Cal tenir en compte que un cop un element ha estat processat per una plantilla se’n processa tot el seu contingut amb ell (i, per tant, també els elements que pugui contenir). Si canviem la plantilla anterior per la següent:

  1. <xsl:template match="persona">
  2. Persona
  3. </xsl:template>
  4.  
  5. <xsl:template match="nom">
  6. A
  7. </xsl:template>

En aplicar-la al mateix XML primer processarà l’element <persona> i el transformarà en “Persona” en el document de sortida, però com que <persona> conté tots els altres elements, la transformació s’acabarà.

    Persona
Afegir elements

El fet de poder fer transformacions fent servir text literal fa que també es pugui fer servir el mateix sistema per crear etiquetes noves. Si es modifica la plantilla anterior per una com la següent:

  1. <xsl:template match="nom">
  2. <senyor>Manel</senyor>
  3. </xsl:template>

El resultat serà que el transformarà en aquest:

  1. <senyor>Manel</senyor>

S’ha d’anar amb compte quan s’especifiquen etiquetes literals, ja que no es poden crear etiquetes que deixin la plantilla mal formada. La plantilla següent que només obre l’etiqueta <senyor> no es pot fer servir, perquè deixa la plantilla mal formada:

  1. <xsl:template match="nom">
  2. <senyor>Manel
  3. </xsl:template>

Una manera alternativa de crear elements en una transformació és fer servir <xs:element>. Entre els atributs que pot tenir, l’únic obligatori és name, que defineix el nom que tindrà l’etiqueta.

Per exemple, amb la plantilla següent creem un element <senyor> que sempre tindrà de contingut “Pere” per a cada element <nom> que es trobi en el document.

  1. <xsl:template match="nom">
  2. <xs:element name="senyor">Pere</xs:element>
  3. </xsl:template>

O sigui, que la sortida de cada element <nom> serà:

<senyor>Pere</senyor>
Afegir atributs

Els atributs es poden definir dins d’un nou element amb <xsl:attribute> i de la mateixa manera que amb els nous elements, l’únic atribut obligatori és name.

Una transformació que tingués això:

  1. <xs:element name="persona">
  2. <xsl:attribute name="home">Si</xsl:attribute>
  3. Marcel
  4. </xsl:element>

Generaria el següent:

  1. <persona home="Si">Marcel</persona>
Control de les sortides de text

En comptes de fer servir literals també es poden fer transformacions en text fent servir l’element <xsl:text>. Aquest element és important quan es volen controlar millor els espais i els salts de línia que hi haurà en les sortides.

Podem fer que surtin 5 espais darrere de la lletra A definint la plantilla de la manera següent:

  1. <xsl:template match="nom">
  2. <xsl:text>A </xsl:text>
  3. </xsl:template>

Si no ho féssim amb <xsl:text> els espais de darrere la A es perdrien.

Obtenir valors

Una tasca habitual a l’hora de fer una transformació sol ser obtenir els valors dels elements del document d’origen per posar-los en l’element de destinació. Es poden obtenir el valor dels elements d’origen fent servir <xsl:value-of>.

Aquest element avalua l’expressió XPath de l’atribut select i en genera una sortida amb el seu contingut.

Per exemple, a partir de l’XML següent:

  1. <xsl:template match="persona">
  2. <xsl:value-of select="nom">
  3. </xsl:template>

Afegirà el valor de l’element <nom> en el fitxer de sortida:

Pere Garcia

Però s’ha de tenir en compte que només avalua el primer element que compleixi la condició, o sigui, que si el fitxer de mostra fos el següent:

  1. <?xml version="1.0" ?>
  2. <persona>
  3. <nom tipus="Professor">Pere Garcia</nom>
  4. <nom>Frederic Pi</nom>
  5. <nom>Manel Puig</nom>
  6. </persona>

…la sortida d’aplicar la mateixa plantilla només seria el primer dels noms i no tots dos, perquè agafaria només el primer <nom> de <persona>:

Pere Garcia

Per tant és molt important triar bé quines són les expressions XPath de les plantilles per evitar aquest comportament. En aquest cas la solució podria ser escollir <nom> en comptes de <persona>:

  1. <xsl:template match="nom">
  2. <xsl:value-of select="."/>
  3. </xsl:template>

Com a resultat de l’element <xsl:value-of> s’hi pot posar qualsevol expressió XPath. Per tant, també es poden obtenir els valors dels atributs afegint ”@” davant del nom.

  1. <xsl:template match="nom">
  2. <xsl:value-of select="."/> ( <xsl:value-of select="@tipus" /> )
  3. </xsl:template>

Que generarà:

Pere Garcia ( Professor )
Frederic Pi (  )
Manel Puig (  )

I també es poden fer servir les funcions XPath. Per tant, es pot generar una sortida amb el total de les persones del fitxer:

  1. <xsl:template match="/">
  2. Total: <xsl:value-of select="count(//nom)"/>
  3. </xsl:template>

Que donarà de resultat:

Total: 3

Reenviar nodes a una altra plantilla

Un altre ús habitual de les plantilles és el de fer-les servir per cridar-ne d’altres quan es volen processar alguns dels nodes obtinguts per la plantilla quan aquesta n’obté diversos.

Les crides a plantilles es poden fer amb l’element <xsl:apply-templates>. Amb aquest element es pot fer que el diferents resultats d’una expressió XPath es vagin processant un a un, buscant una plantilla on aplicar-se.

Si partim d’aquest codi XML:

  1. <classe>
  2. <nom>Frederic Pi</nom>
  3. <nom>Filomeno Garcia</nom>
  4. <nom>Manel Puigdevall</nom>
  5. </classe>

I el full de plantilles següent:

  1. <xsl:template match="/">
  2. <xsl:apply-templates select="classe/nom"/>
  3. </xsl:template>
  4.  
  5. <xsl:template match="nom">
  6. <xsl:value-of select="."/>
  7. </xsl:template>

Al executar-se l’apply-templates s’avalua l’expressió XPath que conté, classe/nom, que retorna tres resultats:

  1. <nom>Frederic Pi</nom>
  2. <nom>Filomeno Garcia</nom>
  3. <nom>Manel Puigdevall</nom>

Cada un d’aquests resultats individualment intentarà trobar una plantilla on aplicar-se. De manera que es processarà tres vegades el segon <xsl:template>, ja que és qui captura nom, i donarà com a resultat:

Frederic Pi
Filomeno Garcia
Manel Puigdevall

Una de les característiques interessants és que <apply-templates> també es pot fer servir per reordenar el contingut. Per exemple, amb l’XML següent:

  1. <classe>
  2. <professors>
  3. <nom>Marcel Puig</nom>
  4. <nom>Maria Sabartés</nom>
  5. </professors>
  6. <alumnes>
  7. <nom>Frederic Pi</nom>
  8. <nom>Filomeno Garcia</nom>
  9. <nom>Manel Puigdevall</nom>
  10. </alumnes>
  11. </classe>

Es poden obtenir tots els nodes amb una plantilla que capturi l’arrel i que primer mostri els noms dels alumnes i després els dels professors, de la següent manera:

  1. <xsl:template match="classe">
  2. Alumnes
  3. ----------
  4. <xsl:apply-templates select="alumnes/nom"/>
  5. Professors
  6. ----------
  7. <xsl:apply-templates select="professors/nom"/>
  8. </xsl:template>
  9.  
  10. <xsl:template match="nom">
  11. <xsl:value-of select="."/>
  12. </xsl:template>

Que generarà:

Alumnes
----------
Frederic Pi
Filomeno Garcia
Manel Puigdevall

Professors
----------
Marcel Puig
Maria Sabartés

Es pot veure que un dels usos d’aquest element pot ser reordenar els resultats. En l’exemple, els alumnes en el document original estaven darrere dels professors, i en canvi en el que hem obtingut estan davant.

Processar els nodes per fer tasques diferents

A vegades pot interessar processar els mateixos nodes diverses vegades per obtenir diferents resultats. Per poder fer això es poden definir les plantilles que tinguin l’atribut mode.

Si es defineix una plantilla amb l’atribut mode per activar la plantilla no n’hi haurà prou que quadri amb l’atribut match, sinó que també caldrà que s’hi passi l’atribut mode.

  1. <template match="nom" mode="resultat">
  2. ...
  3. </template>

Les plantilles amb l’atribut mode han de ser cridades específicament. Per exemple, amb <apply-templates>:

  1. <xsl:apply-templates select="nom" mode="resultat"/>

Això permet fer dues coses diferents amb l’element <alumnes> de l’exercici anterior: comptar els alumnes i fer-ne una llista.

  1. <xsl:template match="classe">
  2. <xsl:apply-templates select="//alumnes" mode="resultat"/>
  3. <xsl:apply-templates select="//alumnes"/>
  4. </xsl:template>
  5.  
  6. <xsl:template match="alumnes">
  7. <xsl:apply-templates select="nom" />
  8. </xsl:template>
  9.  
  10. <xsl:template match="alumnes" mode="resultat">
  11. Total: <xsl:value-of select="count(nom)"/>
  12. </xsl:template>
  13.  
  14. <xsl:template match="nom">
  15. <xsl:value-of select="."/>
  16. </xsl:template>

El resultat serà:

Total: 3            
Frederic Pi            
Filomeno Garcia            
Manel Puigdevall

Forçar el tipus de sortida

XSLT està pensat per generar sortides en text, XML, HTML i XHTML. Per defecte considera que la sortida serà un altre document XML i, per tant, si es vol generar un document XML no cal especificar res.

Molts processadors interpreten que la sortida serà HTML si la primera etiqueta que troben és <html>.

Podem forçar que la sortida sigui una altra amb <xsl:output>. Per exemple podem fer que la sortida sigui interpretada com a text pla amb:

<xsl:output type="text">

Si l’atribut type no és “xml” no sortirà la capçalera XML en el resultat final.

Però a part de type hi ha altres atributs que permeten controlar de quina manera es generaran els resultats. Per exemple, indent serveix per formatar les sortides, encoding per definir la codificació que cal fer servir, etc.

Instruccions de control

XSLT proporciona una manera de processar els resultats molt semblant a com ho fan els llenguatges de programació. Com molts llenguatges de programació, incorpora instruccions per processar els resultats.

Expressions condicionals

<xsl:if> permet afegir els resultats al fitxer només si es compleix una determinada condició.

Per exemple, davant d’un document com el següent:

  1. <alumnes>
  2. <alumne nota="5">Pere Garcia</nota>
  3. <alumne nota="3">Manel Puigdevall</nota>
  4. </alumnes>

Amb <xsl:if> es pot aconseguir posar algun text només en els alumnes que tinguin una nota superior a 5.

  1. <xsl:if test="@nota>=5">
  2. (aprovat)
  3. </xsl>

Hi ha altres funcions per expressar alternatives, com <xsl:choose>, que permet explicitar múltiples alternatives.

  1. <xsl:choose>
  2. <xsl:when select="@nota=10"> (excel·lent) </xsl:when>
  3. <xsl:when select="@nota>=5"> (aprovat) </xsl:when>
  4. <xsl:otherwise> (suspès) </xsl:
  5. otherwis
  6. e>
  7. </xsl:choose>
Iteracions

<xsl:for-each> serveix per processar una seqüència de nodes un per un per fer alguna acció en cada un:

  1. <xsl:for-each select="/classe/alumnes/nom">
  2. <xsl:value-of select="."/>
  3. </xsl:for-each>

Altres

Hi ha etiquetes que permeten fer tasques de transformació elaborades per poder ajustar les transformacions als diferents requisits que es puguin donar:

  • Ordenar: <xsl:sort>.
  • Numerar una llista de resultats: <xsl:number>.
  • Crear variables: <xsl:variable>.
  • Passar paràmetres a les plantilles: <xsl:param>, <xsl:with-param>, <xsl:call-template>.
  • Copiar dades directament: <xsl:copy>, <xsl:copy-of>.
  • Carregar XSL des d’altres arxius: <xsl:import> / <xsl:include>.
  • Definir les nostres funcions: <xsl:function>.

En cas que calgui alguna tasca molt específica, és important tenir a mà l’especificació per comprovar si hi ha algun element que pugui simplificar el procés de creació de la plantilla:

A més, com que XSLT està basat en XML també s’hi poden afegir extensions per ampliar-ne les possibilitats a l’hora de fer transformacions. En aquest sentit són bastant populars les extensions que afegeix el grup EXSTL o les del processador Saxon.

Exemple

Per poder traspassar les dades d’un programa a un altre hem de convertir l’estructura d’un document XML en una altra de diferent.

En una editorial reben les comandes dels llibres en un format XML. El format en què es reben les comandes és un XML agrupat per autors com aquest:

  1. <peticio biblioteca="Fantastica SL">
  2. <data>15-11-2011</data>
  3. <autor>
  4. <nom>Frédérik McCloud</nom>
  5. <llibres>
  6. <llibre>
  7. <titol>Les empentes</titol>
  8. <quantitat>2</quantitat>
  9. </llibre>
  10. </llibres>
  11. </autor>
  12. <autor>
  13. <nom>Corsaro Levy</nom>
  14. <llibres>
  15. <llibre>
  16. <titol>Marxant de la font del gat</titol>
  17. <quantitat>1</quantitat>
  18. </llibre>
  19. <llibre>
  20. <titol>Bèstia!</titol>
  21. <quantitat>1</quantitat>
  22. </llibre>
  23. </llibres>
  24. </autor>
  25. </peticio>

Però com que l’editorial té els llibres organitzats per títols i no per autors, volen que es converteixi en un format que els faci més còmode treballar-hi.

L’editorial vol que tingui una part en què s’identifiqui la data de la comanda i el nom de la llibreria i després que hi hagi la llista de llibres. L’equivalent de l’arxiu anterior seria aquest:

  1. <comanda>
  2. <llibreria data="15-11-2011">Fantastica SL</llibreria>
  3. <llibre quantitat="2">
  4. <nom>Les empentes</nom>
  5. <autor>Frédérik McCloud</autor>
  6. </llibre>
  7. <llibre quantitat="1">
  8. <nom>Marxant de la font del gat</nom>
  9. <autor>Corsaro Levy</autor>
  10. </llibre>
  11. <llibre quantitat="1">
  12. <nom>Bèstia!</nom>
  13. <autor>Corsaro Levy</autor>
  14. </llibre>
  15. </comanda>

Resolució

Es crea un arxiu amb la capçalera XML i s’hi defineix l’arrel dels fitxers XSLT.

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3. version="2.0">
  4.  
  5. </xsl:stylesheet>

Com que es vol tenir totalment controlada tota la sortida el més fàcil és capturar tot el document amb una plantilla que capturi l’arrel.

  1. <xsl:template match="/">
  2.  
  3. </xsl:template>

Dins d’aquesta plantilla ja es pot definir la primera part de l’estructura del document, l’arrel <comanda> i l’element <llibreria>. En ser definits de nou no cal obtenir les dades del fitxer i es poden especificar com a literals.

  1. <xsl:template match="/">
  2. <comanda>
  3. <llibreria>
  4.  
  5. </llibreria>
  6.  
  7. </comanda>
  8. </xsl:template>

Dins d’aquesta plantilla caldrà aconseguir la llista de tots els llibres i les dades de la llibreria. Com que s’ha capturat l’arrel, les dades de l’etiqueta <llibreria> són fàcils d’aconseguir amb XPath:

  • El nom de la llibreria està a /peticio/@llibreria.
  • La data de la petició a /peticio/data.

Com que la data ha d’estar en un atribut, la posem dins d’un element <xsl:attribute> en el qual es defineix el nom dia:

  1. <xsl:template match="/">
  2. <comanda>
  3. <llibreria>
  4. <xsl:attribute name="dia">
  5. <xsl:value-of select="/peticio/data"/>
  6. </xsl:attribute>
  7. <xsl:value-of select="/peticio/@llibreria"/>
  8. </llibreria>
  9. </comanda>
  10. </xsl:template>

Si provem el codi que hem fet veurem que ja genera la primera part del que es vol obtenir. Apareix l’element llibreria i té els valors del document.

  1. <comanda>
  2. <llibreria data="15-11-2011">Fantastica SL</llibreria>
  3. </comanda>

Només ens falta obtenir la llista de llibres. Com que es tracta d’una repetició de dades ho podem fer de dues maneres, amb un for-each o cridant una plantilla nova amb apply-templates que s’encarregui de fer cada llibre.

El més simple és fer-ho amb una plantilla a la qual anirem passant els nodes <titol> del document, i a partir d’aquests nodes obtindrem les dades.

Per tant darrere del tancament de l’element <llibreria> es fa una crida a una plantilla que capturarà tots els elements <titol> del document (en XPath ho podem expressar com ''//titol'':

  1. <xsl:apply-templates select="//titol"/>

Falta definir la plantilla que rebrà la llista d’elements <titol>. Com que tots els títols estan dins d’una etiqueta <llibre> ja es pot definir:

  1. <xsl:template match="titol">
  2. <llibre>
  3. </llibre>
  4. </xsl:template>

Els valors que ens calen es poden aconseguir fàcilment:

  • El títol és el valor del node en el qual estem. O sigui, en XPath seria .
  • La quantitat de llibres demanats és el node germà del qual estem. Per tant, reculem fins al pare amb .. i després entrem en el node quantitat. L’expressió XPath és ../quantitat.
  • El nom de l’autor es pot aconseguir amb una expressió una mica més llarga. Cal recular tres nivells fins a arribar al node <autor>, com es pot veure en la figura (figura). Per tant, l’expressió XPath serà ../../../nom.
Figura Per obtenir l’autor reculem tres nivells i entrem a nom

Només falta emplenar les dades dins de la nova plantilla: posar la quantitat com a atribut i crear les noves etiquetes per a l’autor i el títol, que podem definir com a literals.

  1. <xsl:template match="titol">
  2. <llibre>
  3. <xsl:attribute name="quantitat">
  4. <xsl:value-of select="../quantitat"/>
  5. </xsl:attribute>
  6.  
  7. <nom><xsl:value-of select="."/></nom>
  8. <autor><xsl:value-of select="../../../nom"/></autor>
  9. </llibre>
  10. </xsl:template>

La plantilla final quedarà d’aquesta manera:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3. version="2.0">
  4. <xsl:output indent="yes"/>
  5. <xsl:template match="/">
  6. <comanda>
  7. <llibreria>
  8. <xsl:attribute name="data">
  9. <xsl:value-of select="peticio/data"/>
  10. </xsl:attribute>
  11. <xsl:value-of select="peticio/@llibreria"/>
  12. </llibreria>
  13. <xsl:apply-templates select="//titol"/>
  14. </comanda>
  15. </xsl:template>
  16.  
  17. <xsl:template match="titol">
  18. <llibre>
  19. <xsl:attribute name="quantitat">
  20. <xsl:value-of select="../quantitat"/>
  21. </xsl:attribute>
  22. <nom><xsl:value-of select="."/></nom>
  23. <autor><xsl:value-of select="../../../nom"/></autor>
  24. </llibre>
  25. </xsl:template>
  26. </xsl:stylesheet>
Anar a la pàgina anterior:
Exercicis d'autoavaluació
Anar a la pàgina següent:
Activitats