RSS .92| RSS 2.0| ATOM 0.3
  • Home
  • Best Of
  • In English?
  • L'auteur
  •  

    XSLT sans douleur

    Certains lecteurs s’étant plaints de mon manque d’enthousiasme pour le français, voici comme promis le texte intégral de mon article, paru dans le numéro 109 du magazine Programmez!.

    Les transformations XSLT sont sans pareil pour le traitement de documents XML: transformation, analyse, publication, tout ou presque est possible à qui maîtrise ce langage.

    Les principes de base du langage sont cependant trop souvent méconnus des débutants, la tendance étant d’abuser des instructions procédurales de XSLT: xsl:if, xsl:choose, xsl:for-each. On crée ainsi des transformations peu flexibles et peu efficaces, qui n’utilisent pas le modèle XPath/XSLT à bon escient.

    Cet article propose une manière d’aborder XSLT basée sur une bonne connaissance de XPath, combinée avec un jeu d’instructions XSLT volontairement réduit. Ce “chemin d’apprentissage” de XSLT a fait ses preuves lors de nos sessions d’enseignement, en permettant aux programmeurs de faire les bons choix lors de la création de leurs transformations.

    Une connaissance de base de XSLT sera utile pour comprendre nos exemples, et nous ne donnerons pas de détails quant à la syntaxe des instructions XPath et XSLT utilisées. Il est recommandé d’utiliser les références citées en fin d’article pour compléter ces informations.

    XPath

    XPath est trop souvent ignoré par les débutants en XSLT, car quasiment invisible dans des expressions simples, comme celle ci-dessous:

    <xsl:template match="section"/>

    Cette instruction XSLT déclare une template, un ensemble d’instructions (vide dans cet exemple) qui sera appliqué lorsqu’on rencontre un certain pattern dans le document d’entrée.

    On peut penser que section est simplement un nom d’élément; ce n’est pas faux, mais il s’agit en fait d’une expression XPath, mieux visible dans ce second exemple:

    <xsl:template match="section[@id]"/>

    Cette seconde template ne s’appliquera qu’aux éléments section qui possèdent un attribut id. L’important est de noter que l’attribut match est une expression XPath. En pratiquant XSLT, on constate rapidement que ces expressions sont responsables pour une grande part de la puissance des transformations XSLT, et que la maîtrise de XPath nous aidera énormément dans la conception de transformations concises et efficaces.

    Dans ce qui suit, nous passons en revue les concepts principaux de XPath, en indiquant leur importance dans notre processus d’apprentissage.

    L’arborescence XPath

    La structure “textuelle” et les balises du document XML sont ignorés par le processeur XPath, qui considère seulement l’arbre résultant de l’analyse (parsing) du document XML.

    Les deux éléments <para> ci-dessous, par exemple, sont absolument identiques du point de vue du processeur:

    <para/>
    <para></para/>

    L’arbre XPath contient sept types de noeuds différents: quatre sont utilisés fréquemment (racine, élément, attribut, texte) et les trois autres (commentaires, instructions de traitement et espaces de noms) nettement plus rarement.

    Rappelons que le noeud racine n’existe pas vraiment dans le document XML d’entrée, ce noeud est rajouté artificiellement dans l’arborescence XPath comme conteneur pour le document. L’expression XPath /html sélectionne donc bien l’élément racine html du document d’entrée, situé en-dessous du noeud racine artificiel dans l’arbre XPath.

    La connaissance de ces types de noeuds aidera à l’élaboration d’expressions XPath précises. Les notations utilisées pour sélectionner les noeuds de ces différents types sont parfois peu évidentes. L’expression //text(), par exemple n’est pas un appel de fonction mais bien la sélection de tous les noeuds de type texte du document.

    Chemins de sélection

    Les chemins XPath sont en apparence très semblables à ceux que l’on utilise dans les systèmes de fichiers, comme /section/para. La différence essentielle est qu’un tel chemin pointe dans un système de fichiers sur un seul objet, alors que dans XPath cette expression sélectionne tous les éléments dont le nom est “para”, qui sont enfants d’un élément “section” situé à la racine du document. Le résultat est donc un ensemble de noeuds, qui seront des éléments dans notre exemple, mais peuvent selon l’expression utilisée être de n’importe quel type parmi les sept types de noeuds mentionnés ci-dessus.

    Les chemins XPath sont donc plus proches conceptuellement des requêtes SQL que de chemins sur un disque: on peut les considérer comme des filtres qui, appliqués sur l’arborescence du document XML, laissent passer certains noeuds et pas d’autres.

    Les chemins absolus commencent par un slash, comme /section/para, et s’appliquent donc à partir du noeud racine. Les chemins relatifs comme section/para, sans le slash initial, s’appliquent à partir du noeud contextuel, celui que le
    processeur XSLT est en train de traiter au moment de l’évaluation de l’expression XPath.

    Le double slash permet de faire la différence entre une relation parent-enfant, comme dans le chemin section/para, ou parent-descendant, comme dans le chemin section//para qui utilise ce double slash. Le premier exemple sélectionne les éléments para qui sont juste en-dessous d’un élément section, alors que le second sélectionne les éléments para qui ont un élément section comme ancêtre, quel que soit le nombre de niveaux hiérarchiques qui les séparent.

    Ces principes de construction de chemins XPath sont très importants pour la bonne construction et compréhension de transformations XSLT.

    Prédicats

    Les prédicats XPath sont similaires à la clause where du langage SQL: ils permettent des sélections précises, en ignorant les noeuds d’un chemin qui ne remplissent pas les conditions définies par le prédicat.

    L’exemple ci-dessous sélectionne tous les éléments div possédant un attribut style qui vaut abc, et qui sont situés en-dessous d’un élément section qui contient au moins un élément enfant para.

    section[para]//div[@style=’abc’]

    La concision d’une telle expression, par rapport à sa description en langue française, démontre combien la syntaxe XPath est expressive.

    Les prédicats sont utilisés très fréquemment dans les transformations XSLT. Ils permettent souvent d’éviter les constructions procédurales comme xsl:if, par l’utilisation de templates XSLT plus “ciblées”. Il est donc important de connaître leur principe, ainsi que l’étendue des fonctions XPath que les prédicats peuvent utiliser.

    Axes

    En XPath, les axes permettent de naviguer dans l’arborescence du document XML, dans toutes les directions: parents/enfants (directs ou à plusieurs niveaux), noeuds frères précédents ou suivants, et noeuds précédents ou suivants sans tenir compte de la hiérarchie.

    L’exemple ci-dessous sélectionne les éléments table qui ont le même parent et suivent un élément para ancêtre du noeud courant.

    ancestor::para/following-sibling::table

    L’utilisation des axes XPath n’est pas très fréquente, mais il est important de connaître les types d’axes à disposition pour savoir les utiliser à bon escient.

    Tout ceci n’est pas très simple…

    La promesse d’un XSLT sans douleur semble un peu lointaine au vu de l’étendue des connaissances XPath mentionnées comme nécessaires. Mais le plus dur est fait, XPath étant effectivement ce qui fait la puissance
    des transformations, plus que les instructions XSLT qui sont comme on le verra relativement simples.

    Bien comprendre le rôle de XPath dans XSLT, et le principe de sélection des noeuds par le processeur XPath, est capital pour utiliser XSLT de manière efficace. Il est donc conseillé, à partir des références figurant en fin d’article, d’étudier les éléments XPath mentionnés ci-dessus, avant même d’aborder l’utilisation de XSLT, ou en tout cas tout au début de l’apprentissage.

    XSLT

    L’exemple ci-dessous démontre une fois de plus l’importance de XPath dans les transformations XSLT. Les valeurs des attributs match, class et select de cette transformation sont toutes des expressions XPath.

     <xsl:template
      match="section[para[normalize-space(.)]]">
      <div class="{@style}">
        <h1><xsl:value-of select="title"/></h1>
        <xsl:apply-templates select="para[@ok='true']"/>
      </div>
    </xsl:template>
    

    En supprimant ces expressions, on fait apparaître les instructions XSLT et les éléments HTML littéraux de notre transformation:

     <xsl:template
      match="">
      <div class="">
        <h1><xsl:value-of select=""/></h1>
        <xsl:apply-templates select=""/>
      </div> 
    
    </xsl:template>
    

    Cette nouvelle transformation n’est bien entendu pas utilisable telle quelle, mais sa simplicité montre bien qu’une grande partie de la complexité et de la puissance des transformations XSLT provient de XPath.

    Nous présentons dans ce qui suit, les éléments XSLT indispensables à l’apprentissage.

    Jeu d’instructions réduit

    Notre premier conseil pour XSLT est de se limiter à un jeu d’instructions réduit, pour éviter de tomber dans le piège des constructions procédurales. On se limitera dans un premier temps à ce jeu d’instructions:

    • xsl:stylesheet

    • xsl:template
    • xsl:apply-templates
    • xsl:value-of (y compris la variante utilisée pour les attributs, comme dans <p class=”{@id}”> ou les accolades sont équivalentes à une instruction value-of.

    Ces quelques instructions permettent de réaliser des transformations relativement complexes, pour autant que l’on profite au maximum de la puissance de XPath dans leurs attributs match et select.

    On sera assez rapidement amené à utiliser également les instructions xsl:variable xsl:param, et plus tard xsl:call-template, les modes d’exécution de xsl:template, et xsl:key pour la création de tableaux associatifs. Ces instructions influencent cependant peu la structure générale de la transformation, qui est déterminée principalement par les quatre instructions de notre jeu réduit.

    Les instructions xsl:include et xsl:import permettent de mieux modulariser et réutiliser nos templates XSLT, mais, comme les instructions de la liste ci-dessus, influencent peu la structure générale des transformations.

    Avec XPath, les quatre instructions de base constituent les pièces maîtresses de nos transformations et méritent donc d’être étudiées en détail.

    xsl:if, xsl:choose, xsl:for-each

    Attention, danger! Ces instructions “procédurales” sont parfois nécessaires, mais nettement moins souvent que la plupart des débutants en XSLT ne le pensent.

    L’exemple typique est celui d’une template basée sur xsl:choose, qui sera avantageusement remplacée par plusieurs templates avec des expressions de sélection XPath plus spécifiques.

    Avec xsl:choose, notre template (exemple ci-dessous) ressemble un peu à un fragment de code Java ou C:

    <xsl:template match="something">
        <xsl:choose>
          <xsl:when test="@id">
            ...cas 1
          </xsl:when>
          <xsl:otherwise>
            ...cas 2
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template><
    

    Alors qu’il suffit de faire de chaque xsl:when une template séparée pour obtenir un code plus lisible, plus facile à maintenir et que le processeur exécute en général bien plus efficacement:

    <xsl:template match="something[@id]">
         ...cas 1
      </xsl:template> 
    
      <xsl:template match="something">
         ...cas 2
      </xsl:template>
    

    De la même manière, l’instruction xsl:if peut souvent être évitée en utilisant des expressions XPath plus précises dans les attributes match de xsl:template, alors que xsl:for-each sera avantageusement remplacée par une template XSLT récursive.

    Ces instructions procédurales ne peuvent pas être évitées totalement, elles ont leur utilité. Il est cependant recommandé de ne les utiliser qu’en dernier ressort.

    Scénario de traitement du processeur XSLT

    Le principe de traitement de l’arbre d’entrée par le processeur XSLT est simple, mais souvent méconnu:

    • Le processeur commence par visiter le noeud racine du document.
    • Pour chaque noeud qui est visité, le processeur:

    • 1. Définit ce noeud comme “noeud contextuel” pour les expressions XPath
    • 2. Vérifie si une template s’applique à ce noeud
    • 3a. Si oui, il exécute la template, le traitement est alors terminé.
    • 3b. Si non, il exécute les règles par défaut.

    Rien de compliqué dans ce scénario, qui s’exécute tant qu’il reste des noeuds à traiter, ce qui dépend de la manière dont le document est visité par les instructions XSLT et les règles par défaut.

    Ce scénario explique pourquoi la transformation ci-dessous s’arrête immédiatement, après avoir visité le noeud racine.

    <xsl:stylesheet>
    <xsl:template match="/"/>
    
    </xsl:stylesheet>

    Le processeur comment la visite par le noeud racine, trouve une template qui s’applique à ce noeud et l’exécute. La template ne fait rien, car son corps est vide, et le traitement se termine selon la règle 3a. Aucun autre noeud n’est visité, car la template exécutée n’utilise pas d’instruction de visite comme xsl:apply-templates.

    Régles par défaut

    Selon la règle 3b ci-dessus, les règles par défaut sont exécutées pour chaque noeud que le processeur visite et auquel aucune template ne s’applique.

    Il est donc nécessaire de connaître ces règles par défaut, pour comprendre par exemple que la transformation ci-dessous visite complètement le document d’entrée, en copiant les noeuds de texte sur sa sortie:

    <xsl:stylesheet/>

    Cette transformation minimale est tout à fait valide, et son comportement s’explique en combinant le scénario d’exécution du processeur, ci-dessus, avec les règles par défaut

    Ces règles définissent que, si aucune template ne s’applique:

    • Le noeud racine et les éléments sont visités.
    • Les noeuds de texte sont copiés sur la sortie.
    • Les autres types de noeuds sont ignorés.

    La connaissance de ces règles par défaut est essentielle, pour comprendre le comportement de nos transformations et pour éviter d’écrire des templates inutiles, comme dans cet exemple:

    <xsl:template match="p">
      <xsl:apply-templates/>
    </xsl:template>

    Cette template reproduit exactement la règle par défaut qui dit qu’un noeud est visité, ce que fait aussi xsl:apply-templates. On peut donc, dans le cas général, la supprimer sans modifier le comportement de la transformation XSLT.

    Conclusion

    Notre rapide tour d’horizon nous montre qu’une bonne connaissance de XPath est essentielle pour utiliser efficacement XSLT. Les instructions XSLT elles-mêmes posent en général moins de problèmes de compréhension, et l’utilisation de notre jeu d’instructions réduit aide à utiliser XSLT de la manière préconisée par ses concepteurs.

    Le “chemin d’apprentissage” proposé dans cet article devrait vous aider à aborder XSLT dans le bon sens - bonne chance dans votre exploration!

    Références

    • Spécification XPath: http://www.w3.org/TR/xpath
    • Spécification XSLT: http://www.w3.org/TR/1999/REC-xslt-19991116
    • Tutoriels XPath/XSLT: http://www.zvon.org - partiellement traduits en français.
    • Ouvrage de Michael Kay, XSLT 2.0 and XPath 2.0 Programmer’s Reference, 4th Edition, ISBN: 978-0-470-19274-0

    WordPress database error: [Can't open file: 'wp_comments.MYD'. (errno: 144)]
    SELECT * FROM wp_comments WHERE comment_post_ID = '114' AND comment_approved = '1' ORDER BY comment_date

    Leave a Reply