FAQ XML
FAQ XMLConsultez toutes les FAQ
Nombre d'auteurs : 5, nombre de questions : 65, dernière mise à jour : 16 juin 2021
- Qu'est-ce que XSLT ?
- Est-ce que XSL et XSLT sont la même chose ?
- Qu'est-ce qu'un processeur XSLT ?
- Pourquoi cette FAQ ne parle pas de XSLT 2.0 ?
- Quels type de documents peut-on générer avec du XSLT ?
- Puis-je produire plusieurs documents en même temps avec un seul fichier XSLT ?
- Comment gérer les guillemets et apostrophes en XSLT ?
- Comment écrire dans les attributs d'un élément résultat (html, svg...) ?
- Peut-on modifier la valeur d'une variable XSLT ?
- j'ai crée une variable mais ma feuille n'arrive pas à l'atteindre ?
- Comment accéder à plusieurs documents XML dans une même feuille XSL ?
- Comment supprimer les doublons dans un affichage ?
- Comment regrouper les noeuds en fonction de leurs éléments qui se ressemblent ?
- Comment placer un espace insécable dans un XSLT pour une sortie HTML ?
- Comment changer le format d'une date ?
- Comment tester si un élément existe ?
- Comment effectuer l'équivalent d'une boucle avec compteur en XSLT ?
- Quelle est la différence entre . et current() ?
- Comment empêcher en entête de ma sortie le prologue <?xml version="1.0" encoding="quelque chose"> ?
- Comment puis-je faire apparaître des blocs CDATA dans le résultat d'une transformation ?
- Pourquoi ma soustraction ne fonctionne pas ?
- Comment tester si une valeur est NaN (Not A Number) ?
- Comment traiter le même élément de deux façon différente avec des templates ?
- La transformation d'un XML en HTML a supprimé espaces et sauts de lignes dans le résultat dans mon navigateur.
- Comment vérifier qu'une donnée est bien un nombre ?
- Problème de transformation XSLT avec un document xml dont les balises sont dans un namespace particulier
XSLT est un langage qui permet de transformer un (ou plusieurs) documents XML en un autre document XML, HTML ou texte.
Il est la plupart du temps utilisé afin de séparer les données (XML) du code/présentation (XSLT) pour un résultat final affichable (HTML). Une autre utilisation, moins répandue, est la conversion d'un schéma XML en un autre, afin de permettre l'interopérabilité entre des systèmes logiciels différents et qui communiquent par flux XML.
XSL (eXtensible Stylesheet Language) désigne la famille de spécifications comprenant:
- XPath
- XSLT
- XSL-FO (FO : Formatting Objects)
Pour ajouter à la confusion, XSLT était à l'origine conçu pour être essentiellement utilisé avec XSL-FO (ce qui n'est plus le cas, XSLT étant maintenant utilisé la plupart du temps indépendamment des Formatting Objects). De ce fait, l'abus de langage tend aujourd'hui à désigner XSL-FO sous le vocable de XSL.
Un processeur XSLT peut être comparé à une JVM pour JAVA. C'est lui qui va traduire puis exécuter les instruction de la feuille XSLT. Il prend donc en entrée un XML et un XSLT, puis produit en sortie un flux, un nouveau document XML ou d'un autre format (HTML, texte, etc.) au choix du développeur, à partir du moment où il s'agit d'un format texte (pas de sortie binaire). Chaque processeur a ses spécificités : respect plus ou moins strict de la spécification, librairie d'extensions disponibles, possibilité d'utilisation d'un autre langage (javascript, java....) au sein de la feuille xslt etc......
XSLT 2.0 est à ce jour seulement au stade de Candidate Recommendation. Seules quelques implémentations, plus ou moins complètes, existent.
Parmi ces implémentations, SAXON est réputée être une des plus complètes.
Il y a trois type de documents que l'on peut générer grâce à du XSLT, cela se choisit grâce à l'attribut method de la balise <xsl:output/> des documents XML (method="xml") des pages HTML (method="html") des documents textes quelconques (method="text") qui comprennent, entre autre, n'importe quel type de langage informatique (java,asp,php,sql...) qu'il suffira alors d'évaluer référence du w3c
Non, une feuille xslt 1.0 ne peut avoir qu'un seul résultat de sortie par exécution.
Cependant, de nombreux processeurs XSLT disposent d'extensions, c'est à dire d'éléments ou de fonctions ne
faisant pas partie de la spécification XSLT du W3C mais qui permettent d'accéder à des fonctionnalités bien pratiques,
comme la génération de fichiers multiples. Pour Xalan-J, par exemple, cette extension se présente sous la forme d'un élément <redirect>
(voir http://xml.apache.org/xalan-j/extensionslib.html#redirect).
Certaines extensions, particulièrement pratiques et très utilisées, ont fait l'objet d'une "normalisation informelle" qui a fait qu'elles se retrouvent implémentées de la même façon dans pratiquement tous les processeurs XSLT, sous la forme d'une librairie d'extensions. Le site EXSLT recense les fonctions qui constituent cette librairie, et que tout processeur doit (ou du moins devrait) implémenter.
La spécification XSLT 2.0 intègre cette fonctionnalité, avec l'élément <xsl:document>.
Le plus simple est de créer une variable de type fragment-node et de l'utiliser dans toutes les expressions XPath où
la chaîne comportant des guillemets ou apostrophes doit apparaître.
Exemple:
<
xsl
:
variable
name
=
"phrase"
>
Il a dit:"L'histoire ne s'arrêtera pas là"</
xsl
:
variable>
<
xsl
:
value-of
select
=
"//*[text()=$phrase]"
></
xsl
:
value-of>
deux méthodes:
1°) en utilisant un modèle de valeur d'attribut, une expression XPath entre accolades qui prend la place de la valeur de l'attribut dans la feuille de style.
Quand le processeur XSLT rencontre ce modèle, il le remplace par l'évaluation de l'expression XPath. Un modèle de valeur d'attribut peut également être utilisé pour les attributs de certains éléments XSLT, comme l'attribut name de <xsl:element> par exemple.
<a
title
=
"{l'expression Xpath souhaitée}"
>
à afficher</a>
2°) en utilisant l'élément <xsl:attribute>.
<a><
xsl
:
attribute
name
=
"title"
>
l'expression Xpath souhaité</
xsl
:
attribute>
à afficher</a>
L'élément <xsl:attribute> doit être placé avant tout code ajoutant du contenu (noeuds textuels ou autres éléments) à l'élément dans lequel il est placé.
Sans cela, l'attribut ne sera pas créé sans que le processeur XSLT ne signale d'erreur pour autant.
Non, les variables XSLT sont immutables et sont, par rapport à d'autres langages, plutôt comparables à des constantes.
Voir également un cours sur les variables XSLT
Les variables XSLT sont locales au noeud où elles sont déclarées, c'est pourquoi, si l'on veut des variables "globales" utilisables partout dans la feuille de style, il faut les déclarer juste après la balise ouvrante <xsl:stylesheet>.
Voir également Un cours sur les variables XSLT
En utilisant la fonction XSLT document(), qui prend en paramètre une URI et renvoie la racine du document pointé par cet URI.
Exemple - accéder aux noeuds test du document test.xml :
<xsl:value-of select="document('test.xml')/racine/test"/>
Cette fonction peut être utilisée dans n'importe quel attribut d'élément XSLT qui attend un chemin (variable, param, for-each, apply-templates, ...)
La fonction document() employée sans paramètre permet d'accéder à la racine de la feuille de style elle-même
On utilise la "Méthode Muench" : création d'une clé indexée par la valeur du noeud, et utilisation de la fonction generate-id() pour différencier les noeuds afin
de ne sélectionner que la première occurrence d'un noeud parmi ceux ayant la même valeur.
Exemple avec un tri sur le contenu d'une balise Id
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="id" match="Id" use="."/>
<xsl:template match="/">
<xsl:for-each select="//Id[generate-id(.)=generate-id(key('id', .)[1])]">
<xsl:value-of select='.'/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Exemple avec un tri sur le contenu de l'attribut val d'une balise Id
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="id" match="Id" use="@val"/>
<xsl:template match="/">
<xsl:for-each select="//Id[generate-id(.)=generate-id(key('id', @val)[1])]">
<xsl:value-of select='.'/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
il suffit d'opérer une variante de l'utilisation de la méthode Muench
<?xml version="1.0" encoding="UTF-8"?>
<r>
<t>
<a>
1</a>
<b>
test a</b>
</t>
<t>
<a>
2</a>
<b>
test b</b>
</t>
<t>
<a>
1</a>
<b>
test c</b>
</t>
<t>
<a>
2</a>
<b>
test d</b>
</t>
</r>
<?xml version="1.0" encoding="UTF-8"?>
<
xsl
:
stylesheet
version
=
"1.0"
xmlns
:
xsl
=
"http://www.w3.org/1999/XSL/Transform"
>
<
xsl
:
output
method
=
"xml"
version
=
"1.0"
encoding
=
"UTF-8"
indent
=
"yes"
/>
<
xsl
:
key
name
=
"regrouper"
match
=
"a"
use
=
"."
/>
<
xsl
:
template
match
=
"/"
>
<r>
<
xsl
:
apply-templates
select
=
"r/t/a[generate-id(.)=generate-id(key('regrouper',.)[1])]"
/>
</r>
</
xsl
:
template>
<
xsl
:
template
match
=
"a"
>
<t>
<
xsl
:
copy-of
select
=
"."
/>
<
xsl
:
apply-templates
select
=
"//b[../a=current()]"
/>
</t>
</
xsl
:
template>
<
xsl
:
template
match
=
"b"
>
<
xsl
:
copy-of
select
=
"."
/>
</
xsl
:
template>
</
xsl
:
stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<r>
<t>
<a>
1</a>
<b>
test a</b>
<b>
test c</b>
</t>
<t>
<a>
2</a>
<b>
test b</b>
<b>
test d</b>
</t>
</r>
Première possibilité : utiliser l'attribut disable-output-escaping de la balise <xsl:text>
<
xsl
:
text
disable-output-escaping
=
"yes"
>
&
nbsp;</
xsl
:
text>
Deuxième possibilité : remplacer l'entité par son équivalent en appel de caractère Unicode (32 en hexadécimal, 160 en décimal)
 
Il est également possible de déclarer cette entité dans une DTD interne ou externe
<?xml version="1.0"?>
<!DOCTYPE racine [
<!ENTITY nbsp
" "
>
]>
<racine>
Ce texte contient un espace insécable
!</racine>
Le type date n'existe pas nativement en xslt 1.0, on doit opérer des transformations de chaînes. On utilise généralement une combinaison de fonctions substring(), dont voici le prototype :
substring(chaîne, le numéro du caractère où commencer l'extraction, le nombre de caractères à extraire)
Par exemple, pour convertir le contenu d'un élément DATE du type '15/02/2004' en '20040215'.
<
xsl
:
template
match
=
"DATE"
>
<
xsl
:
value-of
select
=
"substring(., 7, 4)"
/>
<
xsl
:
value-of
select
=
"substring(., 4, 2)"
/>
<
xsl
:
value-of
select
=
"substring(., 1, 2)"
/>
</
xsl
:
template >
Simplement en mettant le chemin XPath de cet élément dans l'attribut test d'un xsl:if ou d'un xsl:when
exemple:
<racine>
<test>
existe</test>
</racine>
...
<
xsl
:
if
test
=
"/racine/test"
>
...
</
xsl
:
if>
....
Il faut écrire une fonction récursive et utiliser les passages de paramètres .
Par exemple, ce code écrit bonjour! le nombre de fois spécifié dans le paramètre fin
<
xsl
:
call-template
name
=
"compteur"
>
<
xsl
:
with-param
name
=
"iteration"
select
=
"0"
/>
<
xsl
:
with-param
name
=
"fin"
select
=
"3"
/>
</
xsl
:
call-template>
<
xsl
:
template
name
=
"compteur"
>
<
xsl
:
param
name
=
"iteration"
/>
<
xsl
:
param
name
=
"fin"
/>
<
xsl
:
if
test
=
"$iteration < $fin"
>
<
xsl
:
value-of
select
=
"'bonjour!'"
/>
<
xsl
:
call-template
name
=
"compteur"
>
<
xsl
:
with-param
name
=
"iteration"
select
=
"$iteration + 1"
/>
<
xsl
:
with-param
name
=
"fin"
select
=
"$fin"
/>
</
xsl
:
call-template>
</
xsl
:
if>
</
xsl
:
template>
current() est le noeud courant (celui pour lequel le template s'exécute) avant l'appel de l'expression XPath, . désigne le noeud en train d'être parcouru lors de l'évaluation de l'expression XPath. Le . est l'abréviation de self::node().
Voir le Cours XSLT
Par défaut, si vous ne spécifiez pas d'élément <xsl:output> ou que vous ne spécifiez pas ou ne mettez rien dans son attribut method, le processeur XSLT va générer du XML en sortie, et ajouter ce prologue. En choisissant judicieusement les valeurs des attributs de <xsl:output>, vous avez un ensemble de possibilités.
Pour générer du XML sans prologue (déconseillé, mais parfois nécessaire) :
<
xsl
:
output
method
=
"xml"
omit-xml-declaration
=
"yes"
.../>
Pour générer du XML sans prologue (déconseillé, mais parfois nécessaire) :
<
xsl
:
output
method
=
"html"
.../>
Il y a une autre valeur possible pour method, text, qui permet d'obtenir une sortie exempte de tout balisage.
En utilisant l'attribut cdata-section-elements de l'élément <xsl:output>, et en listant le nom des éléments figurant dans le
document de sortie et où l'on souhaite faire apparaître un bloc CDATA.
S'il y a plusieurs éléments concernés, leurs noms doivent figurer dans cet attribut séparés par des espaces.
<?xml version="1.0" encoding="UTF-8"?>
<R>
<a>
test1</a>
<b>
test2</b>
</R>
<?xml version="1.0" encoding="UTF-8"?>
<
xsl
:
stylesheet
version
=
"1.0"
xmlns
:
xsl
=
"http://www.w3.org/1999/XSL/Transform"
>
<
xsl
:
output
method
=
"xml"
version
=
"1.0"
encoding
=
"UTF-8"
indent
=
"yes"
cdata-section-elements
=
"a e"
/>
<
xsl
:
template
match
=
"/"
>
<R>
<
xsl
:
for-each
select
=
"R/*"
>
<a>
<
xsl
:
value-of
select
=
"."
/>
</a>
<e>
<
xsl
:
value-of
select
=
"."
/>
</e>
<f>
<
xsl
:
value-of
select
=
"."
/>
</f>
</
xsl
:
for-each>
</R>
</
xsl
:
template>
</
xsl
:
stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<R>
<a>
<![CDATA[
test1
]]>
</a>
<e>
<![CDATA[
test1
]]>
</e>
<f>
test1</f>
<a>
<![CDATA[
test2
]]>
</a>
<e>
<![CDATA[
test2
]]>
</e>
<f>
test2</f>
</R>
Le tiret faisant partie des caractères pouvant être utilisé dans le nom d'un élément, il faut le séparer par des espaces du reste de l'expression XPath pour que l'analyseur XPath le reconnaisse en tant qu'opérateur arithmétique. Par exemple, si l'on veut afficher le contenu de l'élément montant-facture, fils de l'élément courant, diminué de 1 :
<
xsl
:
value-of
select
=
"montant-facture-1"
/>
Le résultat affiché est erroné, car le processeur XSLT cherche à afficher le contenu d'un élément nommé montant-facture-1 fils de l'élément courant.
<
xsl
:
value-of
select
=
"montant-facture - 1"
/>
Soit $n une variable de type quelconque :
<
xsl
:
choose>
<
xsl
:
when
test
=
"string(number($n)) = 'NaN'"
>
$n n'est pas un nombre !</
xsl
:
when>
<
xsl
:
otherwise>
$n est un nombre</
xsl
:
otherwise>
</
xsl
:
choose>
Ce cas a été prévus par la norme XSLT et il existe un attribut mode dans l'apply-templates comme dans la templates qui permet de faire ce lien.Un exemple tout simple pour afficher la même donnée en gras ou en italique:
<?xml version="1.0" encoding="UTF-8"?>
<r>
<test>
un petit test</test>
</r>
<?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>
petit test</title>
</head>
<body>
<
xsl
:
apply-templates
select
=
"r/test"
mode
=
"gras"
/>
<br/>
<
xsl
:
apply-templates
select
=
"r/test"
mode
=
"italique"
/>
</body>
</html>
</
xsl
:
template>
<
xsl
:
template
match
=
"test"
mode
=
"italique"
>
<i>
<
xsl
:
value-of
select
=
"."
/>
</i>
</
xsl
:
template>
<
xsl
:
template
match
=
"test"
mode
=
"gras"
>
<b>
<
xsl
:
value-of
select
=
"."
/>
</b>
</
xsl
:
template>
</
xsl
:
stylesheet>
<html>
<head>
<META
http-equiv
=
"Content-Type"
content
=
"text/html; charset=UTF-8"
>
<title>
petit test</title>
</head>
<body><b>
un petit test</b><br><i>
un petit test</i></body>
</html>
Le processeur XSLT conserve par défaut tous les "blancs" (espaces, sauts de ligne, tabulation, etc.) des éléments XML qu'il manipule, et on les retrouve dans le document de sortie. C'est le navigateur qui à l'affichage effectue une "normalisation" du texte, en supprimant les espaces de début et de fin et en fusionnant les séquences de blancs successifs en un seul caractère espace. En HTML, pour conserver à l'affichage tous les espaces d'un texte, il suffit généralement de placer ce texte dans une balise <pre>.
soit $n une variable quelconque:
<
xsl
:
choose>
<
xsl
:
when
test
=
"string(number($n)) = 'NaN'"
>
$n n'est pas un nombre !</
xsl
:
when>
<
xsl
:
otherwise>
$n est un nombre.</
xsl
:
otherwise>
</
xsl
:
choose>
par exemple
<a
xmlns
=
"http://www.toto.fr"
>
<b>
</b>
<b>
</b>
</a>
Pour que le processeur xslt reconnaisse a et b qui sont dans un namespace, il faut le spécifier dans la feuille :
<
xsl
:
stylesheet
version
=
"1.0"
xmlns
:
xsl
=
"http://www.w3.org/1999/XSL/Transform"
xmlns
:
toto
=
"http://www.toto.fr"
>
<
xsl
:
template
match
=
"toto:a"
>
</
xsl
:
template>
<
xsl
:
template
match
=
"toto:b"
>
</
xsl
:
template>
</
xsl
:
stylesheet>