Introduction à XSLT

Transcription

Introduction à XSLT
Introduction à XSLT
Introduction
Dans cette démonstration, nous allons aborder la conception et l’utilisation des feuilles de style. Les
feuilles de style permettent de transformer un document xml vers un autre document xml, un document
html ou un document de texte brut.
Premiers pas
Une première feuille de style que nous allons faire transformera un document xml contenant des cours
et des inscriptions en un document texte listant les cours. Nous voudrions donc que le fichier inscriptions.xml soit transformer vers le texte suivant
ift3220
ift2030
Pour ce faire nous allons commencer par créer une feuille de style xslt version 2.0 à l’aide de XmlSpy.
Une feuille de style vierge devrait avoir l’allure suivante
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
</xsl:stylesheet>
Cette feuille de style ne fait encore rien. Si nous l’utilisons pour transformer le document inscriptions.xml, nous obtenons le document suivant (sans les fins de ligne):
<?xml version=“1.0”encoding=“UTF-8”?> lepb12345678letp12345678lesg12345678tenc12345678
krac12345678lepb12345678lecs12345678krac12345678
Que s’est-il passé? Premièrement, la ligne <?xml... est présente car nous avons la balise <xsl:output
spécifie que nous voulons créer un document xml. Ce n’est pas le cas, nous allons donc remplacer la
balise <xsl:output ...> par la suivante
<xsl:output method="text" encoding="UTF-8"/>
Si nous réessayons, nous obtenons
lepb12345678letp12345678lesg12345678tenc12345678
krac12345678lepb12345678lecs12345678krac12345678
1
C’est mieux, mais ce n’est pas encore ça. Les codes permanents des élèves inscrits sont affichés
sans que nous n’ayons rien demandé. C’est parce que par défaut, le texte des élément est affiché et
le texte des attributs ne l’est pas. Nous allons donc spécifier un comportement différent de celui par
défaut qui, pour chaque cours, affichera son identificateur sans afficher les élèves inscrits. Nous allons
tout d’abord importer l’espace de nommage que nous voulons utiliser en ajoutant l’attribut suivant à
la balise xsl:stylesheet
xmlns:i="http://www-etud.iro.umontreal.ca/~patryale/demo10/inscriptions/"
Nous pourrons maintenant utiliser les éléments du schéma cours.xsd en les préfixant de i:. Nous
allons ensuite changer le comportement par défaut pour le traitement de la balise i:cours en ajoutant
le code suivant avant la balise fermante </xsl:stylesheet>
<xsl:template match="/i:inscriptions/i:cours">
<xsl:value-of select="@id"/>
</xsl:template>
Si nous utilisons notre nouvelle feuille de style, nous obtenons la sortie suivante
ift3220ift2030
Nous y sommes presque, il ne nous reste qu’à ajouter le saut-de-ligne après chaque sigle de cours.
Pour ce faire, après l’instruction <xsl::value-of ..., nous allons ajouter l’instruction suivante
<xsl:text>&#10;</xsl:text>
Cette instruction fait afficher le caractère unicode ayant le code 10 (retour de ligne) dans le texte à
construire. Nous obtenons maintenant
ift3220
ift2030
la liste des cours que nous convoitions.
Un autre petit pas
C’est bien de pouvoir lister les cours, mais il serait encore mieux de lister les élèves dans chacun de ces
cours. Nous allons donc spécifier un traitement spécifique pour chacun des inscrits
<xsl:template match="/i:inscriptions/i:cours/i:inscription">
<xsl:value-of select="."/>
<xsl:text>&#10;</xsl:text>
</xsl:template>
Maintenant, si nous réexécutons notre feuille de style, nous devrions avoir aussi la liste des élèves,
non? Essayons .... Que s’est-il passé, pourquoi rien n’a changé? C’est tout simplement parce que
lorsqu’un cours est traı̂té, il ne propage pas le traitement à ses enfants. Pour propager le traitement
aux enfants, nous allons remplacer la balise qui traitait les cours par
<xsl:template match="/i:inscriptions/i:cours">
<xsl:value-of select="@id"/>
<xsl:apply-templates/>
</xsl:template>
Nous devrions maintenant nous retrouver avec le document que nous voulions
2
ift3220
lepb12345678
letp12345678
lesg12345678
tenc12345678
krac12345678
ift2030
lepb12345678
lecs12345678
krac12345678
C’est bien, mais ce n’est pas très jolie. Nous pourrions sûrement mieux formatter le tout. Nous
pourrions par exemple faire une en-tête pour chaque cours. Allons-y donc et remplaçons le code traitant
l’élément i:cours par le suivant
<xsl:template match="/i:inscriptions/i:cours">
<xsl:value-of select="fn:replace(@id, ’.’, ’-’)"/>
<xsl:text>&#10;</xsl:text>
<xsl:value-of select="@id"/>
<xsl:text>&#10;</xsl:text>
<xsl:value-of select="fn:replace(@id, ’.’, ’-’)"/>
<xsl:text>&#10;</xsl:text>
<xsl:apply-templates/>
<xsl:text>&#10;</xsl:text>
</xsl:template>
Nous obtenons maintenant la sortie suivante
------ift3220
------lepb12345678
letp12345678
lesg12345678
tenc12345678
krac12345678
------ift2030
------lepb12345678
lecs12345678
krac12345678
Ça semble bon, mais qu’avons nous fait au juste? Nous avons tout simplement utilisé la fonction
replace (déclarée dans l’espace de nommage fn) pour remplacer chaque caractère (expression régulière
.) du nom du cours par un -.
Ce qui compte
Maintenant que nous avons afficher la liste des élèves de chaque cours, nous voulons avoir le nombre
d’élève inscrit après le code du dernier élève. Pour ce faire, nous utiliserons la fonction count
3
<xsl:template match="/i:inscriptions/i:cours">
<!-- ... -->
<xsl:apply-templates/>
<xsl:text>Nombre d’inscrits: </xsl:text>
<xsl:value-of select="count(i:inscription)"/>
<xsl:text>&#10;</xsl:text>
<xsl:text>&#10;</xsl:text>
</xsl:template>
La fonction count prend en paramètre une expression XPath et retourne le nombre de noeuds
auxquels l’expression fait référence. Nous obtenons maintenant la sortie suivante
------ift3220
------lepb12345678
letp12345678
lesg12345678
tenc12345678
krac12345678
Nombre d’inscrits: 5
------ift2030
------lepb12345678
lecs12345678
krac12345678
Nombre d’inscrits: 3
À l’ordre
Mettons un peu d’ordre dans tout cela. Nous aimerions pouvoir trier les élèves des différents cours
par ordre de leur code permanent. Pour ce faire, nous allons spécifier un critère de tri dans la balise
apply-templates
<xsl:apply-templates>
<xsl:sort select="."/>
</xsl:apply-templates>
Cela à pour effet de traiter les noeuds enfants de cours par ordre de inscription. Notez que la
racine du critère de tri est l’élément enfant de cours. Pouvez-vous maintenant ordonner la liste par
ordre de cours?
Les listes peuvent être jolies
Dans les exercices précédents, nous avons affiché du texte brut. Ici, nous allons reprendre l’exemple
précédent et l’afficher en XHTML
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
4
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xdt="http://www.w3.org/2005/xpath-datatypes"
xmlns:i="http://wwwetud.iro.umontreal.ca/~patryale/demo10/inscriptions/"
>
<xsl:output method="xml"
doctype-public=" -// W3C // DTD XHTML 1.0 Strict // EN"
doctype-system="http: // www.w3.org/TR/ xhtml1 /DTD/xhtml1 strict .dtd"
indent ="yes"
encoding="UTF-8"/>
<xsl:template match="/">
<html>
<head>
<title>Liste des cours</title>
</head>
<body>
<h1>Liste des cours</h1>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="/i:inscriptions/i:cours">
<h2><xsl:value-of select="@id"/></h2>
<ul>
<xsl:apply-templates>
<xsl:sort select="."/>
</xsl:apply-templates>
</ul>
<em>
<xsl:text>Nombre d’inscrits: </xsl:text>
<xsl:value-of select="count(i:inscription)"/>
</em>
</xsl:template>
<xsl:template match="/i:inscriptions/i:cours/i:inscription">
<li><xsl:value-of select="."/></li>
</xsl:template>
</xsl:stylesheet>
Le petit truc à remarquer est que les balises qui ne sont pas dans l’espace de noms xsl sont copiées
à la sortie. Sinon, le code parle de lui-même. Il faut se souvenir que le parcourt de l’arbre se produit
aux appels de apply-templates.
Nommons les choses par leur nom
Un code permanent n’est pas nécessairement très parlant pour un humain. Nous allons maintenant aller
chercher le nom de chaque élève dans le document eleves.xsd. Pour ce faire, nous allons charger le
document dans une variable, en ajoutant le code suivant après la balise <output... de notre document
<xsl:variable name="eleves" select="document(’eleves.xml’)"/>
5
Ensuite, pour pouvoir utiliser les balises du documents chargé, nous allons ajouter la déclaration
d’espace de nom suivante :
xmlns:e=“http://www-etud.iro.umontreal.ca/˜patryale/demo10/eleves/”
Finalement, nous allons remplacer notre code traitant chaque inscription par
<xsl:template match="/i:inscriptions/i:cours/i:inscription">
<xsl:variable name="id" select="text()"/>
<xsl:variable name="eleve" select="$eleves/e:eleves/e:eleve[@id=$id]"/>
<li>
<xsl:value-of select="$eleve/e:prenom"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$eleve/e:nom"/>
</li>
</xsl:template>
Notez que pour pouvoir utiliser l’identificateur de la balise i:inscription dans le contexte de la
balise e:eleve, nous utilisons une variable. Notez aussi qu’une variable peut contenir une chaı̂ne de
caractères ou un sous-arbre.
Si nous exécutons notre feuille de style, nous obtenons
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC " -// W3C // DTD XHTML 1.0 Strict // EN"
"http: // www.w3.org/TR/ xhtml1 /DTD/xhtml1 - strict .dtd">
<html
xmlns:i="http://wwwetud.iro.umontreal.ca/~patryale/demo10/inscriptions/"
xmlns:e="http://www-etud.iro.umontreal.ca/~patryale/demo10/eleves/"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xdt="http://www.w3.org/2005/xpath-datatypes"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<head>
<title>Liste des cours</title>
</head>
<body>
<h1>Liste des cours</h1>
<h2>ift3220</h2>
<ul>
<li>Capitaine Krabs</li>
<li>Bob L’Éponge</li>
<li>Gary L’Escargot</li>
<li>Patrick L’Étoile</li>
<li>Carlo Tentacules</li>
</ul>
<em>Nombre d’inscrits: 5</em>
<h2>ift2030</h2>
<ul>
<li>Capitaine Krabs</li>
<li>Sandy L’Écureuil</li>
<li>Bob L’Éponge</li>
</ul>
<em>Nombre d’inscrits: 3</em>
6
</body>
</html>
Pour éviter d’inclure les espaces de noms, nous pouvons ajouter l’attribut suivant à la balise
stylesheet
exclude-result-prefixes="xsl xs fn xdt c e"
C’est ici que nous arrêtons avec cet exemple.
Les balises XSLT
Dans les exemples précédents, quelques balises XSLT d’intérêt sont les suivantes :
output Spécifie le type de document produit (xml, texte ou html).
template Spécifie un traitement pour un ensemble de noeud à l’aide de l’attribut match.
apply-templates Continue le parcours dans les fils de l’élément traité.
sort Spécifie l’ordre dans lequel les fils seront visités à l’aide de la balise select.
text Insère du texte dans le document produit.
value-of Évalue expression dans l’attribut select et retourne sa valeur.
variable Déclare une variable constante.
Nous avons aussi vu qu’il ne faut pas oublier de déclarer les espaces de noms dans la balise
stylesheet.
<?xml-stylesheet type="text/xsl" href="compactHTML.xsl"?>
Les expressions XPath
Vous avez remarqué que les expressions dans les attributs match ou select peuvent être très simple
comme elle peuvent être complexes. Ces expressions sont appelées expressions XPath. Elles sont
composées de trois composantes :
1. Un axe qui donne un chemin vers un ensemble de noeud, en séparant chaque nom de noeud
par un /. Le noeud racine est nommé /, le noeud courant par . et le noeud parent par ...
Pour indiquer une relation parent-enfant non-immédiate, on utilise le //.
2. Un noeud de test qui peut être un nom de balise, * ou un nom de fonction comme node()
et text()
3. Un prédicat donné entre crochet après le test. Un prédicat peut utiliser une variable en
préfixant son nom de $ ou une fonction comme concat, substring, count ou replace.
Dans l’expression suivante
$eleves/e:eleves/e:eleve[@id=$id]
L’axe est $eleves/e:eleves/, le test e:eleve et le prédicat [@id=$id]. Pour plus d’informations,
vous pouvez consulter Xml: Looking at the forest instead of the Trees.
7

Documents pareils