Travaux pratiques XSLT

L'objectif de ces travaux pratiques est de vous familiariser avec XSLT qui est un langage de programmation permettant d'effectuer des transformations sur des documents XML. Un programme XSLT est lui-même un document XML respectant la DTD de XSLT.

Documentation

Pour réaliser ces TP, vous pouvez utiliser la documentation courte de XML et de XSLT ou les documentations officielles qui se trouvent sur le site du W3C, à la rubrique XSLT.

Un tutoriel en ligne très bien fait sur XSLT se trouve ici. Un autre sur XPath . Vous pouvez commencer le TP et revenir à ces tutoriels si vous êtes bloqué, où commencer par ces tutoriels avant de commencer le TP.

Fichier XML exemple

Les exercices de ce TP vont utiliser un fichier XML exemple qui contient une liste commerciale de presse-fruits. Ce fichier s'appelle juicers.xml et peut être récupéré ici. Il utilise une DTD, juicers.dtd, qui peut être récupérée ici.

Récupérez ces deux fichiers et essayer de charger le fichier juicers.xml dans un navigateur Web pour examiner sa structure. Chargez ensuite le fichier dans un éditeur de texte, afin de pouvoir l'éditer. N'importe quel éditeur de texte (Notepad, Emacs, vi, Textedit) fera l'affaire.

Exemple de transformation XSLT

Voici un exemple de programme XSLT qui permet de transformer le document XML contenant des presse-fruits en une liste de ces presse-fruits au format HTML. Ce fichier s'appelle jlist.xsl.

      <?xml version="1.0" encoding="utf-8"?>
      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
		      version="1.0">
	
	<xsl:output method="html" encoding="iso-8859-1"/>
	
	<xsl:template match="/">
	  <html>
	    <head>
	      <title>Juicers List</title>
	    </head>
	    <body>
	      <ul>
		<xsl:for-each select="/juicers/juicer">
		  <li><xsl:value-of select="name"/></li>
		</xsl:for-each>
	      </ul>
	    </body>
	  </html>
	</xsl:template>
      </xsl:stylesheet>
    

Pour effectuer la transformation, il est possible d'utiliser un outil de transformation comme xsltproc, saxon ou xalan, mais la solution la plus simple est de faire effectuer cette transformation par un navigateur web, comme Internet Explorer, Safari, Firefox, Mozilla ou Opera. Pour cela, il suffit d'ajouter la ligne suivante au début de votre fichier XML juicers.xml:

      <?xml-stylesheet href="jlist.xsl" type="application/xml"?>
    

Ainsi, les quatre premières lignes de votre fichier juicers.xml doivent ressembler à ceci:

      <?xml version="1.0" encoding="utf-8"?>
      <?xml-stylesheet href="jlist.xsl" type="application/xml"?>
      <!DOCTYPE juicers SYSTEM "juicers.dtd">
      <juicers>
    

Transformation avec xsltproc

Vous pouvez également faire les transformations statiquement avec xsltproc. Cette commande est normalement disponible sous votre environnement par l'intermédiaire de l'interpréteur de commande.

Voici un exemple d'utilisation :

      xsltproc -o juicers-list.html jlist.xsl juicers.xml
    

La commande précédente créé un fichier juicers-list.html en appliquant le script XSLT jlist.xsl au document XML juicers.xml.

Exercices

  1. Générez un document juicers-table.html à l'aide d'un programme XSLT juicers-table.xsl.

  2. Générez un document HTML contenant une table avec le coût de chaque presse-fruit sur le modele de juicers-cost-table.html à l'aide d'un fichier juicers-cost-table.xsl.

  3. Générez un document HTML juicers-cost-description.html avec deux tables, une avec le nom du presse-fruit et son coût, une autre avec la description du presse-fruit (juicers-cost-description.xsl).

  4. Créez un document HTML hyperlinked-cost-description-tables.html reprenant celui de la question precedente mais avec des liens entre un presse-fruit dans la première table et ce même presse-fruit dans la seconde (hyperlinked-cost-description-tables.xsl).

    Pour faire cette exercice, vous aurez besoin de la notation {expression-xpath} qui permet de récupérer une valeur depuis le document XML (comme la fonction XSL <xsl:value-of select="...">) dans des guillemets. Par exemple:

    	    <a href="{@id}-COST"/>
    	  

    {@id} renvoie le meme resultat que la commande XSLT <xsl:value-of select="@id"/>

  5. Même chose que pour la question precedente mais en rajoutant des images pour chaque presse-fruit (hyperlinked-tables-with-images.html, hyperlinked-tables-with-images.xsl)

    Vous trouverez un fichier TAR des images ICI.

  6. Écrivez un script XSL permettant de générer une page HTML affichant le coût moyen d'un presse-fruit. Voilà à quoi doit ressembler votre résultat:

    	    Total number of juicers = 6
    	    Cost of all juicers = 1696.93
    	    The average cost of the juicers = $282.82 
    	  

    Vous pouvez utiliser l'instruction XSLT <xsl:variable name="x" select="..."/> pour déclarer des variables dans votre script. La récupération d'une valeur préalablement stockée dans une variable se fait en rajoutant un signe $ devant le nom de cette variable dans une expression XPath.

    Pour faire cet exercice, vous devrez utiliser les fonction XPath count() et sum(). Pour formater un nombre de telle façon a ce qu'il ait deux chiffres après la virgule et un signe $ devant lui, utilisez la fonction XPath: format-number($avgCost, '$#.00'). Par exemple:

    	    <xsl:value-of select="count(/juicers/juicer)"/>
    	  

    donne le nombre d'éléments juicer dans le fichier XML.

  7. le but de cette partie est d'écrire un script getElectricJuicers.xsl permettant de générer un document HTML contenant une liste des presse-fruits qui sont électriques.

    Le but de cet exercice est d'utiliser les variables XML et l'instruction xsl:if. Votre sortie doit ressembler à:

    	    This juicer is electric: Champion Juicer
    	    This juicer is electric: Green Power Gold Juice Extractor
    	    This juicer is electric: Juiceman Jr.
    	    This juicer is electric: Omega Juicer
    	    This juicer is electric: Wheateena Wheatgrass Juicer
    	  

    C'est-à-dire que pour chaque presse-fruits vous devez écrire "This juicer is electric:" suivi de son nom. Voici comment implémenter ceci:

    	    Pour chaque presse-fruits
    	    - Récupérer son nom et le stocker dans une variable
    	    - Récupérer la valeur de l'élément/attribut indiquant si 
    	    il est électrique ou non et la stocker dans une variable
    	    - Tester la valeur de la variable "est_electrique" pour 
    	    déterminer si le presse-fruits est électrique. Si oui:
    	    - Afficher le texte "The juicer is electric:"
    	    - Afficher la valeur de la variable contenant le nom
    	    - Afficher un saut de ligne HMTL
    	  
  8. Dans cette partie, il vous est demandé d'écrire un script XSLT (doesItContainThisJuicers.xsl) permettant de déterminer si la liste des presse-fruits contient les appareils Champion, Omega et Ultrex. Générez un fichier HTML avec le résultat de votre requête pour chaque appareil demandé.

    Le but ici est d'utiliser les variables XSL et la fonction contains(). Vous allez créer une variable contenant la liste de tous les noms de presse-fruits (séparés par des ~) présents dans le document XML. Il faut ensuite déterminer si cette liste contient Champion, Omega et Ultrex.

    Il vous est demandé d'afficher le contenu de la variable contenant la liste de tous les presse-fruits. Ensuite, voud devrez afficher une ligne pour chaque presse-fruits qui vous intéresse. Voici à quoi doit ressembler la sortie:

    	    Juicer List: OJ Home Juicer~Champion Juicer~Green Power Gold Juice Extractor~Juiceman Jr.~Omega Juicer~Wheateena Wheatgrass Juicer
    	    - contient Champion
    	    - contient Omega
    	    - ne contient pas Ultrex
    	  

    Notez qu'il n'y a pas de ~ après le dernier presse-fruits.

    L'instruction XSLT xsl:variable utilisée sous cette forme peut vous être utile:

    	    <xsl:variable name="mavariable">
    	    ... contenu de la variable ...
    	    </xsl:variable>
    	  
  9. Il y a plusieurs façon d'identifier un aéroport: par son code ICAO (par exemple BOS est le code ICAO pour Boston) ou encore par la latitude/longitude (par exemple 74.3N, 123.0W pour l'aéroport de Boston).

    Voici le fichier airports.xml qui contient une liste d'aéroports.

    Le contenu d'un élément location est une chaîne de caractères pouvant prendre deux formes: ICAO: code ou LatLon: valeur. Pour cet exercice vous allez créer un document HTML qui ressemblera à ceci (notez que vous devez convertir le caractères en majuscules):

    	    ICAO = BOS
    	    LatLon = 74.31W, 106.5N
    	    ICAO = SLT
    	    ICAO = MOL
    	    Erreur! Les données doivent être: ICAO: code ou LatLon: valeur
    	    LatLon = 43.01W, 116.8N
    	  
  10. Le prix des presse-fruits augmente régulièrement. Un document XML séparé (priceAdjuster.xml) est utilisé pour spécifier l'ajustement de prix devant être effectué sur un presse-fruit (cet exemple n'effectue pas d'ajustement). Le fichier priceAdjuster2.xml ne spécifie une modification de prix.

    Vous devez dans cet exercice créer un document HTML contenant une table des presse-fruits. La différence est que le prix doit être ajusté en fonction du fichier priceAdjuster.xml. Lorsque vous aurez écrit votre script, testez-le avec priceAdjuster.xml etpriceAdjuster2.xml.

    Aide : il existe une commande XPath (document()) permettant de lire un fichier externe. Cette commande peut-être utilisée de la façon suivante:

    	    <xsl:variable name="priceAdjuster" select="document('priceAdjuster.xml')"/>
    	  

    Une fois cette variable définie, elle peut être utilisée comme racine dans une expression XPath:

    	    <xsl:if test="$priceAdjuster/priceAdjustment/adjustment/@action='no change'">
    	    ...
    	    </xsl:if>
    	  
  11. En XSL, il est possible de créer des templates nommés acceptant des paramètres. Par exemple, voici un template appelé createJuicerCostTable qui a un paramètre sizeIncrease qui est positionné par défaut à 0:

    	    <xsl:template name="createJuicerCostTable">
    	    <xsl:param name="sizeIncrease" select="0"/>
    	    ...
    	    </xsl:template>
    	  

    Une fois ce template défini, il est possible de l'appeler depuis un autre template avec les instructions XSL suivantes:

    	    <xsl:call-template name="createJuicerCostTable">
    	    <xsl:with-param name="sizeIncrease" select="10"/>
    	    </xsl:call-template>
    	  

    Reprenez l'exercice précédent en écrivant le template nommé createJuicerCostTable qui va écrire le tableau HTML.

  12. Modifiez le script identity.xsl pour qu'il mette le nom des attributs et éléments de tout fichier XML en majuscules, sans modifier les données du fichier.

  13. Le fichier Classified.xml contient des données à transmettre mais certaines de ces données sont classées "top secret". Écrivez un script XSL qui produit un nouveau fichier XML où tout ce qui est classé "top secret" est absent.

  14. Votre société de production de presse-fruits utilise en interne la DTD juicers.dtd. Le CFPF (Consortium des Fabricants de Presse-Fruits) s'est mis d'accord sur une représentation commune des catalogues de presse-fruits pour faciliter l'échange d'information. Voici à qui ressemble la nouvelle représentation: juicer-transformed.xml. Écrivez un script XSL qui permet de transformer votre représentation interne ( juicers.xml) en cette nouvelle représentation.

  15. Écrire un script XSL qui permet de récupérer tous les éléments PERSONAE ainsi que leurs sous-éléments du fichier AllsWellThatEndsWell.xml. Le fichier résultat doit ressembler à ceci:

    	    <?xml version="1.0"?>
    	    <PERSONAE>       
    	    <PERSONA>KING OF FRANCE</PERSONA>
    	    <PERSONA>DUKE OF FLORENCE</PERSONA>
    	    <PERSONA>BERTRAM, Count of Rousillon.</PERSONA>
    	    <PERSONA>LAFEU, an old lord.</PERSONA>
    	    </PERSONAE>
    	  
  16. Écrire un script XSL qui permet d'obtenir le fichier juicers-new.xml. Vous devez utiliser l'attribut mode de l'élément xsl:template: vous devez utiliser deux patrons pour traiter l'élément juicer, un contenant juste le nom et un second contenant le nom, un / et le prix du presse-fruits.

  17. Écrivez une page XHTML à laquelle vous associerez une feuille de style qui va récupérer les dix derniers articles de flux RSS d'un ou de plusieurs quotidiens (Le Monde, Le Figaro, La Croix, Libération, l'humanité, etc.). Le nom cliquable de ces articles sera placé dans une liste affichée dans la page XHTML. Lorsque l'utilisateur cliquera sur le nom d'un article, il pourra retrouver l'intégralité de l'article sur le site d'origine.

Corrigés

  1. juicers-table.xsl
  2. juicer-cost-table.xsl
  3. hyperlinked-cost-description-tables.xsl
  4. hyperlinked-tables-with-images.xsl
  5. averageCost.xsl
  6. getElectricJuicers.xsl
  7. doesItContainTheseJuicers.xsl
  8. airports.xsl
  9. juicer-cost-table-adjust.xsl
  10. juicer-cost-table-adjust2.xsl
  11. identity.xsl
  12. Classified.xsl
  13. juicerTransformer.xsl
  14. AllsWellThatEndsWell.xsl
  15. juicers-mode.xsl