Introduction à XSLT Éric Laporte Institut Gaspard-Monge Université Paris-Est Marne-la-Vallée
Ouvrir plusieurs documents sources (1/3) Cowslip Dutchman's-Breeches Greek Valerian Extraire du catalogue les plantes de cette liste 2 documents sources : la liste de plantes et le catalogue
Ouvrir plusieurs documents sources (2/3) <xsl:copy-of select="document('plant_catalog.xml')/CATALOG/PLANT[ COMMON=current()]"/> Document source principal : java -jar saxon8.jar -o extrListeExter.xml listePlantes.xml extrListeExter.xsl
document() ou doc() Expression Xpath permettant daccéder à la racine dun document XML extérieur au document source Le nom du document source est entre guillemets ou entre apostrophes <xsl:copy-of select="document('plant_catalog.xml')/CATALOG/PLANT[ COMMON=current()]"/> <xsl:copy-of select='document("plant_catalog.xml")/CATALOG/PLANT[ COMMON=current()]'/>
Ouvrir plusieurs documents sources (3/3) current() : le noeud courant (name dans toute la 2 e règle) Dans le prédicat, le noeud contexte est un élément PLANT <xsl:copy-of select="document('plant_catalog.xml')/CATALOG/PLANT[ COMMON=current()]"/>
Modulariser une expression Dans la version précédente, l'expression Xpath était trop longue <xsl:variable name="catalogue" select="document('plant_catalog.xml')/CATALOG"/> Plus lisible (on divise le calcul en étapes) Permet de réutiliser le résultat d'un calcul intermédiaire C'est une constante, non une variable
Portée d'une constante locale xsl:template xsl:variable match="name" name="catalogue" xsl:copy-of select="..."select="$catalogue..." Dans les noeuds frères droits du noeud et dans les sous-arbres correspondants On ne peut utiliser la constante que là
Les constantes XSLT ne sont pas utilisables comme les variables des langages de programmation habituels On peut initialiser une constante On peut redéfinir une constante avec le même nom ailleurs, mais c'est une autre définition de constante avec une autre portée On ne peut pas utiliser les constantes XSLT pour définir un compteur incrémenté par une itération
Portée d'une constante locale xsl:template xsl:variable match="..." name="..." select="..." La constante est définie dans la règle Elle est réinitialisée à chaque exécution de la règle La valeur de la constante n'est pas transmise d'une exécution à l'autre...
Initialiser une constante (1/2) Le contenu du select est évalué comme expression Xpath <xsl:variable name="catalogue" select="document($nom-catalogue)/CATALOG"/> Si le select doit être interprété littéralement, il faut deux niveaux de guillemets
Initialiser une constante (2/2) Autre syntaxe possible plant_catalog.xml <xsl:variable name="catalogue" select="document($nom-catalogue)/CATALOG"/> Avec cette syntaxe, la valeur de la constante peut être calculée par des instructions XSLT, par exemple apply- templates
Sauvegarder le noeud courant Le noeud courant et le noeud contexte changent tout le temps On peut les sauvegarder dans des constantes plant_catalog.xml <xsl:variable name="catalogue" select="document($nom-catalogue)/CATALOG"/> A l'intérieur du prédicat, le noeud contexte est un élément PLANT
Constantes globales (1/2) <xsl:variable name="catalogue" select="document('plant_catalog.xml')/CATALOG"/>
Constantes globales (2/2) Comme les constantes locales mais : Définition En dehors des fonctions Bonne pratique : en tête de fichier Portée Tout le programme, même avant la définition Les définitions circulaires sont interdites
Portée des constantes xsl:template xsl:variable match="..." name="i" select="..." La définition de la constante locale ne change pas la valeur de la constante globale, même si elles ont le même nom... xsl:variable name="i"select="..." xsl:stylesheet
Produire des liens hypertextes (1/2) En début de page XHTML, un index alphabétique des plantes avec des liens vers les entrées du catalogue Plant Catalog Plant index
Produire des liens hypertextes (2/2) On utilise comme nom d'ancre le nom anglais de la plante
Résultat Trillium Trout Lily Violet, Dog-Tooth Wake Robin Bloodroot
Évaluation des valeurs dattributs En fonction de linstruction et de lattribut Valeur évaluée dynamiquement Valeur littérale "Modèle de valeur dattribut" Littéral à lextérieur des {}, évalué dynamiquement à lintérieur Attributs des éléments n'appartenant pas à l'espace de noms XSLT : permet de calculer le nom de l'attribut
Appel de règles (1/2) Dans la version précédente, on appelle les règles sur COMMON pour faire l'index et sur PLANT pour faire le catalogue Plant Catalog Plant index
Appel de règles (2/2) Appel par noeud avec mode Le mode fonctionne comme le nom d'une fonction Le mode dans l'appel et dans la fonction doit concorder : - présence/absence ;- valeur.
Identificateurs pour liens hypertextes (1/2) Utiliser comme noms d'ancres les identificateurs de noeuds
Résultat Trout Lily Violet, Dog-Tooth Wake Robin Bloodroot
Identificateurs pour liens hypertextes (2/2) generate-id($noeud1) Renvoie un identifiant de $noeud1 generate-id() Renvoie un identifiant du noeud contexte Dans une même exécution du programme XSLT, - un même noeud a toujours le même identifiant - deux noeuds distincts ont deux identifiants distincts $noeud1 is $noeud2 generate-id($noeud1)=generate-id($noeud2) Testent l'égalité des noeuds $noeud1=$noeud2$noeud1 eq $noeud2 Testent l'égalité des valeurs textuelles des noeuds
Traiter un document avec espace de noms (1/3) Bloodroot Sanguinaria canadensis 4 Mostly Shady
Traiter un document avec espace de noms (2/3) Dans le programme XSLT, déclarer un préfixe pour l'espace de noms et l'utiliser avec tous les noms concernés <xsl:stylesheet xmlns:xsl=" version="2.0" xmlns:jr="
Résultat Violet, Dog-Tooth Erythronium americanum et copient les éléments avec leur espace de noms Rappel : copie les éléments sans leurs attributs
Traiter un document avec espace de noms (3/3) Si on déclare un préfixe dans le programme XSLT Les noms d'éléments sans préfixe sont interprétés comme ne faisant pas partie de l'espace de noms Il faut donc écrire le préfixe dans les expressions Xpath Si on déclare l'espace de noms par défaut dans le programme XSLT Les noms sans préfixe sont interprétés comme ne faisant pas partie de l'espace de noms C'est encore pire : pas de solution
Traitement par défaut (1/5) Dans le programme précédent, apply-templates appelle la 2 e règle sur un seul noeud Et si la règle n'était pas applicable à ce noeud ?
Traitement par défaut (2/5) Extraire l'unique plante pour laquelle LIGHT vaut 'Mostly Sunny' appelle les règles sur un noeud Aucune règle n'est applicable à ce noeud
Traitement par défaut (3/5) CATALOG PLANT BOTANICALCOMMON Bloodroot Sanguinaria Canadensis PLANT... ZONELIGHT 4 Mostly Shady... / Application des règles implicites
Traitement par défaut (4/5) Résultat BloodrootSanguinariacanadensis4Mostly Shady ColumbineAquilegiacanadensis3Mostly Shady Marsh Marigold Caltha palustris 4 Mostly Sunny CowslipCalthapalustris4Mostly Shady Dutchman's- BreechesDicentracucullaria3Mostly Shady Ginger, WildAsarumcanadense3Mostly Shady HepaticaHepaticaamericana4Mostly Shady LiverleafHepaticaamericana4Mostly Shady Jack-In-The-...
Traitement par défaut (5/5) Partie texte : résultat du traitement par défaut L'appel provoque un traitement par défaut Partie balisée : résultat de l'application de la règle Le traitement par défaut est récursif et finit par appeler la règle
Comment ça marche ? Quand il y a un appel de règles sur un noeud et qu'aucune règle n'est applicable, le processeur appelle des "règles implicites" en fonction du type du noeud - Éléments et racine : appeler les règles sur les noeuds fils (de type élément, texte ou commentaire mais pas attribut) - Texte et attributs : copier la valeur textuelle - Commentaires : rien Ces règles implicites s'appellent récursivement d'élément en élément Elles écrivent tout le texte qu'elles rencontrent Si elles rencontrent un noeud sur lequel une règle définie par l'utilisateur est applicable, elles lui repassent la main
Comment éviter le traitement par défaut ? Le traitement par défaut est un symptôme qui montre que le développeur ne contrôle pas tout Pour l'éviter, vérifier que pour chaque appel par noeud et chaque noeud il y a au moins une règle applicable Exemple : le programme ci-dessous provoque-t-il un traitement par défaut ?
Instructions conditionnelles (1/2) Produire un titre au singulier ou au pluriel suivant qu'il y a un ou plusieurs objets <xsl:variable name="shade-plants" select="jr:PLANT[jr:LIGHT='Shade']/jr:COMMON"/> Shade plant Shade plants
Instructions conditionnelles (2/2) Un xsl:choose doit contenir au moins un xsl:when Si plusieurs xsl:when sont vérifiés, seul le premier est exécuté Résultat Shade plants Violet, Dog-Tooth - Trout Lily - Adder's-Tongue - Bee Balm - Bergamot - Buttercup - Crowfoot - Cinquefoil - Jacob's Ladder - Greek Valerian - Snakeroot - Cardinal Flower -
Un piège à débutants (1/2) Si on définit une constante dans un choose, on ne peut pas l'utiliser une fois qu'on est sorti du choose <xsl:variable name="shade-plants" select="jr:PLANT[jr:LIGHT='Shade']/jr:COMMON"/> Shade plant Shade plants
Un piège à débutants (2/2) Mettre le choose dans la définition de la constante <xsl:variable name="shade-plants" select="jr:PLANT[jr:LIGHT='Shade']/jr:COMMON"/> Shade plant Shade plants
Instructions conditionnelles (1/2) Écrire un délimiteur après chaque objet, sauf le dernier - Résultat Shade plants Violet, Dog-Tooth - Trout Lily - Adder's-Tongue - Bee Balm - Bergamot - Buttercup - Crowfoot - Cinquefoil - Jacob's Ladder - Greek Valerian - Snakeroot - Cardinal Flower
Instructions conditionnelles (2/2) Le défaut de xsl:if est qu'il n'y a pas de else Utiliser xsl:if quand on est sûr qu'on n'aura pas besoin d'un else -
La liste de noeuds courante (1/2) position() et last() dépendent de la liste de noeuds contexte position() : position du noeud contexte dans la liste de noeuds contexte last() : longueur de la liste de noeuds contexte La liste de noeuds contexte est initialisée à partir de la liste de noeuds courante Ici c'est la liste des noeuds jr:COMMON sélectionnés -
La liste de noeuds courante (2/2) La liste de noeuds courante change à chaque appel par noeud, comme le noeud courant Elle dépend de l'expression Xpath dans apply-templates <xsl:variable name="shade-plants" select="jr:PLANT[jr:LIGHT='Shade']/jr:COMMON"/> (...) -
Modularisation (1/11) Pour découper un programme en unités petites, réutilisables et lisibles <xsl:variable name="shade-plants" select="jr:PLANT[jr:LIGHT='Shade']/jr:COMMON"/>
Modularisation (2/11) Règle nommée Shade plant Shade plants
Modularisation (3/11) Règle nommée - appelée par son nom - le noeud courant ne change pas à l'appel - peut avoir des paramètres (syntaxe : comme les constantes) Même principe que les fonctions des autres langages de programmation (...)
Modularisation (4/11) Valeur de retour d'une règle nommée Un sous-arbre, ici réduit à un noeud texte La valeur de retour est insérée dans le document résultat à un emplacement qui correspond à l'appel de la règle nommée On peut coder un objet et ses champs dans un sous-arbre pour faire de la programmation objet en cachette Une règle qui a à la fois un attribut name et un attribut match peut être appelée soit par nom, soit par noeud Peu lisible donc déconseillé
Modularisation (5/11) Coder les dates sous forme d'arbres Solution : une règle nommée renvoyant un arbre
Modularisation (6/11)
Résultat Bloodroot Sanguinaria canadensis 4 Mostly Shady L'espace de noms apparaît sous forme de préfixe, mais ça n'a pas d'importance
Modularisation (7/11) On peut définir des fonctions Xpath Comme les règles nommées, mais appel en Xpath <xsl:variable name="shade-plants" select="jr:PLANT[jr:LIGHT='Shade']/jr:COMMON"/>
Modularisation (8/11) Définition d'une fonction Xpath Shade plant Shade plants
Modularisation (9/11) Le nom d'une fonction Xpath définie par l'utilisateur doit avoir un espace de noms <xsl:stylesheet xmlns:xsl=" version="2.0" xmlns:jr=" xmlns:u=" (...) (...)
Modularisation (10/11)
Modularisation (11/11) Répartir un programme en plusieurs documents Réutiliser du code Pas d'encapsulation Conflits entre règles appelées par noeuds : comme si les règles étaient dans le même module (si une est plus spécifique que toutes les autres, elle a la priorité, sinon c'est une erreur) Conflits entre règles appelées par nom : ne pas définir deux règles avec le même nom Les modules doivent être construits et maintenus ensemble Les espaces de noms doivent être déclarés dans chaque module
Changer de noeud courant (1/5) xsl:for-each permet de changer de noeud courant Comme xsl:apply-templates, sauf que le contrôle reste dans la même règle Rappel Extraction d'un information avec appel de règle : <xsl:apply-templates select="/CATALOG/PLANT[BOTANICAL='Potentilla']"/>
Changer de noeud courant (2/5) La même chose mais avec xsl:for-each : <xsl:for-each select="/CATALOG/PLANT[BOTANICAL='Potentilla']">
Changer de noeud courant (3/5) Points communs entre xsl:for-each et xsl:apply-templates Permettent de changer de noeud courant (et de liste de noeuds courante) Permettent de visiter un noeud ou plusieurs Permettent de classer les noeuds suivant un ordre
Changer de noeud courant (4/5) Classement avec xsl:for-each Les instructions sont exécutées une fois pour tous les noeuds visités Les instructions qui suivent sont exécutées autant de fois qu'il y a de noeuds à visiter
Changer de noeud courant (5/5) Différences entre xsl:for-each et xsl:apply-templates Avantages de xsl:for-each - la sélection des noeuds est faite par une seule instruction - ne provoque pas de traitement par défaut Inconvénients : moins modulaire - moins de réutilisation de règles - découpage en règles moins fin