1. Valeur, boucle et élément courant

1.1. value-of : affichage des valeurs

1.1.1. Déclaration

Cette déclaration, primordiale puisqu'elle est la seule qui permet l'affichage d'une valeur en xslt, ne peut se faire que dans un template. Comme les templates sont un chapitre suivant, les exemples déroulés ci-après se tiendront tous dans le tout premier template

 
Sélectionnez
<xsl:template match="/">
	<xsl:value-of select="'Cela affiche une string!'"/>
</xsl:template>

L'attribut select de xsl:value-of contient la donnée à afficher. Cette donnée peut être de la forme d'une chaîne (comme ci-dessus), d'un nombre ou d'un chemin xpath.

1.1.2. Comportement suivant les xpath

Pour ce paragraphe nous prendrons un xml "annuaire" comme exemple.

fichier xml
Sélectionnez
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="monfichier.xslt"?>
<annuaire>
	<personne>
		<nom>Dupond</nom>
		<prenom>Marc</prenom>
		<num_telephone>02 96 45 87 34</num_telephone>
	</personne>
	<personne>
		<nom>Dupont</nom>
		<prenom>Matthias</prenom>
		<num_telephone>03 45 67 25 99</num_telephone>
	</personne>
	<personne>
		<nom>Durand</nom>
		<prenom>Lucien</prenom>
		<num_telephone>01 45 29 62 77</num_telephone>
	</personne>
</annuaire>

Le xsl:value-of quand il a un xpath dans son attribut select affiche les données text() (les données uniquement textuelles qui se trouvent entre les balises) correspondantes. Si nous souhaitons par exemple afficher les données de la deuxième personne "Dupont Matthias" sur une ligne de tableau HTML, on utilisera le code suivant :

fichier xslt:
Sélectionnez
<?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></title>
		</head>
		<body>	
		<table>
			<tr>
				<td>
					<xsl:value-of select="/annuaire/personne[2]/nom"/>
				</td>
				<td>
					<xsl:value-of select="/annuaire/personne[2]/prenom"/>
				</td>
				<td>
					<xsl:value-of select="/annuaire/personne[2]/num_telephone"/>
				</td>
			</tr>
		</table>
		</body>
	</html>	
	</xsl:template>
</xsl:stylesheet>
résultat
Sélectionnez
<html>
	<head>	
		<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title></title>
	</head>
	<body
		><table>
			<tr><td>Dupont</td><td>Matthias</td><td>03 45 67 25 99</td>
			</tr>
		</table>
	</body>
</html>

Ceci correspond bien a chacun des text() des trois balises nom, prenom et num_telephone. Quel est le comportement sur un xpath qui sélectionne plusieurs noeuds ? Nous allons prendre tous les noms du fichier : //nom

fichier xslt
Sélectionnez
<?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></title>
		</head>
		<body>	
		<table>
			<tr>
				<td>
					<xsl:value-of select="//nom"/>
				</td>
 
			</tr>
		</table>
		</body>
	</html>	
	</xsl:template>
</xsl:stylesheet>
résultat
Sélectionnez
<html>	
	<head>	
		<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title></title>
	</head>
		<body>
			<table>
				<tr>
					<td>Dupond</td>
				</tr>
		</table>
	</body>
</html>

La réponse est simple, si un xpath sélectionne plusieurs noeuds seul le premier est affiché. Que se passerait-il par contre si le xpath sélectionné était celui d'un noeud qui en contient d'autres, comme les balises personnes ? Et bien ce serait le contenu text() de toutes les balises contenues qui s'afficherait :

fichier xslt
Sélectionnez
<?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></title>
		</head>
		<body>	
		<table>
			<tr>
				<td>
					<xsl:value-of select="/annuaire/personne[2]"/>
				</td>
 
			</tr>
		</table>
		</body>
	</html>	
	</xsl:template>
</xsl:stylesheet>
résultat
Sélectionnez
<html>
	<head>		
		<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title></title>
	</head>
	<body>
		<table>
			<tr>
			<td>DupontMatthias03 45 67 25 99</td>
			</tr>
		</table>
	</body>
</html>

Attention, je rappelle que le contenu d'un attribut n'est pas un text(). Si le fichier xml était modifié de cette façon :

fichier xml modifié:
Sélectionnez
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="monfichier.xslt"?>
<annuaire>
	<personne>
		<nom id="1">Dupond</nom>
		<prenom>Marc</prenom>
		<num_telephone>02 96 45 87 34</num_telephone>
	</personne>
	<personne>
		<nom  id="2">Dupont</nom>
		<prenom>Matthias</prenom>
		<num_telephone>03 45 67 25 99</num_telephone>
	</personne>
	<personne>
		<nom  id="3">Durand</nom>
		<prenom>Lucien</prenom>
		<num_telephone>01 45 29 62 77</num_telephone>
	</personne>
</annuaire>

En lui appliquant le fichier xslt précédant, le résultat ne serait pas modifié. La seule méthode pour afficher le contenu d'un attribut est d'utiliser le xpath correspondant:@nom_de_l_attribut.

variation sur le fichier xslt
Sélectionnez
<?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></title>
		</head>
		<body>	
		<table>
			<tr>
				<td>
					<xsl:value-of select="/annuaire/personne[2]/nom/@id"/>
				</td>
				<td>
					<xsl:value-of select="/annuaire/personne[2]/nom"/>
				</td>
				<td>
					<xsl:value-of select="/annuaire/personne[2]/prenom"/>
				</td>
				<td>
					<xsl:value-of select="/annuaire/personne[2]/num_telephone"/>
				</td>
			</tr>
		</table>
		</body>
	</html>	
	</xsl:template>
</xsl:stylesheet>
résultat
Sélectionnez
<html>
	<head>	
		<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title></title>
	</head>
	<body>
		<table>
			<tr>
				<td>2</td>
				<td>Dupont</td>
				<td>Matthias</td>
				<td>03 45 67 25 99</td>
			</tr>
		</table>
	</body>
</html>

1.2. Définition de l'élément courant

L'élément courant est le noeud sélectionné par le processeur, il n'est pas forcément celui qui est en cours de lecture ou d'affichage ; il ne peut être créé/modifié que par les instructions xsl:for-each ou les xsl:apply-templates . Dans ces boucles, il est le noeud en court de traitement, on peut l'atteindre par la fonction xslt: current()

 
Sélectionnez
<xsl:value-of select="current()"/>

La suite de ce cours va en détailler une partie, et le chapitre Tests et Conditions complétera ses particularités comportementales .

1.3. for-each : la boucle

1.3.1. Déclaration et fonctionnement

L'élément xsl:for-each est une boucle traitant tous les noeuds xml qui lui sont soumis, car en XSLT il n'existe pas de boucle indexée(for i=.. to ..) ; la boucle s'effectue toujours sur l'intégralité des données fournies dans le select du xsl:for-each Comme pour le xsl:value-of le chemin xpath lui est fourni dans son attribut select . Le code xslt encadré par les balises xsl:for-each sera donc appliqué sur chaque élément "visité" : l'élément courant current()

exemple de déclaration
Sélectionnez
<xsl:for-each select="//node()">
					<xsl:value-of select="current()"/>
 
</xsl:for-each>

1.3.2. Modification et utilisation de l'élément courant

Nous allons à nouveau sélectionner tous les noms, mais cette fois ci, au lieu de mettre le xpath dans le xsl:value-of, nous le soumettrons au xsl:for-each.

mon fichier xslt
Sélectionnez
<?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></title>
		</head>
		<body>	
		<table>
			<tr>
				<xsl:for-each select="//nom">
					<td>
					<xsl:value-of select="current()"/>
					</td>
				</xsl:for-each>				
			</tr>
		</table>
		</body>
	</html>	
	</xsl:template>
</xsl:stylesheet>
résultat:
Sélectionnez
<html>
	<head>
		<META http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title />
	</head>
	<body>
		<table>
			<tr>
				<td>Dupond</td>
				<td>Dupont</td>
				<td>Durand</td>
			</tr>
		</table>
	</body>
</html>

Cette fois ci nous pouvons observer que tous les noeuds ont bien été traités et que l'élément courant est bien le noeud en cours de lecture dans le xpath du select.

1.3.3. Comportement de parcours

Des tests précédents nous pouvons déjà déduire une partie du parcours des xpath . En effet, dans l'exemple précédent , le premier nom affiché est le premier rencontré en partant du haut du fichier . En nous servant du xsl:for-each et du xpath //node() qui sélectionne TOUS les noeuds du xml . Nous allons pouvoir voir l'ordre de parcours en utilisant un xml aux balises numérotées :

mon fichier xml
Sélectionnez
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="monfichier.xslt"?>
<racine num="0">
	<noeud num="1">
		<noeud num="3">
			<noeud num="5"/>
			<noeud num="6"/>
		</noeud>
		<noeud num="4">
			<noeud num="7"/>
		</noeud>
	</noeud>
	<noeud num="2"/>
</racine>
le fichier xslt
Sélectionnez
<?xml version="1.0" encoding="UTF-8"?>
 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
	<xsl:template match="/">
		<html>
			<body>
				<xsl:for-each select="//node()">
					<xsl:value-of select="concat(@num,' :: ')"/>
				</xsl:for-each>
			</body>
		</html>
	</xsl:template>
</xsl:stylesheet>
résultat
Sélectionnez
<html xmlns:fo="http://www.w3.org/1999/XSL/Format">
	<body> :: 0 :: 1 :: 3 :: 5 :: 6 :: 4 :: 7 :: 2 :: </body>
</html>

L'ordre est donc:

  1. a)Sens vertical du haut vers le bas prendre le premier aller en b)
  2. b)traiter le noeud aller en c)
  3. c)Si le noeud a un fils:
    - prendre le premier dans le sens vertical
    - retour en b)
    - sinon aller en d)
  4. d)Si dans le sens vertical il y a un "frère" à lui succéder aller en b) sinon en e)
  5. e)Je remonte au père du noeud s'il existe et aller en d) sinon aller en f)
  6. f) fin

attention le premier :: du résultat n'est pas une erreur . C'est simplement que le tout premier noeud sélectionner est : ?xml-stylesheet type="text/xsl" href="mon fichier.xslt"? comme il n'a pas d'attribut num , rien n'est affiché .

1.4. Complément sur l'élément courant

1.4.1. XPath sur l'élément courant

Jusqu'ici nous avons utilisé des chemins relatifs précédés de / (où il faut indiquer tout le chemin depuis la racine ) ou de // pour parser l'intégralité de l'arbre.Avec l'apparition de l'élément courant, nous allons pouvoir le prendre comme référent au lieu de la racine. Les XPath l'utilisant comme tel ne sont précédés ni de / , ni de // . Dans cet exemple, reprenant le fichier d'annuaire, on parcourt les différentes personnes et on affiche leur nom prenom, num_telephone via l'élément courant fixé par le xsl:for-each

fichier xslt
Sélectionnez
<?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/>
			</head>
			<body>
				<table>
					<xsl:for-each select="/annuaire/personne">
						<tr>
							<td>
								<xsl:value-of select="nom"/>
							</td>
							<td>
								<xsl:value-of select="prenom"/>
							</td>
							<td>
								<xsl:value-of select="num_telephone"/>
							</td>
						</tr>
					</xsl:for-each>
				</table>
			</body>
		</html>
	</xsl:template>
</xsl:stylesheet>
résultat
Sélectionnez
<html>
	<head>
		<META http-equiv="Content-Type" content="text/html; charset=UTF-8" >
		<title />
	</head>
	<body>
		<table>
			<tr>
				<td>Dupond</td>
				<td>Marc</td>
				<td>02 96 45 87 34</td>
			</tr>
			<tr>
				<td>Dupont</td>
				<td>Matthias</td>
				<td>03 45 67 25 99</td>
			</tr>
			<tr>
				<td>Durand</td>
				<td>Lucien</td>
				<td>01 45 29 62 77</td>
			</tr>
		</table>
	</body>
</html>

Pour des soucis de performances, il est à noter que se servir de l'élément courant comme base des xpath(comme ici), quand cela est possible, est toujours plus performant que d'utiliser des chemins préfixés / ou // .

1.4.2. Différence entre . et current()

Le " . " est un raccourci pour le xpath self::* et non pas pour la fonction xslt current(). Comme nous l'avons vu précédemment current() renvoie l'élément en cours de traitement.Self::* lui renvoi l'élément en cours de lecture. Par contre il est vrai que dans certains cas,comme dans le xsl:value-of ces éléments pointent sur le même noeud.

fichier xslt:
Sélectionnez
<?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/>
			</head>
			<body>
				<table>
					<xsl:for-each select="/annuaire/personne/nom">
						<tr>
							<td>
								<xsl:value-of select="current()"/>
							</td>
							<td>
								<xsl:value-of select="."/>
							</td>
 
						</tr>
					</xsl:for-each>
				</table>
			</body>
		</html>
	</xsl:template>
</xsl:stylesheet>
résultat:
Sélectionnez
<html>
	<head>
		<META http-equiv="Content-Type" content="text/html; charset=UTF-8" >
		<title />
	</head>
	<body>
		<table>
			<tr>
				<td>Dupond</td>
				<td>Dupond</td>
			</tr>
			<tr>
				<td>Dupont</td>
				<td>Dupont</td>
			</tr>
			<tr>
				<td>Durand</td>
				<td>Durand</td>
			</tr>
		</table>
	</body>
</html>

La différence se fait essentiellement dans les évaluations de xpath, lorsqu'on utilise des tests. Nous allons dans un premier xsl:for-each nous placer sur le nom de la première personne. //personne[1]/nom,suivent trois xsl:for-each imbriqués qui auront comme base commune de remonter de deux parents puis de parser à nouveau toutes les balises nom en effectuant un test :
Dans le premier select="parent::*/parent::*/personne[nom=current()]/nom", on ne sélectionne que les personnes dont le fils nom est égal au noeud courant.
Dans le second select="parent::*/parent::*/personne/nom[text()=.]", on ne sélectionne que les balises nom dont le contenu est égal à l'élément en cours de lecture (elle même).
Dans le dernier select="parent::*/parent::*/personne/nom[.=current()]", on ne sélectionne que les balises en lecture dont le contenu est égal à l'élément courant.

fichier xslt:
Sélectionnez
<?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/>
			</head>
			<body>
				<table>
					<xsl:for-each select="//personne[1]/nom">
					<tr>
						<xsl:for-each select="parent::*/parent::*/personne[nom=current()]/nom">
 
								<td>
									<xsl:value-of select="."/>
								</td>
 
 
						</xsl:for-each>
							</tr>	<tr>
						<xsl:for-each select="parent::*/parent::*/personne/nom[text()=.]">
 
								<td>
									<xsl:value-of select="."/>
								</td>
 
 
						</xsl:for-each>
							</tr>	<tr>
						<xsl:for-each select="parent::*/parent::*/personne/nom[.=current()]">
 
								<td>
									<xsl:value-of select="."/>
								</td>
 
						</xsl:for-each>
						</tr>
					</xsl:for-each>
				</table>
			</body>
		</html>
	</xsl:template>
</xsl:stylesheet>
résultat
Sélectionnez
<?xml-stylesheet type="text/xsl" href="C:\Documents and Settings\amoureux erwan\Mes documents\xml\tutoriel\boucle\test.xslt"?>
<html>
	<head>
		<META http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title />
	</head>
	<body>
		<table>
			<tr>
				<td>Dupond</td>
			</tr>
			<tr>
				<td>Dupond</td>
				<td>Dupont</td>
				<td>Durand</td>
			</tr>
			<tr>
				<td>Dupond</td>
			</tr>
		</table>
	</body>
</html>