Conditions et tests en XSLT 1.0

erwan amoureux

Les conditions et les tests en XSLT, ainsi que quelques particularismes de l'élément courant.
Merci à Philippe Gibone et à Bestiol pour leur relecture.

- Titre : Conditions et tests en XSLT 1.0

- Auteur : erwan amoureux

- Parution : 10 novembre 2006

- Mise à jour : 12 juillet 2020

- Licence : Copyright ® 2006 Erwan Amoureux. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Conditions et tests en XSLT

- I-A. Rappel sur les opérateurs du Xpath

- I-B. xsl :if

- I-C. Le xsl:choose

- I-D. Tests particuliers sur l'élément courant

I - Conditions et tests en XSLT

Ci-dessous le fichier XML qui servira lors des démonstrations suivantes.

I-A - Rappel sur les opérateurs du Xpath

- l'égalité : =

- supérieur : &gt ;

- inférieur : &lt ;

- addition : +

- soustraction : - (attention ce symbole est accepté dans les noms de balises, il faut donc impérativement le faire précéder et succéder d'un espace si on veut qu'il soit interprété)

- division : div

- modulo : mod

I-B - xsl :if

En XSLT le si ? alors ? se code par l'utilisation de la balise xsl:if. Son attribut test contient le xpath qu'il faut tester, s'il est valide le code contenu à l'intérieur de la balise xsl:if est exécuté.

<xsl:if test="le xpath">......</xsl:if>

Les types de tests peuvent être séparés en deux catégories :
- tester la valeur d'un nœud ou d'une variable ;
- tester l'existence d'un nœud ou du contenu d'une variable.
On souhaite afficher dans un tableau tous les individus de sexe M (test sur la valeur)

le xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>nom</title>
</head>
<body>
<table>
<xsl:for-each select="//personne">
<xsl:if test="sexe= 'M' ">
<tr>
<td>
<xsl:value-of select="nom"/>
</td>
<td>
<xsl:value-of select="prenom"/>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

le résultat

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>nom</title>
</head>
<body>
<table>
<tr>
<td>Dupuis</td>
<td>Paul</td>
</tr>
<tr>
<td>Kaplan</td>
<td>Pierre</td>
</tr>
</table>
</body>
</html>

On souhaite afficher dans un tableau, tous les individus ayant un loisir (test sur l'existence)

le xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>loisirs</title>
</head>
<body>
<table>
<xsl:for-each select="//personne">
<xsl:if test="loisir ">
<tr>
<td>
<xsl:value-of select="nom"/>
</td>
<td>
<xsl:value-of select="prenom"/>
</td>
<td>
<xsl:value-of select="loisir"/>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

le résultat

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>loisirs</title>
</head>
<body>
<table>
<tr>
<td>Dupuis</td>
<td>Paul</td>
<td>Musique</td>
</tr>
<tr>
<td>Durand</td>
<td>Celine</td>
<td>Sports</td>
</tr>
<tr>
<td>Kaplan</td>
<td>Pierre</td>
<td>Cinema</td>
</tr>
</table>
</body>
</html>

Comportement de multiples xsl:if : Il est bien entendu possible de mettre de multiples xsl:if les uns derrière les autres, voire de les encapsuler entre eux. Dans le premier cas, ils s'exécuteront les uns après les autres. Cette balise ne permet pas l'expression d'un SINON.
Comme exemple nous regrouperons les deux demandes précédentes.

Le xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>2 demandes</title>
</head>
<body>
<table>
<xsl:for-each select="//personne">
<xsl:if test="sexe= 'M' ">
<tr>
<td>
<xsl:value-of select="nom"/>
</td>
<td>
<xsl:value-of select="prenom"/>
</td>
<td>Homme</td>
</tr>
</xsl:if>
<xsl:if test="loisir ">
<tr>
<td>
<xsl:value-of select="nom"/>
</td>
<td>
<xsl:value-of select="prenom"/>
</td>
<td>
<xsl:value-of select="loisir"/>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Le résultat

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>2 demandes</title>
</head>
<body>
<table>
<tr>
<td>Dupuis</td>
<td>Paul</td>
<td>Homme</td>
</tr>
<tr>
<td>Dupuis</td>
<td>Paul</td>
<td>Musique</td>
</tr>
<tr>
<td>Durand</td>
<td>Celine</td>
<td>Sports</td>
</tr>
<tr>
<td>Kaplan</td>
<td>Pierre</td>
<td>Homme</td>
</tr>
<tr>
<td>Kaplan</td>
<td>Pierre</td>
<td>Cinema</td>
</tr>
</table>
</body>
</html>

I-C - Le xsl:choose

La structure ressemble un peu à celle d'un CASE/SWITCH. Les différents cas (dont les tests ne sont pas obligés de se référer à une même variable ou nœud) sont énumérés les uns à la suite des autres. Si le test est valide, c'est le code contenu entre les deux balises (xsl:when) qui est exécuté. La balise xsl :otherwise correspond à un SINON.

<xsl:choose>
<xsl:when test="xpath1">
...
</xsl:when>
<xsl:when test="xpath1">
....
</xsl:when>
<xsl:otherwise>
....
</xsl:otherwise>
</xsl:choose>

Si des tests se recoupent, un seul est effectué : le premier déclaré.

le xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>choix</title>
</head>
<body>
<table>
<xsl:for-each select="//personne">
<tr>
<td>
<xsl:value-of select="nom"/>
</td>
<td>
<xsl:value-of select="prenom"/>
</td>
<xsl:choose>
<xsl:when test="sexe= 'M'">
<td>Homme</td>
</xsl:when>
<xsl:when test="loisir">
<td>
<xsl:value-of select="loisir"/>
</td>
</xsl:when>
<xsl:otherwise>
<td>autres</td>
</xsl:otherwise>
</xsl:choose>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

le résultat

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>choix</title>
</head>
<body>
<table>
<tr>
<td>Dupuis</td>
<td>Paul</td>
<td>Homme</td>
</tr>
<tr>
<td>Durand</td>
<td>Celine</td>
<td>Sports</td>
</tr>
<tr>
<td>Kaplan</td>
<td>Pierre</td>
<td>Homme</td>
</tr>
<tr>
<td>Gautier</td>
<td>Lucille</td>
<td>autres</td>
</tr>
</table>
</body>
</html>

On peut observer ici que les deux hommes ne sont repris qu'une fois au titre du test xsl:when test=« sexe= 'M' » Il est bien entendu tout à fait possible d'encapsuler des xsl:if ou des xsl:choose les uns avec les autres.

I-D - Tests particuliers sur l'élément courant

Lorsqu'un test est effectué sur l'élément courant, des notions Xpath comme name(), position(), text(), ? qui ne peuvent normalement être testées qu'entre [], peuvent être testées directement. Un exemple : nous allons construire un tableau par personne, sachant qu'en fonction de leur position() dans l'arbre (paire ou impaire) le tableau aura la « class » correspondante. L'intitulé des lignes sera le name() de la balise correspondante.

le xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>nom</title>
</head>
<body>
<table>
<xsl:for-each select="//personne">
<xsl:choose>
<xsl:when test="position() mod 2=0">
<table class="pair">
<xsl:for-each select="child::*">
<tr>
<td>
<xsl:value-of select="name()"/>
</td>
<td>
<xsl:value-of select="."/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:when>
<xsl:otherwise>
<table class="impair">
<xsl:for-each select="child::*">
<tr>
<td>
<xsl:value-of select="name()"/>
</td>
<td>
<xsl:value-of select="."/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

le résultat

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>nom</title>
</head>
<body>
<table>
<table class="impair">
<tr>
<td>nom</td>
<td>Dupuis</td>
</tr>
<tr>
<td>prenom</td>
<td>Paul</td>
</tr>
<tr>
<td>age</td>
<td>45</td>
</tr>
<tr>
<td>sexe</td>
<td>M</td>
</tr>
<tr>
<td>loisir</td>
<td>Musique</td>
</tr>
</table>
<table class="pair">
<tr>
<td>nom</td>
<td>Durand</td>
</tr>
<tr>
<td>prenom</td>
<td>Celine</td>
</tr>
<tr>
<td>age</td>
<td>54</td>
</tr>
<tr>
<td>sexe</td>
<td>F</td>
</tr>
<tr>
<td>loisir</td>
<td>Sports</td>
</tr>
</table>
<table class="impair">
<tr>
<td>nom</td>
<td>Kaplan</td>
</tr>
<tr>
<td>prenom</td>
<td>Pierre</td>
</tr>
<tr>
<td>age</td>
<td>23</td>
</tr>
<tr>
<td>sexe</td>
<td>M</td>
</tr>
<tr>
<td>loisir</td>
<td>Cinema</td>
</tr>
</table>
<table class="pair">
<tr>
<td>nom</td>
<td>Gautier</td>
</tr>
<tr>
<td>prenom</td>
<td>Lucille</td>
</tr>
<tr>
<td>age</td>
<td>27</td>
</tr>
<tr>
<td>sexe</td>
<td>F</td>
</tr>
</table>
</table>
</body>
</html>