XSLT Travaux Pratiques

Inria

Comprenez XPath

Transformez un document XML en HTML.

Info Le saviez-vous ?

Cette page (et le reste du site) est entièrement générée avec XSLT !

Prérequis

  • HTML
  • CSS pour faire joli
  • Javascript pour se démarquer

Cours

  • XPath
  • XSLT

Problèmes XPath

Opérations ensemblistes

Il n'y a pas d'opérateurs ensemblistes dans XPath, en revanche, on peut facilement les obtenir. A quelle opération ensembliste correspond chacune des expressions suivantes ?

$node-set1 | $node-set2

L'union de deux ensembles

$node-set1[count(. | $node-set2) != count($node-set2)]

Dans un node-set, chaque nœud est unique (et ne peut être compté deux fois)
L'exclusion

$node-set1[count(. | $node-set2) != count($node-set2)] | $node-set2[count(. | $node-set1) != count($node-set1)]

L'exclusion mutuelle

Inégalité et différence

Que retournent à partir de ce document :

//a/item[2] = //b/item ?

Vrai : il existe un item correspondant dans l'ensemble <b>

//a/item[2] != //b/item ?

Vrai aussi ! il existe un item dans l'ensemble <b> qui ne correspond pas

Comment obtenir {a} - {b} ? Utilisez ce testeur XPath

//a/item[not(. = //b/item)]

<data>
    <a>
        <item>1</item>
        <item>2</item>
        <item>3</item>
        <item>4</item>
        <item>5</item>
    </a>
    <b>
        <item>2</item>
        <item>3</item>
        <item>4</item>
        <item>6</item>
        <item>7</item>
    </b>
</data>

Select distinct

Ecrire une requête XPath qui fasse un "select distinct" sur les catégories dans ce document :

Utilisez ce testeur XPath

Il faut comparer chaque noeud avec les noeuds précédents (voir les axes XPath)
//category[not(. = preceding::category)]
<dataset>
    <node>
        <category>C1</category>
    </node>
    <node>
        <category>C2</category>
    </node>
    <node>
        <category>C1</category>
    </node>
    <node>
        <category>C3</category>
    </node>
    <node>
        <category>C1</category>
    </node>
    <node>
        <category>C2</category>
    </node>
    <node>
        <category>C1</category>
    </node>
    <node>
        <category>C3</category>
    </node>
</dataset>

Transformation avec XSLT

Zoo

On dispose du document XML :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE zoo SYSTEM "zoo.dtd" [
    <!ENTITY % notations SYSTEM "notations.ent">
%notations;
    <!ENTITY flipper.jpg SYSTEM "flipper.jpg" NDATA jpg>
    <!ENTITY oum.jpg SYSTEM "oum.jpg" NDATA jpg>
    <!ENTITY ecco.jpg SYSTEM "ecco.jpg" NDATA jpg>
]>
<!-- Un petit Zoo avec quelques animaux -->
<zoo>
    <info>Ouvert tous les jours de 8h00 à 19h00</info>
    <info><img src="nourrir.gif" />Il est <b>interdit</b> de nourrir les animaux&#127;&#128;.</info>
    <aquarium>
        <mammifères-marins>
            <dauphins>
                <dauphin id="jhgtr13" photo="flipper.jpg" date-naissance="1997-4-1">
                    <nom>Flipper</nom>
                    <sexe>M</sexe>
                    <taille unité="cm">215</taille>
                    <poids unité="kg">105</poids>
                </dauphin>
                <dauphin id="lkjh45" photo="ecco.jpg" date-naissance="2003-10-23">
                    <nom>Ecco</nom>
                    <sexe>F</sexe>
                    <taille unité="cm">202</taille>
                    <poids unité="kg">98</poids>
                </dauphin>
                <dauphin id="kjlhy90" photo="oum.jpg" date-naissance="1996-12-25">
                    <nom>Oum</nom>
                    <sexe>F</sexe>
                    <!-- c'est mon préféré -->
                    <taille unité="cm">295</taille>
                    <poids unité="kg" status="mesure approximative">190<!-- il faut refaire la pesée --></poids>
                </dauphin>
            </dauphins>
        </mammifères-marins>
        <poissons>
            <sélaciens>
                <danger>Il est <b>interdit</b> de nager avec les requins.</danger>
                <requin id="plojk09" espèce="marteau" date-naissance="1998-6-5">
                    <nom>Oussama</nom>
                    <sexe>M</sexe>
                    <taille unité="cm">455</taille>
                    <poids unité="kg">540</poids>
                    <commentaire>A tendance a se jeter contre les murs
                        <![CDATA[<<< marteau & cinglé !!! >>>]]>
                        <!-- Il faudra bien le faire piquer un jour -->
                    </commentaire>
                </requin>
                <requin id="vgyuh43" espèce="requin bleu" nom-savant="carcharias glaucus" date-naissance="2004-1-13">
                    <nom>Saddam</nom>
                    <sexe>M</sexe>
                    <taille unité="cm">355</taille>
                    <poids unité="kg" status="">425</poids>
                </requin>
            </sélaciens>
        </poissons>
    </aquarium>
</zoo>

et de sa DTD :

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!ENTITY nourrir.gif SYSTEM "nourrir.gif" NDATA gif>

<!ENTITY % block "p | info | danger | attention">
<!ENTITY % inline "b | i | em | strong | stabilo | img">
<!ENTITY % attractions "aquarium?, vivarium?, enclos?, volière?">
<!ENTITY % animal "nom, sexe, taille, poids, commentaire?">
<!ENTITY % animal-attr "
    id		ID #REQUIRED
    espèce		CDATA #IMPLIED
    nom-savant	CDATA #IMPLIED
    photo		ENTITY #IMPLIED
    date-naissance  CDATA #REQUIRED
">
<!ENTITY % u-attr "
    unité		CDATA #REQUIRED
    status		CDATA #IMPLIED
">

<!ELEMENT p (#PCDATA | %inline;)*>
<!ELEMENT info (#PCDATA | %inline;)*>
<!ELEMENT danger (#PCDATA | %inline;)*>
<!ELEMENT attention (#PCDATA | %inline;)*>

<!ELEMENT b (#PCDATA | %inline;)*>
<!ELEMENT i (#PCDATA | %inline;)*>
<!ELEMENT em (#PCDATA | %inline;)*>
<!ELEMENT strong (#PCDATA | %inline;)*>
<!ELEMENT stabilo (#PCDATA | %inline;)*>
<!ELEMENT img EMPTY>
<!ATTLIST img src ENTITY #REQUIRED>

<!ELEMENT zoo ((%block;)*, %attractions;)>

<!ELEMENT aquarium (mammifères-marins?, poissons?)>
<!ELEMENT mammifères-marins (dauphins?, baleines?, orques?)>
<!ELEMENT poissons (sélaciens?)>

<!ELEMENT vivarium (serpents?, arachnéens?)>
<!ELEMENT serpents (boas?)>
<!ELEMENT arachnéens (mygales?)>

<!ELEMENT enclos (primates?, fauves?)>
<!ELEMENT primates (gorilles?, orangs-outans?)>
<!ELEMENT fauves (tigres?, lions?)>

<!ELEMENT volière (oiseaux-terrestres?, oiseaux-aquatiques?, rapaces?)>
<!ELEMENT oiseaux-terrestres (autruches?)>
<!ELEMENT oiseaux-aquatiques (pingouins?, manchots?)>
<!ELEMENT rapaces (aigles?)*>

<!ELEMENT dauphins (%block; | dauphin)+>
<!ELEMENT dauphin (%animal;)>
<!ATTLIST dauphin %animal-attr;>

<!ELEMENT baleines (%block; | baleine)+>
<!ELEMENT baleine (%animal;)>
<!ATTLIST baleine %animal-attr;>

<!ELEMENT orques (%block; | orque)+>
<!ELEMENT orque (%animal;)>
<!ATTLIST orque %animal-attr;>

<!ELEMENT sélaciens (%block; | requin)+>
<!ELEMENT requin (%animal;)>
<!ATTLIST requin %animal-attr;>

<!ELEMENT boas (%block; | boa)+>
<!ELEMENT boa (%animal;)>
<!ATTLIST boa %animal-attr;>

<!ELEMENT mygales (%block; | mygale)+>
<!ELEMENT mygale (%animal;)>
<!ATTLIST mygale %animal-attr;>

<!ELEMENT gorilles (%block; | gorille)+>
<!ELEMENT gorille (%animal;)>
<!ATTLIST gorille %animal-attr;>

<!ELEMENT orangs-outans (%block; | orang-outan)+>
<!ELEMENT orang-outan (%animal;)>
<!ATTLIST orang-outan %animal-attr;>

<!ELEMENT tigres (%block; | tigre)+>
<!ELEMENT tigre (%animal;)>
<!ATTLIST tigre %animal-attr;>

<!ELEMENT lions (%block; | lion)+>
<!ELEMENT lion (%animal;)>
<!ATTLIST lion %animal-attr;>

<!ELEMENT autruches (%block; | autruche)+>
<!ELEMENT autruche (%animal;)>
<!ATTLIST autruche %animal-attr;>

<!ELEMENT pingoins (%block; | pingoin)+>
<!ELEMENT pingoin (%animal;)>
<!ATTLIST pingoin %animal-attr;>

<!ELEMENT manchots (%block; | manchot)+>
<!ELEMENT manchot (%animal;)>
<!ATTLIST manchot %animal-attr;>

<!ELEMENT aigles (%block; | aigle)+>
<!ELEMENT aigle (%animal;)>
<!ATTLIST aigle %animal-attr;>

<!ELEMENT nom (#PCDATA)>
<!ELEMENT sexe (#PCDATA)>
<!ELEMENT taille (#PCDATA)>
<!ATTLIST taille %u-attr;>

<!ELEMENT poids (#PCDATA)>
<!ATTLIST poids %u-attr;>

<!ELEMENT commentaire (#PCDATA | %block;)*>

qui utilise une entité :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!NOTATION jpg SYSTEM "images/jpeg">
<!NOTATION gif SYSTEM "images/gif">

Le document XML décrit les animaux d'un Zoo. L'objectif est de faire une feuille de style XSLT qui transforme le document source XML en une version publiée en (X)HTML. Tout se passe côté client (dans un prochain tépé, tout se passera côté serveur Web).

Pour commencer avec XSLT

Créez une feuille de style minimaliste qui affiche le corps HTML avec un titre grâce à une règle qui réagit sur la racine du source XML.

Modifiez le source XML pour lui assigner cette feuille de style.

Il suffit d'ajouter dans le document XML source juste après la déclaration <?xml?> l'instruction de traitement suivante qui sera interprêtée par le navigateur :

<?xml-stylesheet type="text/xsl" href="zoo.xsl"?>

Chargez le document dans le navigateur.

Youpi, ça marche.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output method="html"/>

    <xsl:template match="/">
        <html>
            <head>
                <title>Zoo</title>
                <link href="zoo.css" rel="stylesheet" type="text/css"/>
            </head>
            <body>
                <h1>Bienvenue au Zoo</h1>
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>

Ajoutez des règles à votre feuille de style pour qu'elle transforme le contenu en (X)HTML en utilisant ces ressources.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output method="html"/>

    <xsl:template match="/">
        <html>
            <head>
                <title>Zoo</title>
                <link href="zoo.css" rel="stylesheet" type="text/css"/>
            </head>
            <body>
                <h1>Bienvenue au Zoo</h1>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="info|attention|danger">
        <xsl:choose>
            <xsl:when test="parent::dauphins or parent::sélaciens">
                <tr>
                    <td colspan="6"><xsl:call-template name="avertissement"/></td>
                </tr>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="avertissement"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="avertissement">
	<table class="{name()}" align="center">
            <tr>
                <td><img src="{name()}.gif" /></td>
                <td><xsl:apply-templates /></td>
            </tr>
	</table>
    </xsl:template>

    <xsl:template match="b"><b><xsl:apply-templates /></b></xsl:template>
    <xsl:template match="i"><i><xsl:apply-templates /></i></xsl:template>
    <xsl:template match="em"><em><xsl:apply-templates /></em></xsl:template>
    <xsl:template match="strong"><strong><xsl:apply-templates /></strong></xsl:template>

    <xsl:template match="dauphins|sélaciens">
        <h2><xsl:value-of select="name()" /></h2>
        <table border="1">
            <tr>
                <th>Nom</th>
                <th>Date naissance</th>
                <th>Type</th>
                <th>Taille</th>
                <th>Poids</th>
                <th>Sexe</th>
            </tr>
            <xsl:apply-templates/>
        </table>
    </xsl:template>

    <xsl:template match="dauphin|requin">
	<tr>
            <td><xsl:value-of select="nom" /></td>
            <td><xsl:value-of select="@date-naissance" /></td>
            <td><xsl:value-of select="@espèce" /><br /><i><xsl:value-of select="@nom-savant" /></i></td>
            <td><xsl:value-of select="taille" />&#160;<xsl:value-of select="taille/@unité" /></td>
            <td><xsl:value-of select="poids" />&#160;<xsl:value-of select="poids/@unité" /></td>
            <td><xsl:value-of select="sexe" /></td>
            <xsl:if test="@photo">
                <td><img src="{@photo}" alt="{nom}" /></td>
            </xsl:if>
	</tr>
    </xsl:template>

</xsl:stylesheet>

Aide Voir le code HTML

Un navigateur peut afficher le résultat HTML d'une transformation XSLT. Le problème est que le code HTML produit n'est pas visible (il est gardé jalousement par le navigateur qui se contente de le consommer pour formatter l'affichage).

Une solution alternative :

  • est d'utiliser un processeur XSLT utilisable en ligne de commande, qui permet de sauver dans un fichier le résultat HTML produit. Par exemple, XSLTPROC peut s'utiliser comme ceci : xsltproc stylesheet.xsl input.xml
  • est de compiler cette qui s'utilise comme cela :
    java TestXSLT stylesheet.xsl input.xml et qui affiche le résultat sur la sortie standard.

Problème Le navigateur n'affiche rien

Un document XML associé à sa feuille de style XSLT avec la PI appropriée est supposée être mis en forme dans le navigateur. Tout cela fonctionne bien avec un document hébergé sur un serveur Web, mais peut ne pas fonctionner pour un fichier local.

Les navigateurs embarquent une règle, la "same origin policy" (SOP) qui leur interdit d'exécuter un script sur des données ne provenant pas du même site Web. Cette règle est précieuse car par exemple elle empêche à un pirate d'accéder à vos coordonnées bancaires ! Elle concerne non seulement les scripts Javascript, mais les scripts XSLT également.

Malheureusement, certains navigateurs Web trop zélés considèrent qu'il ne faut pas faire confiance à un script chargé depuis un fichier local. C'est pourquoi ceux-là n'affichent rien.

Pour ces exercices il faut alors soit utiliser un autre navigateur, soit utiliser un outil en ligne de commande pour procéder à la transformation.

Introduction d'espaces de noms

On veut séparer ce qui est documentaire (les éléments <img>, <b>, <info>, <danger>, <commentaire>, etc) de ce qui est structure de données (les autres éléments).

Déclarez et utilisez dans le document XML source 2 espaces de nommage pour identifier ces 2 familles. Vous n'utiliserez pas de préfixe pour les éléments de structures de données, vous en utiliserez un pour les éléments documentaires. Utilisez un URN et un URL pour les 2 URIs d'espace de nom.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE zoo SYSTEM "zoo.dtd" [
    <!ENTITY % notations SYSTEM "notations.ent">
%notations;
    <!ENTITY flipper.jpg SYSTEM "flipper.jpg" NDATA jpg>
    <!ENTITY oum.jpg SYSTEM "oum.jpg" NDATA jpg>
    <!ENTITY ecco.jpg SYSTEM "ecco.jpg" NDATA jpg>
]>
<!-- Un petit Zoo avec quelques animaux -->
<zoo xmlns="urn:unice:master-2004-2005" xmlns:doc="http://www.unice.fr/master/2004-2005">
    <doc:info>Ouvert tous les jours de 8h00 à 19h00</doc:info>
    <doc:attention>Il est <doc:b>interdit</doc:b> de nourrir les animaux.</doc:attention>
    <aquarium>
        <mammifères-marins>
            <dauphins>
                <dauphin id="jhgtr13" photo="flipper.jpg" date-naissance="1997-4-1">
                    <nom>Flipper</nom>
                    <sexe>M</sexe>
                    <taille unité="cm">215</taille>
                    <poids unité="kg">105</poids>
                </dauphin>
                <dauphin id="lkjh45" photo="ecco.jpg" date-naissance="2003-10-23">
                    <nom>Ecco</nom>
                    <sexe>F</sexe>
                    <taille unité="cm">202</taille>
                    <poids unité="kg">98</poids>
                </dauphin>
                <dauphin id="kjlhy90" photo="oum.jpg" date-naissance="1996-12-25">
                    <nom>Oum</nom>
                    <sexe>F</sexe>
                    <!-- c'est mon préféré -->
                    <taille unité="cm">295</taille>
                    <poids unité="kg" status="mesure approximative">190<!-- il faut refaire la pesée --></poids>
                </dauphin>
            </dauphins>
        </mammifères-marins>
        <poissons>
            <sélaciens>
                <doc:danger>Il est <doc:b>interdit</doc:b> de nager avec les requins.</doc:danger>
                <requin id="plojk09" espèce="marteau" date-naissance="1998-6-5">
                    <nom>Oussama</nom>
                    <sexe>M</sexe>
                    <taille unité="cm">455</taille>
                    <poids unité="kg">540</poids>
                    <doc:commentaire>A tendance a se jeter contre les murs
                        <![CDATA[<<< marteau & cinglé !!! >>>]]>
                        <!-- Il faudra bien le faire piquer un jour -->
                    </doc:commentaire>
                </requin>
                <requin id="vgyuh43" espèce="requin bleu" nom-savant="carcharias glaucus" date-naissance="2004-1-13">
                    <nom>Saddam</nom>
                    <sexe>M</sexe>
                    <taille unité="cm">355</taille>
                    <poids unité="kg" status="">425</poids>
                </requin>
            </sélaciens>
        </poissons>
    </aquarium>
</zoo>

Que fait le parseur XML lorsqu'il rencontre votre URL d'espace de nom ?

  1. Il en parle à son parfrère.
  2. Rien.
  3. Il essaye de lire la DTD à l'adresse indiquée.
  4. Il est obligé de trouver la DTD à l'adresse indiquée, sinon ça plante.
  5. Il vous averti qu'il s'agit d'un site de fesses; vous êtes content de pouvoir compléter votre collection de photos.
Rien. Les URIs font juste partie du nom des éléments et des attributs qui les utilisent.

Rechargez le document dans le navigateur.

Le document associé à XSLT

Que constatez-vous ? Pourquoi ?

L'affichage n'est plus celui souhaité.

En ajoutant des déclarations <zoo xmlns="...">, tous les éléments sont associés à cet espace de nommage; or la feuille de style ne traite que des éléments sans espace de nommage, donc peu de chose devraient être affichées : la règle qui correspond à la racine, puis les règles par défaut qui peuvent s'appliquer (affichage du texte brut).

Pour que la feuille de style XSLT réagisse sur les éléments qui appartiennent à un espace de nommage, il faut faire une déclaration en utilisant un préfixe (c'est une contrainte de XPath). Le fait qu'il y ait ou non un préfixe dans le document source n'a pas d'importance, seul importe le fait que les éléments sont dans un espace de noms, et que les règles XSLT correspondent à ces espaces de noms.

Corrigez votre feuille de style pour qu'elle fonctionne à nouveau.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:zoo="urn:unice:master-2004-2005"
    xmlns:doc="http://www.unice.fr/master/2004-2005"
    exclude-result-prefixes="zoo doc">

    <xsl:output method="html"/>

    <xsl:template match="/">
        <html>
            <head>
                <title>Zoo</title>
                <link href="zoo.css" rel="stylesheet" type="text/css"/>
            </head>
            <body>
                <h1>Bienvenue au Zoo</h1>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="doc:info|doc:attention|doc:danger">
        <xsl:choose>
            <xsl:when test="parent::zoo:dauphins or parent::zoo:sélaciens">
                <tr>
                    <td colspan="6"><xsl:call-template name="doc:avertissement"/></td>
                </tr>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="doc:avertissement"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="doc:avertissement">
	<table class="{local-name()}" align="center">
            <tr>
                <td><img src="{local-name()}.gif" /></td>
                <td><xsl:apply-templates /></td>
            </tr>
	</table>
    </xsl:template>

    <xsl:template match="doc:b"><b><xsl:apply-templates /></b></xsl:template>
    <xsl:template match="doc:i"><i><xsl:apply-templates /></i></xsl:template>
    <xsl:template match="doc:em"><em><xsl:apply-templates /></em></xsl:template>
    <xsl:template match="doc:strong"><strong><xsl:apply-templates /></strong></xsl:template>

    <xsl:template match="zoo:dauphins|zoo:sélaciens">
        <h2><xsl:value-of select="local-name()" /></h2>
        <table border="1">
            <tr>
                <th>Nom</th>
                <th>Date naissance</th>
                <th>Type</th>
                <th>Taille</th>
                <th>Poids</th>
                <th>Sexe</th>
            </tr>
            <xsl:apply-templates/>
        </table>
    </xsl:template>

    <xsl:template match="zoo:dauphin|zoo:requin">
	<tr>
            <td><xsl:value-of select="zoo:nom" /></td>
            <td><xsl:value-of select="@date-naissance" /></td>
            <td><xsl:value-of select="@espèce" /><br /><i><xsl:value-of select="@nom-savant" /></i></td>
            <td><xsl:value-of select="zoo:taille" />&#160;<xsl:value-of select="zoo:taille/@unité" /></td>
            <td><xsl:value-of select="zoo:poids" />&#160;<xsl:value-of select="zoo:poids/@unité" /></td>
            <td><xsl:value-of select="zoo:sexe" /></td>
            <xsl:if test="@photo">
                <td><img src="{@photo}" alt="{zoo:nom}" /></td>
            </xsl:if>
	</tr>
    </xsl:template>

</xsl:stylesheet>

Que remarquez-vous des patterns qui correspondent aux attributs ?

Dans la feuille de style corrigée, les patterns qui correspondent aux attributs restent sans préfixe, car ils n'en n'ont pas dans le document XML source. Or, les éléments non préfixés appartiennent à l'espace de nommage par défaut (xmlns="..."), mais les attributs sans préfixes n'appartiennent jamais à un espace de nommmage; donc on peut (on doit) les adresser sans préfixe dans XSLT.

Imports de règles

On veut que les mois des dates apparaissent en clair, c'est à dire sous la forme "15 mars 2004" au lieu de "2004-03-15". On utilise cette librairie qui fait ça très bien.

Est-ce que cette feuille de style peut-être distribuée sur la planète sans problème ? Pourquoi ?

On ne peut raisonnablement pas distribuer cette feuille de style sur internet.

La feuille de style déclare l'espace de nommage suivant : xmlns:date="*** Processing dates ***". Bien que valide (le parseur ne vérifie pas la consistance de l'URI de l'espace de nom), on ne peut pas dire qu'il s'agisse d'un identificateur universel : quelqu'un pourrait avoir la même (mauvaise) idée ; il y a donc, potentiellement, un risque de collision de noms.

Utilisez des URIs à la place.

Faites les adaptations nécessaires à votre feuille de style pour que les dates apparaissent en clair.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:zoo="urn:unice:master-2004-2005"
    xmlns:doc="http://www.unice.fr/master/2004-2005"
    xmlns:date="*** Processing dates ***"
    exclude-result-prefixes="zoo doc date">

    <xsl:import href="dates.xsl"/>
    <xsl:output method="html"/>

    <xsl:template match="/">
        <html>
            <head>
                <title>Zoo</title>
                <link href="zoo.css" rel="stylesheet" type="text/css"/>
            </head>
            <body>
                <h1>Bienvenue au Zoo</h1>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="doc:info|doc:attention|doc:danger">
        <xsl:choose>
            <xsl:when test="parent::zoo:dauphins or parent::zoo:sélaciens">
                <tr>
                    <td colspan="6"><xsl:call-template name="doc:avertissement"/></td>
                </tr>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="doc:avertissement"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="doc:avertissement">
	<table class="{local-name()}" align="center">
            <tr>
                <td><img src="{local-name()}.gif" /></td>
                <td><xsl:apply-templates /></td>
            </tr>
	</table>
    </xsl:template>

    <xsl:template match="doc:b"><b><xsl:apply-templates /></b></xsl:template>
    <xsl:template match="doc:i"><i><xsl:apply-templates /></i></xsl:template>
    <xsl:template match="doc:em"><em><xsl:apply-templates /></em></xsl:template>
    <xsl:template match="doc:strong"><strong><xsl:apply-templates /></strong></xsl:template>

    <xsl:template match="zoo:dauphins|zoo:sélaciens">
        <h2><xsl:value-of select="local-name()" /></h2>
        <table border="1">
            <tr>
                <th>Nom</th>
                <th>Date naissance</th>
                <th>Type</th>
                <th>Taille</th>
                <th>Poids</th>
                <th>Sexe</th>
            </tr>
            <xsl:apply-templates/>
        </table>
    </xsl:template>

    <xsl:template match="zoo:dauphin|zoo:requin">
	<tr>
            <td><xsl:value-of select="zoo:nom" /></td>
            <td>
                <xsl:call-template name="date:format">
                    <xsl:with-param name="date" select="@date-naissance"/>
                </xsl:call-template>
            </td>
            <td><xsl:value-of select="@espèce" /><br /><i><xsl:value-of select="@nom-savant" /></i></td>
            <td><xsl:value-of select="zoo:taille" />&#160;<xsl:value-of select="zoo:taille/@unité" /></td>
            <td><xsl:value-of select="zoo:poids" />&#160;<xsl:value-of select="zoo:poids/@unité" /></td>
            <td><xsl:value-of select="zoo:sexe" /></td>
            <xsl:if test="@photo">
                <td><img src="{@photo}" alt="{zoo:nom}" /></td>
            </xsl:if>
	</tr>
    </xsl:template>

</xsl:stylesheet>

Génération de tables des matières, tris

Créez une table des matières des animaux du zoo, dont chaque item pointe vers les fiches descriptives complètes. Vous utiliserez des règles avec un mode nommé.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:zoo="urn:unice:master-2004-2005"
    xmlns:doc="http://www.unice.fr/master/2004-2005"
    xmlns:date="*** Processing dates ***"
    exclude-result-prefixes="zoo doc date">

    <xsl:import href="dates.xsl"/>
    <xsl:output method="html"/>
    <xsl:param name="liste-par-nom" select="false()" />

    <xsl:template match="/">
        <html>
            <head>
                <title>Zoo</title>
                <link href="zoo.css" rel="stylesheet" type="text/css"/>
            </head>
            <body>
                <h1>Bienvenue au Zoo</h1>
                <xsl:choose>
                    <xsl:when test="$liste-par-nom">
                        <ul>
                            <xsl:apply-templates mode="toc" select="//zoo:nom">
                                <xsl:sort select="."/>
                            </xsl:apply-templates>
                        </ul>
                    </xsl:when>
                    <xsl:otherwise>
                        <ul>
                            <xsl:apply-templates mode="toc" select="//zoo:nom">
                                <xsl:sort select="../@date-naissance"/>
                            </xsl:apply-templates>
                        </ul>
                    </xsl:otherwise>
                </xsl:choose>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="zoo:nom" mode="toc">
        <li><a href="#{generate-id()}"><xsl:value-of select="."/></a></li>
    </xsl:template>

    <xsl:template match="doc:info|doc:attention|doc:danger">
        <xsl:choose>
            <xsl:when test="parent::zoo:dauphins or parent::zoo:sélaciens">
                <tr>
                    <td colspan="6"><xsl:call-template name="doc:avertissement"/></td>
                </tr>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="doc:avertissement"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="doc:avertissement">
	<table class="{local-name()}" align="center">
            <tr>
                <td><img src="{local-name()}.gif" /></td>
                <td><xsl:apply-templates /></td>
            </tr>
	</table>
    </xsl:template>

    <xsl:template match="doc:b"><b><xsl:apply-templates /></b></xsl:template>
    <xsl:template match="doc:i"><i><xsl:apply-templates /></i></xsl:template>
    <xsl:template match="doc:em"><em><xsl:apply-templates /></em></xsl:template>
    <xsl:template match="doc:strong"><strong><xsl:apply-templates /></strong></xsl:template>

    <xsl:template match="zoo:dauphins|zoo:sélaciens">
        <h2><xsl:value-of select="local-name()" /></h2>
        <table border="1">
            <tr>
                <th>Nom</th>
                <th>Date naissance</th>
                <th>Type</th>
                <th>Taille</th>
                <th>Poids</th>
                <th>Sexe</th>
            </tr>
            <xsl:apply-templates/>
        </table>
    </xsl:template>

    <xsl:template match="zoo:dauphin|zoo:requin">
	<tr>
            <td><a name="{generate-id(zoo:nom)}"><xsl:value-of select="zoo:nom" /></a></td>
            <td>
                <xsl:call-template name="date:format">
                    <xsl:with-param name="date" select="@date-naissance"/>
                </xsl:call-template>
            </td>
            <td><xsl:value-of select="@espèce" /><br /><i><xsl:value-of select="@nom-savant" /></i></td>
            <td><xsl:value-of select="zoo:taille" />&#160;<xsl:value-of select="zoo:taille/@unité" /></td>
            <td><xsl:value-of select="zoo:poids" />&#160;<xsl:value-of select="zoo:poids/@unité" /></td>
            <td><xsl:value-of select="zoo:sexe" /></td>
            <xsl:if test="@photo">
                <td><img src="{@photo}" alt="{zoo:nom}" /></td>
            </xsl:if>
	</tr>
    </xsl:template>

</xsl:stylesheet>

Triez votre table des matières par ordre alphabétique sur le nom des animaux. Faites une autre règle pour trier votre table des matières par date de naissance croissante. Déclarez un paramètre à votre feuille de style pour pouvoir choisir le type de tri. Comment peut-on passer un paramètre à la feuille de style côté client ?

Il n'y a pas de moyen trivial de faire de passage de paramètres à la feuille de style côté client. Il faut faire appel à Javascript pour instancier le processeurs XSLT. Le problème est qu'on perd toute compatibilité : selon le navigateur, les objets ne s'invoquent pas de la même manière.

Le salut réside dans les transformations opérées côté serveur, beaucoup plus souples et neutres vis à vis du client.

Utilisation d'un framework CSS / Javascript

Pour faire une présentation soignée, le mieux est d'utiliser un framework CSS. Si vous n'en connaissez pas téléchargez Bootstrap.

Adaptez votre feuille de style XSLT pour qu'elle utilise ce framework, et faites les changements nécessaires pour utiliser ses composants. Utilisez aussi des composants dynamiques avec Javascript.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:zoo="urn:org.inria.ns.tp:tp-web-rest:zoo"
    xmlns:doc="http://org.inria.ns.tp/tp-web-rest/doc"
    xmlns:date="urn:org.inria.ns.tp:tp-web-rest:dates"
    exclude-result-prefixes="zoo doc date">

    <xsl:import href="dates.xsl"/>
    <xsl:output method="html" doctype-public=" "/>
    <xsl:param name="liste-par-nom" select="true()" />

    <xsl:template match="/">
        <html>
            <head>
                <title>Zoo</title>
                <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"/>
                <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css"/>
                <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"/>
                <style>
body {
    padding-top: 60px;
}
h2:first-letter {
    text-transform: uppercase;
}
                </style>
            </head>
            <body>
                <header class="navbar navbar-default navbar-inverse navbar-fixed-top" role="banner">
                    <div class="navbar-header navbar-brand">Bienvenue au Zoo</div>
                </header>
                <div class="container">
                    <div class="well sidebar-nav">
                        <ul class="nav nav-pills nav-stacked">
                          <xsl:choose>
                            <xsl:when test="$liste-par-nom">
                                <xsl:apply-templates mode="toc" select="//zoo:nom">
                                    <xsl:sort select="."/>
                                </xsl:apply-templates>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:apply-templates mode="toc" select="//zoo:nom">
                                    <xsl:sort select="../@date-naissance"/>
                                </xsl:apply-templates>
                            </xsl:otherwise>
                          </xsl:choose>
                        </ul>
                    </div>
                    <xsl:apply-templates/>
                </div>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="zoo:nom" mode="toc">
        <li><a href="#{generate-id()}"><xsl:value-of select="."/></a></li>
    </xsl:template>

    <xsl:template match="zoo:aquarium/*/*/doc:info | zoo:aquarium/*/*/doc:attention | zoo:aquarium/*/*/doc:danger">
        <tr>
            <td colspan="6"><xsl:apply-templates select="." mode="apply"/></td>
        </tr>
    </xsl:template>
    <xsl:template match="doc:info | doc:attention | doc:danger">
        <xsl:apply-templates select="." mode="apply"/>
    </xsl:template>

    <xsl:template match="doc:info" mode="apply">
        <div class="alert alert-info">
            <p class="lead">
                <span class="glyphicon glyphicon-info-sign"/>
                <xsl:text> </xsl:text>
                <xsl:apply-templates />
            </p>
        </div>
    </xsl:template>

    <xsl:template match="doc:attention" mode="apply">
        <div class="alert alert-warning">
            <p class="lead">
                <span class="glyphicon glyphicon-warning-sign"/>
                <xsl:text> </xsl:text>
                <xsl:apply-templates />
            </p>
        </div>
    </xsl:template>

    <xsl:template match="doc:danger" mode="apply">
        <div class="alert alert-danger">
            <p class="lead">
                <span class="glyphicon glyphicon-cutlery"/>
                <xsl:text> </xsl:text>
                <xsl:apply-templates />
            </p>
        </div>
    </xsl:template>

    <xsl:template match="doc:b"><b><xsl:apply-templates /></b></xsl:template>
    <xsl:template match="doc:i"><i><xsl:apply-templates /></i></xsl:template>
    <xsl:template match="doc:em"><em><xsl:apply-templates /></em></xsl:template>
    <xsl:template match="doc:strong"><strong><xsl:apply-templates /></strong></xsl:template>

    <xsl:template match="zoo:dauphins|zoo:sélaciens">
        <h2><xsl:value-of select="local-name()"/></h2>
        <table class="table table-bordered">
            <tr>
                <th>Nom</th>
                <th>Date naissance</th>
                <th>Type</th>
                <th>Taille</th>
                <th>Poids</th>
                <th>Sexe</th>
                <xsl:if test="*/@photo">
                    <th>Photo</th>
                </xsl:if>
            </tr>
            <xsl:apply-templates/>
        </table>
    </xsl:template>

    <xsl:template match="zoo:dauphin|zoo:requin">
	   <tr>
            <td><a name="{generate-id(zoo:nom)}"><xsl:value-of select="zoo:nom" /></a></td>
            <td>
                <xsl:call-template name="date:format">
                    <xsl:with-param name="date" select="@date-naissance"/>
                </xsl:call-template>
            </td>
            <td><xsl:value-of select="@espèce" /><br /><i><xsl:value-of select="@nom-savant" /></i></td>
            <td><xsl:value-of select="zoo:taille" />&#160;<xsl:value-of select="zoo:taille/@unité" /></td>
            <td><xsl:value-of select="zoo:poids" />&#160;<xsl:value-of select="zoo:poids/@unité" /></td>
            <td><xsl:value-of select="zoo:sexe" /></td>
            <xsl:if test="@photo">
                <td><img src="img/{@photo}" alt="{zoo:nom}" class="img-circle"/></td>
            </xsl:if>
	   </tr>
    </xsl:template>

</xsl:stylesheet>