separation of concerns : séparer la structure de la présentation
xsltproc
(cf. infra).javax.xml.transform.Source
)
vise à unifier les différentes provenances de
données.javax.xml.transform.sax
)javax.xml.transform.Result
:Result
n'est pas la valeur d'une
fonction ! ContentHandler
passé en paramètre à la création.DOMSource
pour la
transformation,
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder parseur =
dbf.newDocumentBuilder();
Document doc_xsl =
parseur.parse(nomFST);
DOMSource fst = new DOMSource(doc_xsl);
Trsf.java
)
:import
java.io.File;
import java.io.OutputStreamWriter;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
class Trsf {
public static void main( String[] args )
{
try{
String nomFich =
args[1];
String nomFST =
args[0]; // pour garder le même ordre des args. que xsltproc
Source don =
new StreamSource(new File(nomFich));
Result res =
new StreamResult(new OutputStreamWriter(System.out, "UTF-8"));
Source fst =
new StreamSource(new File(nomFST));
Transformer tf =
TransformerFactory.newInstance().newTransformer(fst);
tf.transform(don,
res);
}
catch(Exception e){
System.out.println(e.getMessage());
}
}
}// Trsf
<xsl:output>
<xsl:output>
.
Voir ici
pour
le détail.document(chaîne-URL)
livre la racine
de l'arbre du document visé.
<a href=".....">
:<xsl:template match="/html/body/ul/li/a">
<dc:description>
<xsl:value-of select="document(@href)/PLAY/TITLE/text()" />
</dc:description>
</xsl:template>
à 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: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,
ledocument
au sens du DOM,
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>
<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>
<xsl:apply-templates
/>
provoque l'activation du mécanisme récursif :<xsl:apply-templates
/>
de la première règle est épuisée, </table>
</body>
</html>
et le calcul se termine.<?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 :
priority
,
à valeur numérique :<xsl:template
match="monElem" priority="2">...
aura
précédence sur<xsl:template
match="monElem" priority="1">...
0.6
, et même négatif.-0.5
à 0.5
."*"
, ou "text()"
: priorité négative
= -0.5
;"monpréfixe:*"
: priorité négative = -0.25
;"toto"
ou "monpréfixe:toto"
: 0
;/
' ou un prédicat entre '[
' et ']
'
(voir ci-après)
: 0.5
."père/fils"
est plus
spécifique que "fils"
, puisqu'il ne sélectionne que
certains sommets "fils"
, "père/fils[@âge='25']"
ait la même priorité que "//fils"
.<monElem>
susceptible de recevoir un attribut (optionnel) monAttr
.monAttr
est présent,
indépendamment de sa valeurmonAttr
est présent et a
pour valeur "maChose".listHR1.xsl
et listHR2.xsl
sont en pratique équivalentes... mais pourquoi donc ?<xsl:template match="liste/eleve[position() !=
last()]"> <!-- tous sauf le dernier -->
<xsl:template match="liste/eleve[position() = last()]"> <!--
rien que le dernier -->
<xsl:template match="liste/eleve">
(supposée plus générale, donc moins prioritaire)<xsl:template match="liste/eleve[position() =
last()]" priority="1">
<xsl:template match="/">
<html><head><title>Visualisation</title></head>
.....
<xsl:apply-templates select="liste/*"
/>
.....
<xsl:template match="eleve">
(à présent, de priorité nulle)<xsl:template match="eleve[position() =
last()]">
(de priorité 0.5)<?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>
text()
" désigne
tous les contenus textuels du sommet
courant|
"<xsl:template match="* | /">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="text() | @*">
<xsl:value-of select="." />
</xsl:template>
Les
prédicatsmonElem[@
monAttr
]
"choisira
tous les élément monElem
pour lesquels l'attribut
(optionnel) monAttr
est présent,monElem[@
monAttr='maChose'
]
"
qui ne choisira que ceux pour lesquels l'attribut en question vaut 'maChose'
.monElem[@
*
]
"choisira
tous les élément monElem
pour lesquels au moins un
attribut est présent.and
, or
et not()
.sum
(applicable à des nombres) :<xsl:value-of
select="sum(/liste/eleve/note) div count(/liste/eleve)" />
<?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:
" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
)<html><head>...
",
nons sommes en train de construire un arbre par 'doc.createElement("html");
'...
.<xsl:output>
,method
, qui
prend ici la valeur "xml"
. <xsl:output>
.http://www.w3.org/1999/XSL/Transform
" assorti de
la version
- ici, '1.0'
).<xsl:stylesheet
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'
>
<xsl:output>
, voyez ici).<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0"
>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:m2trad="http://inalco/M2Trad/"
xmlns:h="http://www.w3.org/1999/xhtml"
>
name
".<xsl:template match="person">
<xsl:element name="name">
<xsl:attribute name= "username">
<xsl:value-of
select="@username"/>
</xsl:attribute>
<xsl:value-of select="name" />
</xsl:element>
</xsl:template>
<person username="Jim">
<name>Brown</name>
</person>
<name
username="Jim">Brown</name>
.<xsl:template match="person">
<name
username="{@username}">
<xsl:value-of select="name" />
</name>
</xsl:template>
{}
<xsl:template match="person">
<name
username="Jim">
<xsl:value-of
select="name" />
</name>
</xsl:template>
"{@username}"
a précisément pour
but de contourner cette difficulté !<xsl:copy-of
select="exp" />
à
ne pas confondre avec <xsl:copy>
!!!exp
.<xsl:copy>
pour sa part ne recopie que la balise de l'élément courant, sans ses
attributs ni ses fils.<xsl:element
name="{name(.)}"/>
Voici deux exemples simples utilisant cette instruction : <xsl:for-each>
(voir plus loin)critère
est une
expression applicable aux éléments à traiter <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>
mode
mode
", mode
", listeTriMoy.xsl
<?xml version='1.0'
encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'>
<xsl:output method="html"/>
<xsl:template match="/">
<html><head><title>Classement</title></head>
<body>
<p> Voici la liste des élèves par
rang de mérite </p>
<ol>
<xsl:apply-templates />
</ol>
<xsl:apply-templates mode="moy"
/>
</body>
</html>
</xsl:template>
<xsl:template match="liste">
<xsl:apply-templates>
<xsl:sort select="note" data-type="number"
order="descending"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="eleve">
<li>
<xsl:value-of
select="nom"/> :
<xsl:value-of
select="note"/>
</li>
</xsl:template>
<xsl:template match="liste" mode="moy">
<p> Voici la moyenne des notes</p>
<b>
<xsl:value-of
select="sum(eleve/note) div count(eleve)" /> / 20
</b>
</xsl:template>
</xsl:stylesheet>
listHR2.xsl
,
qui compte trois règles, est
équivalente à la suivante, qui n'en comporte qu'une :listFE.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 la liste des noms et des
notes</h2>
<ol>
<xsl:for-each
select="liste/eleve">
<li><xsl:value-of
select="nom"/> :
<xsl:value-of select="note"/>
</li>
<xsl:if
test="position()!=last()">
<hr
/>
</xsl:if>
</xsl:for-each>
</ol>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
choose
, et discussion des choix de style de
programmation.<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">
<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">
<xsl:with-param name="nbase" select="$nbase+1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="Val">
<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">
<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 (révision INaLCO-M2-IM octobre 2008)
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> <!-- ASCII-10 = LF -->
</xsl:if>
<xsl:if test="position()=last()">
<xsl:text> </xsl:text>
</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 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. (ExpArBoolMIL2cp.xsl
)
<?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 !
-->
<!-- on écrit d'abord la
parenthèse fermante -->
<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 -->
<!-- (1) appel récursif global
sur l'opérande gauche -->
<xsl:apply-templates select="./*[1]"/>
<!-- (2) on écrit l'opérateur, entre deux blancs
-->
<xsl:value-of select="concat(' ', @op,
' ')"/>
<!-- (3) 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 (ExpArBoolMIL2ap.xsl
).
<?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>