XSL (eXtensible Stylesheet Language) est un langage de style complet pour réordonner, dupliquer, changer la structure des éléments et construire des pages complexes (avec colonnes, tables des matières, etc). Il permet une présentation des données xml en (x)html ou en pdf (via xslfo).
Les feuilles de transformation XSLT sont des documents xml, régis par un schéma.
On leur donne l’extension .xslt
ou .xsl
.
xsltproc feuille.xsl document.xml > resultat.xml
En ajoutant la référence à la feuille de style à l’entête du fichier xml
<?xml-stylesheet type="text/xsl" href="feuille.xsl"?>
Lors de la transformation XML par XSL, le document XML est parcouru dans l’ordre. A chaque noeud XML (élément) rencontré, le système vérifie si un template dans le fichier XSL peut s’appliquer
Les noeuds texte non traités sont copiés dans le résultat
document.xml :
<?xml version="1.0"?>
<?xml:stylesheet type="text/xsl" href="style.xsl"?>
<biblio>
<book lang="fr">
<title>XML</title>
<auteur>Jean Martin</auteur>
</book>
<book lang="en">
<title>XML in action</title>
<author>John Smith</author>
</book>
<paper>
<title>XML software</title>
<date>05/02/2002</date>
</paper>
</biblio>
style.xsl :
<xsl:stylesheet version='1.0'
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- règle de production pour <book> -->
<xsl:template match="book">
<p>a book</p>
</xsl:template>
<!-- règle de production pour <book lang="en"> -->
<xsl:template match="book[lang='en']">
<p>a book in english </p>
</xsl:template>
<!-- règle de production pour pour <title> -->
<xsl:template match="title">
<p>a title</p>
</xsl:template>
</xsl:stylesheet>
Résultat de la transformation :
<p>a book</p>
<p>a book in english </p>
<p>a title</p>
05/02/2002
Tout comme tout document XML, une feuille de style XSL commence par un prologue
<?xml version="1.0"?>
Suivit de la déclaration des espaces de nommages
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
Après l’entête, se situe des templates XSL, qui correspondent à un ou des noeuds de l’arbre source.
Les templates contiennent des instructions XSL, des balises et du contenu à produire dans le document cible.
On peut cibler les noeuds sélectionnés avec XPath (syntaxe de sélection XML).
<xsl:stylesheet version='1.0' xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- S'applique la 1ere <section> -->
<xsl:template match="section[1]">
<p>Titre : <xsl:value-of select="title"/></p>
<xsl:apply-templates select="authors"/>
</xsl:template>
<!-- S'applique à tous les <authors> -->
<xsl:template match="authors">
<p><xsl:value-of select="."/></p>
</xsl:template>
</xsl:stylesheet>
À l’intérieur d’un template, le noeud courant est le noeud de l’arbre reconnu par l’attribut match
.
Les commandes XSL contenues dans le template peuvent également utiliser des expressions Xpath pour sélectionner des noeuds XML. Les expressions Xpath peuvent être absolues (racine de l’arbre source) ou relatives au noeud courant, mais la portée du noeud courant est le template pour lequel il est définit.
Permet de récupérer le contenu des feuilles texte d’un sous-arbre
style.xsl :
<xsl:template match="compte">
<p><xsl:value-of select="client"/></p>
<p><xsl:value-of select="solde"/></p>
</xsl:template>
document.xml :
<compte devise="euro">
<numero>123456KL</numero>
<client>
<nom>Dupont</nom>
<prenom>Michel</prenom>
</client>
<solde>1683.25</solde>
</compte>
Résultat :
<p>DupontMichel</p>
<p>1683.25</p>
Les accolades ({...}
) est l’équivalent de <xsl:value-of select="..."/>
Permet d’écrire explicitement un noeud texte
Isole le texte, pour ne pas reproduire les retours chariots
Avec text | Écrit directement |
---|---|
|
|
Client: Dupont |
Client: Dupont |
Par défaut, le texte est échappé
<xsl:text>coût < 100€ </xsl:text>
<xsl:text disable-output-escaping="yes">coût < 100€ </xsl:text>
Permet de formatter des nombres et de numéroter des éléments.
<xsl:template match="chapter">
<xsl:variable name="chapNum">
<xsl:number count="chapter" format="1" level="any"/>
</xsl:variable>
<xsl:value-of select="$chapNum"/>
</xsl:template>
Attributs :
count | Expression XPath qui spécifie les éléments à compter | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
level |
Définit les niveaux de l'arborescence à prendre en compte dans la numérotation
|
||||||||||||
from | Expression XPath qui définit quand commmencer le comptage | ||||||||||||
value | Expression XPath ou valeur littérale. Doit retourner un nombre. | ||||||||||||
format |
Définit le format du nombre généré
format="1. " ,
format="1) "
|
||||||||||||
lang | Définit le langage dont l'alphabet doit être utilisé | ||||||||||||
letter-value | alphabetic (par défaut) ou traditional . Spécifie si la numérotation dans le langage choisit est alphabétique (ex nombres romains) ou traditionnelle (valeurs numériques) |
||||||||||||
grouping-separator | Définit quel caractère doit être utilisé pour séparer les groupes de chiffres (, par défaut) |
||||||||||||
grouping-size | Spécifie combien de chiffres sont dans un groupe (3 par défaut) |
document.xml :
<items>
<item>
<item>Alice</item>
<item>Bob</item>
<item>Carole</item>
</item>
<item>
<item>Dave</item>
<item>Erin</item>
<item>Frank</item>
</item>
<item>
<item>Gena</item>
<item>Heather</item>
<item>Isabel</item>
</item>
</items>
table.xsl :
<xsl:template match="item">
<xsl:for-each select="item">
<xsl:element name="item">
<!-- single -->
<xsl:number format="1. " level="single" />
<xsl:value-of select="."/>
<!-- multiple -->
<xsl:number format="1. " level="multiple" />
<xsl:value-of select="."/>
<!-- any -->
<xsl:number format="1. " level="any" />
<xsl:value-of select="."/>
<!-- position() -->
<xsl:number format="1. " value="position()" />
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:template>
Resultat :
Single Multiple Any position()
1. Alice 1.1. Alice 2. Alice 1. Alice
2. Bob 1.2. Bob 3. Bob 2. Bob
3. Carole 1.3. Carole 4. Carole 3. Carole
1. Dave 2.1. Dave 6. Dave 1. Dave
2. Erin 2.2. Erin 7. Erin 2. Erin
3. Frank 2.3. Frank 8. Frank 3. Frank
1. Gena 3.1. Gena 10. Gena 1. Gena
2. Heather 3.2. Heather 11. Heather 2. Heather
3. Isabel 3.3. Isabel 12. Isabel 3. Isabel
<xsl:template match="item">
<xsl:for-each select="item">
<xsl:element name="item">
<xsl:number format="1. " level="single" from="*[position()>1]" />
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:template>
. Alice
. Bob
. Carole
1. Dave
2. Erin
3. Frank
1. Gena
2. Heather
3. Isabel
<xsl:template match="item">
<xsl:variable name="parent" select="count(preceding-sibling::*)"/>
<xsl:for-each select="item">
<xsl:element name="item">
<xsl:number format="1. " level="any" value="1 + count(preceding::*) - $parent" />
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:template>
1. Alice
2. Bob
3. Carole
4. Dave
5. Erin
6. Frank
7. Gena
8. Heather
9. Isabel
<xsl:number value="250000" grouping-separator="."/>
250.000
Permet d’appliquer les templates à la descendance d’un noeud auquel est appliqué un template (la descendance d’un noeud auquel est appliqué un template n’est pas traitée par défaut).
Si la cible de apply-templates
n’est pas précisée, la commande s’applique sur tous les fils du noeud courant. Sinon, on peut sélectionner les noeuds cibles avec XPath.
<xsl:apply-templates select="//para"/>
<xsl:apply-templates select="para[@class='title']"/>
style.xsl :
<xsl:template match="compte">
<p>
Propriétaire du compte :
<xsl:apply-templates select="client"/>
</p>
</xsl:template>
<xsl:template match="client">
<b><xsl:value-of select="nom"/></b>,
<xsl:value-of select="prénom"/>
</xsl:template>
document.xml :
<compte devise="euro">
<numero>123456KL</numero>
<client>
<nom>Dupont</nom>
<prenom>Michel</prenom>
</client>
<solde>1683.25</solde>
</compte>
Résultat :
<p>
Propriétaire du compte :
<b>Dupont</b>,
Michel
</p>
Placer un attribut mode
sur apply-templates
applique le template
avec ce même attribut. Cela permet de regrouper des templates pour définir des traitements particuliers.
<xsl:template match="chapter">
<div class="sommaire">
<ul>
<xsl:apply-templates select= "section" mode="sommaire"/>
</ul>
</div>
<xsl:apply-templates select="section"/>
</xsl:template>
<xsl:template match="section" mode="sommaire"/>
<li><xsl:value-of select="title"/></li>
</xsl:template>
<xsl:template match="section">
<div class="section"><xsl:apply-templates/></div>
</xsl:template>
Permet de regrouper dans un template des règles de production utilisées fréquemment
<xsl:template match='member'>
<xsl:call-template name="info "/>
...
</xsl:template>
<xsl:template match='guest'>
<xsl:call-template name="info "/>
...
</xsl:template>
<xsl:template name='info'>
Prénom : <xsl:value-of select="firstname"/>
Nom : <xsl:value-of select="lastname"/>
</xsl:template>
Permet d’insérer un commentaire <!-- ... -->
<xsl:comment> ... </xsl:comment>
Permet de générer explicitement un attribut pour l’élément en cours de production
name
spécifie le nom de l’attribut<xsl:template match="link">
<a>
<xsl:attribute name="title">
<xsl:value-of select= "linktitle"/>
</xsl:attribute>
<xsl:apply-templates/>
</a>
</xsl:template>
Permet de définir un groupe d’attribus
attribute
element
et copy
avec l’attribut use-attribute-sets
<xsl:attribute-set name="link-spec">
...
</xsl:attribute-set>
Permet de générer explicitement un élément
<xsl:template match="link[@dest='spec']">
<xsl:element name="a" use-attribute-sets= "link-spec">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
L’attribut use-attribute-sets
permet de référencer les
groupes d’attributs à produire, séparés par des espaces
Copier le noeud courant :
Permet de copier un noeud de l’arbre source
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
L’attribut use-attribute-sets
permet de référencer les
groupes d’attributs à produire, séparés par des espaces
Copier un attribut :
Permet de copier un attribut de l’arbre source
<xsl:template match="link">
<a>
<xsl:copy select="./@href"/>
<xsl:apply-templates/>
</a>
</xsl:template>
Permet de copier un sous-arbre de l’arbre source
select
spécifie le sous-arbre à copier par une expression XPath<xsl:template match="div[@class= 'menu']">
<xsl:copy-of select= ". "/>
</xsl:template>
La fonction document()
permet d’inclure un document xml tiers.
<xsl:copy-of select="document('labels.xml')">
On peut aussi appliquer les templates sur un document tiers :
<xsl:variable name='gurl'>
http://www.google.fr/search?q=<xsl:value-of select="$keyword"/>
</xsl:variable>
<xsl:apply-templates select="document($gurl)//table[2]">
Permet de boucler sur les noeuds d’un ensemble de noeuds
<xsl:template match="addressbook">
<xsl:for-each select="contact/name">
<xsl:value-of select="firstname"/>
<xsl:text> <xsl:text>
<xsl:value-of select="lastname"/>
</xsl:for-each>
</xsl:template>
Permet de traiter une condition
Il est parfois préférables d’utiliser deux templates
<xsl:template match="a">
<xsl:copy>
<xsl:attribute name="href">...</xsl:attribute>
<xsl:if test="not(start-with(@href,'http://example.fr')">
<xsl:text>(lien externe)</xsl:text>
</xsl:if>
<xsl:apply-templates>
</xsl:copy>
</xsl:template>
Conditions multiples
<xsl:choose>
<xsl:when test="condition 1">
...
</xsl:when>
<xsl:when test="condition 2">
...
</xsl:when>
<xsl:otherwise>
...
</xsl:otherwise>
</xsl:choose>
Permet de spécifier l’ordre d’application d’une instruction sur un ensemble de noeuds
S’applique sur apply-templates
et for-each
<xsl:for-each select="catalog/cd">
<xsl:sort select="artist"/>
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="artist"/></td>
</tr>
</xsl:for-each>
Attributs :
select | Critère de tri |
---|---|
lang | Pour les tris alphabétiques |
data-type | text ou number |
order | ascending ou descending |
case-order | upper-first ou lower-first |
Permet de définir une variable (non modifiable).
La valeur de la variable peut être le résultat d’une expression XPath ou un texte littéral
<xsl:variable name="position" select="count(active)"/>
<xsl:variable name="date">27/07/1969</xsl:variable>
Les variables ainsi définies peuvent ensuite être utilisées dans des expressions XPath.
On obtient leur valeur avec $
:
<xsl:apply-templates select="item[$position]"/>
<xsl:value-of select="$date"/>
Une variable déclarée dans un template est une variable locale, dont la portée est limitée au template.
La valeur d’une variable reste constante, tandis que la valeur d’un paramètre est une valeur par défaut, qui peut être modifiée avec with-param
lors de l’appel à call-template
ou apply-templates
.
<xsl:param name="COLOR" select="'black'"/>
<xsl:template match="item">
<font color="{$COLOR}">
<xsl:apply-templates/>
</font>
</xsl:template>
...
<xsl:apply-templates select="item">
<xsl:with-param name="COLOR" select="'blue'"/>
</xsl:apply-templates>
...
L’élément output
permet de paramétrer les options de sortie de la feuille de style
Attributs :
method | xml , text ou html |
---|---|
version | nmtoken |
encoding | string |
omit-xml-declaration | yes ou no |
standalone | yes ou no |
doctype-public | string |
doctype-systel | string |
cdata-section-elements | qnames |
indent | yes ou no |
media-type | string |
L’élément key
permet de créer un tableau associatif valeur/noeud. L’attribut match
définit les noeuds concernés et l’attribut use
permet de définir la valeur (la clé du tableau).
<xsl:key name="mykeys" match="footnote[@id]" use="@id"/>
On peut récupérer le noeud associé à une valeur donnée avec la fonction key(name, value)
Cette fonction est souvent utilisée avec generate-id(node)
, qui génère un id unique pour un noeud donné (ou le noeud courant si omis)
document.xml :
<body>
<p>Lorem ipsum dolor sit amet <ref footnote="1" /></p>
<footnotes>
<footnote id="1">Ma référence</footnote>
</footnotes>
</body>
style.xsl :
<xsl:output method="html" />
<!-- Keep body and p as is -->
<xsl:template match="body|p">
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<!-- Key map of footnotes -->
<xsl:key name="mykeys" match="footnote[@id]" use="@id"/>
<!-- Replace <ref footnote="id"> with link to footnote -->
<xsl:template match="ref[@footnote]">
<a href="#{generate-id(key('mykeys', @footnote))}">
<xsl:for-each select="key('mykeys', @footnote)">
<sup>(<xsl:number/>)</sup>
</xsl:for-each>
</a>
</xsl:template>
<!-- Footnotes list -->
<xsl:template match="footnotes">
<ul>
<xsl:for-each select="footnote">
<li>
<a name="{generate-id()}">
<xsl:number format="1. " />
<xsl:value-of select="."/>
</a>
</li>
</xsl:for-each>
</ul>
</xsl:template>
Résultat :
<body>
<p>Lorem ipsum dolor sit amet <a href="#id0xffffffffffc12300"><sup>(1)</sup></a></p>
<ul><li><a name="id0xffffffffffc12300">1. Ma référence</a></li></ul>
</body>
Une feuille de style .xsl peut inclure d’autres feuilles de style .xsl.
Deux méthodes sont disponibles: include
et import
.
include
permet d’inclure le contenu d’une autre feuille de style .xsl.
Une feuille inclue a la même précédence que la feuille parente. Si les deux feuilles de style définissent un même template, le template le plus en bas de la page est appliqué.
main.xsl :
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:for-each select="COLLECTION/BOOK">
<xsl:apply-templates select="TITLE"/>
<xsl:apply-templates select="AUTHOR"/>
<xsl:apply-templates select="PUBLISHER"/>
</xsl:for-each>
</xsl:template>
<!-- Le template suivant est overridé.
Il pourrait overrider doc.xsl s'il était placé en-dessous de include -->
<xsl:template match="TITLE">Title: <xsl:value-of select="."/></xsl:template>
<xsl:include href="doc.xsl" />
</xsl:stylesheet>
doc.xsl :
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="TITLE">Title - <xsl:value-of select="."/></xsl:template>
<xsl:template match="AUTHOR">Author - <xsl:value-of select="."/></xsl:template>
<xsl:template match="PUBLISHER">Publisher - <xsl:value-of select="."/></xsl:template>
</xsl:stylesheet>
import
permet d’importer des templates.
Pour appliquer les templates importés, il faut les appeler explicitement à l’intérieur d’un template de la feuille de style avec apply-imports
.
main.xsl :
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="doc.xsl"/>
<xsl:template match="example">
<div style="border: solid red">
<xsl:apply-imports/>
</div>
</xsl:template>
</xsl:stylesheet>
doc.xsl :
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="example">
<pre><xsl:apply-templates/></pre>
</xsl:template>
</xsl:stylesheet>
Résultat :
<div style="border: solid red"><pre>...</pre></div>
Permet de produire des messages au cours de la transformation, soit
<xsl:template match="section">
<xsl:message>
<xsl:text>Traitement de la section</xsl:text>
<xsl:value-of select="title"/>
</xsl:message>
...
</xsl:template>
Si le document source utilise plusieurs namespaces, ils doivent tous être déclarés dans la feuille de style et utilisé dnas les balises produits et les XPath.
<xsl:stylesheet version="1.0"
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:html= "http://www.w3.org/1999/xhtml">
...
<xsl:template match="html:body">
<fo:flow>
...
</fo:flow>
</xsl:template>
</xsl:stylesheet>