I. Origines, mise en œuvre II. Premiers exemplesIII. Vue d'ensemble de la mécanique
- Visualisation d'un fichier de noms et de notes dans un navigateur
- Commentaire
- Première variation : attributs
- Deuxième variation : liste
- Troisième variation : attributs + liste
IV. Rudiments de XPath V. Structures de contrôle, règles paramétrées, règles nommées VI. Un exemple (relativement) complet
- L'unité de base de la programmation XSLT est la règle.
- Mécanisme récursif
- Application d'une règle à un sommet (nœud) de l'arbre XML
- Retour sur les règles implicites (ou "par défaut" : default rules)
- Variations avec le matériel dont nous disposons
separation of concerns : séparer la structure de la présentation
à partir du fichier XML [Nom_note_2.xml]
:
<?xml version="1.0" ?>
<liste>
<eleve>
<nom> Toto</nom> <note> 12 </note>
</eleve>
<eleve>
<nom> Tata</nom> <note> 13 </note>
</eleve>
<eleve>
<nom> Tutu</nom> <note> 17 </note>
</eleve>
<eleve>
<nom> Titi</nom> <note> 11 </note>
</eleve>
</liste>
on veut obtenir ce spectacle :
Pour cela, il faut transformer l'arbre XML en un texte HTML interprétable par le navigateur :
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Visualisation</title>
</head>
<body>
<h2> Voici le tableau des noms et des notes</h2>
<table border="2" bgcolor="yellow">
<tr>
<th>Nom</th>
<th>Note</th>
</tr>
<tr>
<td> Toto</td>
<td> 12 </td>
</tr>
<tr>
<td> Tata</td>
<td> 13 </td>
</tr>
<tr>
<td> Tutu</td>
<td> 17 </td>
</tr>
<tr>
<td> Titi</td>
<td> 11 </td>
</tr>
</table>
</body>
</html>
C'est l'objet de la feuille de style XSLT que voici [table.xsl]:
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html><head><title>Visualisation</title></head>
<body>
<h2> Voici le tableau des noms et des notes</h2>
<table border="2" bgcolor="yellow">
<tr>
<th>Nom</th>
<th>Note</th>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="liste/eleve">
<tr>
<td><xsl:value-of select="nom"/></td>
<td><xsl:value-of select="note"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" ?>
<liste>
<eleve nom="Toto" note="12"/>
<eleve nom="Tata" note="13"/>
<eleve nom="Tutu" note="17"/>
<eleve nom="Tutu" note="11"/>
</liste>
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html><head><title>Visualisation</title></head>
<body>
<h2> Voici la liste des noms et des notes</h2>
<ol>
<xsl:apply-templates/>
</ol>
</body>
</html>
</xsl:template>
<xsl:template match="liste/eleve">
<li>
<xsl:value-of select="nom"/> :
<xsl:value-of select="note"/>
</li>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0"?>en mode table et en mode liste.
<liste>
<eleve nom='Pierre'> <note> 12 </note>
</eleve>
<eleve nom="Paul"> <note> 13 </note>
</eleve>
<eleve nom='Jacques'> <note>17 </note>
</eleve>
</liste>
À chaque étape du calcul, l'interpréteur XSLT gère une
pile de nœuds candidats :
au commencement, cette pile contient un seul sommet qui est le Document.
Attention ! pas l'élément-racine au sens de XML mais le nœud qui représente le fichier XML tout entier,
et dont l'élément-racine est un fils - le seul qui nous intéresse pour le moment.
La collection des règles dans son ensemble est essayée
sur le nœud qui est au-dessus de la pile.
Appelons P ce nœud.
Normalement, au plus une seule règle doit se révéler applicable (via
l'évaluation de son attribut match).
Le cas échéant, un mécanisme de priorités entre en jeu pour sélectionner une règle entre plusieurs possibles,
nous n'examinerons pas cette éventualité ici, et nous ferons l'hypothèse qu'au plus une règle est applicable.
Dans le cas contraire, une erreur est signalée.
Si aucune règle ne s'avère applicable à P,
un mécanisme récursif se déclenche automatiquement :
Lorsque le sommet P n'a pas
d'enfants, on passe au suivant dans la pile.
Le calcul s'arrête lorsque la pile des candidats est épuisée.
Si une règle est applicable au sommet considéré, elle
s'applique (voir ci-après).
Cette application va d'une part produire du texte en sortie,
d'autre part faire apparaître de nouveaux sommets candidats,
qui sont empilés sur la pile gérée par l'interpréteur (mécanisme
récursif).
Après quoi le calcul (essai de la collection des règles ...) reprend
avec le nœud qui est le nouveau sommet de la pile.
C'est par rapport à ce sommet que sont évaluées les
expressions qui apparaissent
dans les attributs select (exemples ci-dessus) et
test (voir plus loin) du corps de la règle.
Prenons quelques exemples :
<html>Après quoi, l'exécution de <xsl:apply-templates /> provoque l'activation du mécanisme récursif :
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Visualisation</title>
</head>
<body>
<h2> Voici le tableau des noms et des notes</h2>
<table border="2" bgcolor="yellow">
<tr>
<th>Nom</th>
<th>Note</th>
</tr>
</table>et le calcul se termine.
</body>
</html>
<?xml version="1.0" encoding="utf-8"?>Si on ne veut pas de cet en-tête, on peut l'éviter en annonçant au début de la feuille de style :
<?xml version='1.0'?>
<Prog>
<Variables> <Var nom="a"/> <Var nom="b"/> <Var nom="q"/> <Var nom="r"/>
</Variables>
<Sequence>
<Lecture> <Var nom="a"/> </Lecture>
<Lecture> <Var nom="b"/> </Lecture>
<Affectation> <Var nom="q"/> <Cte val="0"/> </Affectation>
<Affectation> <Var nom="r"/> <VarExp> <Var nom="a"/> </VarExp> </Affectation>
<Boucle>
<Comparaison op=">="> <VarExp> <Var nom="t"/> </VarExp>
<VarExp> <Var nom="b"/> </VarExp>
</Comparaison>
<Sequence>
<Affectation> <Var nom="q"/>
<Bin op="+"> <VarExp> <Var nom="q"/> </VarExp> <Cte val="1"/> </Bin>
</Affectation>
<Affectation> <Var nom="r"/>
<Bin op="-"> <VarExp><Var nom="r"/></VarExp>
<VarExp><Var nom="b"/></VarExp>
</Bin>
</Affectation>
</Sequence>
</Boucle>
<Ecriture> <VarExp> <Var nom="q"/> </VarExp> </Ecriture>
<Ecriture> <VarExp> <Var nom="r"/> </VarExp> </Ecriture>
</Sequence>
</Prog>
<?xml version="1.0"?>
<Capitales>
<France>Paris</France>
<España>Madrid</España>
<Česko>Praha</Česko>
<Україна>Київ</Україна>
<България>София</България>
<Ελλάς>Αθήνα</Ελλάς>
<Россия>Москва</Россия>
<საქართველო>თბილისი</საქართველო>
<Հայաստան>Երեւան</Հայաստան>
<!-- <ኢትዮጵያ>አዲስ አበባ</ኢትዮጵያ> -->
<भारत>नई दिल्ली</भारत>
<தமிழ்_நாடு>ென்னை</தமிழ்_நாடு>
<ประเทศไทย>กรุงเทพฯ</ประเทศไทย>
<Việt_Nam>Hà Nội</Việt_Nam>
<中華>北京</中華>
<日本国>東京</日本国>
</Capitales>
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
<xsl:output method="html" encoding="utf-8" />
<xsl:template match="/">
<html><head><title>Visualisation</title></head>
<body>
<h2> Voici une liste de pays avec leurs capitales</h2>
<ul>
<xsl:apply-templates/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="Capitales/*">
<li>
<xsl:value-of select="name()"/> :
<xsl:value-of select="."/>
<!-- le contenu textuel du sommet courant -->
</li>
</xsl:template>
</xsl:stylesheet>
<xsl:template name="indent">
<xsl:param name="prof"/>
<xsl:if test="$prof>0">
<xsl:value-of select="$indentElem"/> <!-- envoi de la chaîne en sortie -->
<xsl:call-template name="indent"> <!-- appel récursif terminal -->
<xsl:with-param name="prof" select="$prof - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<?xml version="1.0?>
<liste >
<eleve nom="Luc" note="12" />
<eleve nom="Maurice" note="18" />
<eleve nom="Juliette" note="07" />
<eleve nom="Max" note="07" />
<eleve nom="Pierre" note="08" />
<eleve nom="Kevin" note="09" />
<eleve nom="Christine" note="12" />
<eleve nom="Joseph" note="09" />
<eleve nom="Elisabeth" note="07" />
<eleve nom="Elsa" note="09" />
<eleve nom="Jules" note="11" />
<eleve nom="Jean-Pierre" note="09" />
<eleve nom="Franck" note="12" />
<eleve nom="Francine" note="13" />
<eleve nom="Aline" note="12" />
<eleve nom="Jacques" note="09" />
<eleve nom="Mauricette" note="12" />
<eleve nom="Alexandre" note="09" />
<eleve nom="Antoinette" note="12" />
<eleve nom="Paulette" note="09" />
<eleve nom="Ernestine" note="18" />
<eleve nom="Julien" note="13" />
<eleve nom="Josette" note="19" />
</liste>
<chart>
<chart_data>
<row>
<null/>
<string>0</string>
<string>1</string>
<string>2</string>
<string>3</string>
<string>4</string>
<string>5</string>
<string>6</string>
<string>7</string>
<string>8</string>
<string>9</string>
<string>10</string>
<string>11</string>
<string>12</string>
<string>13</string>
<string>14</string>
<string>15</string>
<string>16</string>
<string>17</string>
<string>18</string>
<string>19</string>
<string>20</string>
</row>
<row>
<null/>
<number>0</number>
<number>0</number>
<number>0</number>
<number>0</number>
<number>0</number>
<number>0</number>
<number>0</number>
<number>3</number>
<number>1</number>
<number>7</number>
<number>0</number>
<number>1</number>
<number>6</number>
<number>2</number>
<number>0</number>
<number>0</number>
<number>0</number>
<number>0</number>
<number>2</number>
<number>1</number>
<number>0</number>
</row>
</chart_data>
</chart>
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
<xsl:output method="xml"
omit-xml-declaration="yes" indent="yes" encoding="utf-8" />
<xsl:variable name="noteMax" select="'20'" />
<xsl:strip-space elements="*" />
<xsl:template name="Base">
<!-- Réalisation de l'axe des abscisses, de 0 à 20
c'est le premier élément <row> de l'histogramme -->
<xsl:param name="nbase"/>
<xsl:if test="$nbase <= $noteMax">
<xsl:element name="string">
<xsl:value-of select="$nbase"/>
</xsl:element>
<xsl:call-template name="Base"> <!-- récursion terminale -->
<xsl:with-param name="nbase" select="$nbase+1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="Val">
<!-- Réalisation de l'axe des ordonnées,
c'est le second élément <row> de l'histogramme -->
<xsl:param name="nbase"/>
<xsl:if test="$nbase <= $noteMax">
<xsl:element name="number">
<xsl:value-of select="count(//eleve[@note=$nbase])"/>
</xsl:element>
<xsl:call-template name="Val"> <!-- récursion terminale -->
<xsl:with-param name="nbase" select="$nbase+1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="/">
<xsl:element name="chart">
<xsl:element name="chart_data">
<xsl:element name="row">
<xsl:element name="null"/>
<xsl:call-template name="Base">
<xsl:with-param name="nbase" select="0"/>
</xsl:call-template>
</xsl:element>
<xsl:element name="row">
<xsl:element name="null"/>
<xsl:call-template name="Val">
<xsl:with-param name="nbase" select="0"/>
</xsl:call-template>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
jfp% xsltproc qr.xml
VAR a; b; q; r; LIRE a ;
LIRE b ;
q := 0 ;
r := a ;
TANTQUE t >= b FAIRE
q := q + 1 ;
r := r - b
FINTQ ;
ECRIRE q ;
ECRIRE r
.
jfp%
Cette feuille de style se borne à mettre en scène le
produit de PrettyMIL.xsl dans un "cadre HTML".
Par conséquent elle proclame <xsl:output
method="html" ... />,
au contraire des deux autres qui sont neutres vis-à-vis de la méthode
de sortie, pour pouvoir être employées
dans toutes les situations.
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
<xsl:output method="html"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" encoding="utf-8"
indent="yes"/>
<xsl:include href="PrettyMIL.xsl"/>
<xsl:template match="/">
<html>
<head>
<title>Programme MIL</title>
</head>
<body>
<pre>
<xsl:apply-templates/>
</pre>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
C'est elle qui fait le gros du travail : le traitement des
instructions.
Les expressions forment un sous-langage à part, où les questions
d'indentation n'entrent pas.
La syntaxe à précédences dans les expressions arithmétiques offre
suffisamment de difficultés
pour qu'on sépare le traitement des expressions de celui des
instructions,
en le confiant à une feuille de style séparée.
On peut ainsi mettre au point les deux feuilles séparément, par exemple
en faisant fonctionner PrettyMIL
avec un imprimeur d'expressions en notation complètement parenthésée,
beaucoup plus facile à réaliser.
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
<xsl:output omit-xml-declaration="yes"/> <!-- non committal -->
<!-- Pretty MIL (format XML version ISTM-2007)
avec indentations et importation des ExpAr -->
<xsl:strip-space elements="*" />
<xsl:include href="../ExpAr/ExpArBoolMIL2ap.xsl"/>
<xsl:variable name="indentElem" select="' '"/>
<xsl:template name="indent">
<!-- en l'absence d'effets de bord, la boucle habituelle se réalise
avec une récursion terminale -->
<xsl:param name="prof"/>
<xsl:if test="$prof>0">
<xsl:value-of select="$indentElem"/>
<xsl:call-template name="indent">
<xsl:with-param name="prof" select="$prof - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="/Prog">
<xsl:apply-templates select="Variables"/> <!-- marque explicitement l'ordre -->
<xsl:apply-templates select="Sequence">
<xsl:with-param name="prof" select="0"/>
</xsl:apply-templates>
<xsl:text>.</xsl:text> <!-- le point final -->
</xsl:template>
<xsl:template match="Variables">
<xsl:text>VAR </xsl:text> <!-- ASCII-32 = espace -->
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="Variables/Var[position() != last()]">
<xsl:value-of select="@nom"/>
<xsl:text>; </xsl:text>
</xsl:template>
<xsl:template match="Variables/Var[position() = last()]">
<xsl:value-of select="@nom"/>
<xsl:text>. </xsl:text>
</xsl:template>
<xsl:template match="Sequence">
<xsl:param name="prof"/>
<!-- l'emploi d'une itération évite de dédoubler toute la collection
des règles relatives aux différentes instructions
-->
<xsl:for-each select="*"> <!-- tous les enfants, dans l'ordre -->
<xsl:call-template name="indent">
<xsl:with-param name="prof" select="$prof"/>
</xsl:call-template>
<xsl:apply-templates select="."> <!-- chaque enfant -->
<xsl:with-param name="prof" select="$prof"/>
</xsl:apply-templates>
<xsl:if test="position()<last()"> <!-- l'entité est obligatoire en XSLT -->
<xsl:text> ; </xsl:text> <!-- point-virgule et ASCII-10 = LF -->
</xsl:if>
<xsl:if test="position()=last()">
<xsl:text> </xsl:text> <!-- LF sans point-virgule -->
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="Espace">
<xsl:text>ESP</xsl:text>
</xsl:template>
<xsl:template match="Ligne">
<xsl:text>LIG</xsl:text>
</xsl:template>
<xsl:template match="Lecture">
<xsl:text>LIRE </xsl:text>
<xsl:value-of select="Var/@nom"/>
</xsl:template>
<xsl:template match="Ecriture">
<xsl:text>ECRIRE </xsl:text>
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="Affectation">
<xsl:value-of select="Var/@nom"/>
<xsl:text> := </xsl:text>
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="Boucle">
<xsl:param name="prof"/>
<xsl:text>TANTQUE </xsl:text>
<xsl:apply-templates select="Comparaison"/>
<xsl:text> FAIRE </xsl:text>
<xsl:apply-templates select="Sequence">
<xsl:with-param name="prof" select="$prof + 1"/>
</xsl:apply-templates>
<xsl:call-template name="indent">
<xsl:with-param name="prof" select="$prof"/>
</xsl:call-template>
<xsl:text>FINTQ</xsl:text>
</xsl:template>
<xsl:template match="Conditionnelle">
<xsl:param name="prof"/>
<xsl:text>SI </xsl:text>
<xsl:apply-templates select="Comparaison"/>
<xsl:text> ALORS </xsl:text>
<!-- voir ExpAr/Bin : il ya deux fils "Sequence" à distinguer ! -->
<xsl:apply-templates select="./*[position()=2]">
<xsl:with-param name="prof" select="$prof + 1"/>
</xsl:apply-templates>
<xsl:call-template name="indent">
<xsl:with-param name="prof" select="$prof"/>
</xsl:call-template>
<xsl:text>SINON </xsl:text>
<xsl:apply-templates select="./*[position()=3]">
<xsl:with-param name="prof" select="$prof + 1"/>
</xsl:apply-templates>
<xsl:call-template name="indent">
<xsl:with-param name="prof" select="$prof"/>
</xsl:call-template>
<xsl:text>FINSI</xsl:text>
</xsl:template>
<!-- ======== Expressions arithmétiques & booléennes : importées ======== -->
<!-- et voila tout ! -->
</xsl:stylesheet>
Pour illustrer le propos relatif à la division entre
instructions et expressions, voici d'abord
une feuille de style réalisant l'impression des expressions en syntaxe
complètement parenthésée,
utile pour faire des essais.
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
<xsl:output omit-xml-declaration="yes"/> <!-- non committal -->
<xsl:strip-space elements="*" />
<!-- ======== Expressions arithmétiques & booléennes (version 2007) ========
munies d'une racine postiche "ExpAr" pour essais.
Nécessité de préciser quels éléments-fils sont visés par apply-templates
sous peine de voir répercuter les blancs précédants,
à cause des règles par défaut !
De même, <xsl:text>(</xsl:text> vaut mieux que '(' sec,
car le saut de ligne suivant vient avec !
-->
<xsl:template match="/ExpAr">
<!--Marqueur sans valeur sémantique, appel récursif global -->
<xsl:apply-templates/>
</xsl:template>
<!-- Traitement différencié des trois sortes d'expressions -->
<xsl:template match="Bin"> <!-- Le cas intéressant ! -->
<xsl:text>(</xsl:text>
<!-- On ne peut pas demander simplement "Bin|Cte|VarExp", car
alors les DEUX opérandes seraient traités simultanément !!!
Il faut absolument les distinguer par position -->
<xsl:apply-templates select="./*[1]"/>
<!-- on écrit l'opérateur, entre deux blancs -->
<xsl:value-of select="concat(' ', @op, ' ')"/>
<!-- appel récursif global sur l'opérande droit -->
<xsl:apply-templates select="./*[2]"/>
<!-- enfin on écrit la parenthèse fermante -->
<xsl:text>)</xsl:text>
</xsl:template>
<xsl:template match="Cte">
<xsl:value-of select="@val"/>
</xsl:template>
<xsl:template match="VarExp">
<xsl:value-of select="Var/@nom"/>
</xsl:template>
<xsl:template match="Comparaison">
<!-- sur le même modèle que Bin -->
<xsl:apply-templates select="./*[1]"/>
<xsl:value-of select="concat(' ', @op, ' ')"/>
<xsl:apply-templates select="./*[2]"/>
</xsl:template>
<!-- et voila tout ! -->
</xsl:stylesheet>
Et voici la version officielle, avec le parenthésage
minimal
compte-tenu des précédences entre opérateurs.
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
<xsl:output omit-xml-declaration="yes" encoding="utf-8" />
<!-- ======== Expressions arithmétiques & booléennes (version 2007) ========
Une réalisation de l'impression en syntaxe à précédences (2 niveaux)
-->
<xsl:strip-space elements="*" />
<xsl:template match="/ExpAr">
<!--Marqueur sans valeur sémantique, appel récursif global -->
<xsl:apply-templates/>
</xsl:template>
<!-- L'impossibilité de définir une fonction de précédence
conduit à traiter séparément les 2 classes d'opérateurs -->
<xsl:template match="Bin[@op = '+' or @op = '-']">
<!-- on ne parenthèse pas l'opérande gauche
(association à gauche ou précédence) -->
<xsl:apply-templates select="./*[1]"/>
<!-- on écrit l'opérateur -->
<xsl:value-of select="concat(' ', @op, ' ')"/>
<!-- on parenthèse l'op. droit sauf si précédence -->
<xsl:choose>
<xsl:when test="./*[position()=2 and (@op='+' or @op='-')]">
<xsl:text>(</xsl:text>
<xsl:apply-templates select="./*[2]"/>
<xsl:text>)</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="./*[2]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Bin[@op = '*' or @op = '/']">
<!-- on parenthèse l'opérande gauche si précédence) -->
<xsl:choose>
<xsl:when test="./*[position()=1 and (@op='+' or @op='-')]">
<xsl:text>(</xsl:text>
<xsl:apply-templates select="./*[1]"/>
<xsl:text>)</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="./*[1]"/>
</xsl:otherwise>
</xsl:choose>
<!-- on écrit l'opérateur -->
<xsl:value-of select="concat(' ', @op, ' ')"/>
<!-- on parenthèse l'op. droit dans tous les cas Bin -->
<xsl:choose>
<xsl:when test="./*[position()=2 and name()='Bin']">
<xsl:text>(</xsl:text>
<xsl:apply-templates select="./*[2]"/>
<xsl:text>)</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="./*[2]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="Cte">
<xsl:value-of select="@val"/>
</xsl:template>
<xsl:template match="VarExp">
<xsl:value-of select="Var/@nom"/>
</xsl:template>
<xsl:template match="Comparaison">
<!-- sur le même modèle que Bin -->
<xsl:apply-templates select="./*[position()=1]"/>
<xsl:value-of select="concat(' ', @op, ' ')"/>
<xsl:apply-templates select="./*[position()=2]"/>
</xsl:template>
<!-- et voila tout ! -->
</xsl:stylesheet>