Du bon usage de xsl:output
(révision du 10/11/2013)
- Principe
- Attributs
- method et version
- doctype-public, doctype-system
et standalone
- cdata-section-elements
- media-type
- Exemple : XHTML
- doctype
- namespace
- text
-
La balise
<xsl:output />
, comme son nom
l'indique,
gouverne la production du fichier-résultat.
Son rôle n'apparaît que lorsque ce fichier est effectivement produit !
Rappelons que, dans certains emplois de XSLT, le résultat de la
transformation est utilisé directement (et aussitôt jeté à la poubelle)
sans passer par une sortie sur fichier :
- Cas d'un navigateur qui affiche le HTML produit.
- Cas de Apache-Fop qui convertit le XSL-FO produit
en
un
flot
SAXResult
pour effectuer le rendu.
Il faut donc bien avoir présent à l'esprit que XSLT construit un
arbre
XML (un Document
au sens de DOM) et non pas un fichier.
Cet arbre est
- soit mis en œuvre directement, comme dans les cas d'usage
rappelés ci-dessus,
- soit envoyé dans un fichier suivant les modalités fixées
par
<xsl:output>
[cf. doc : When written out using the XML output
method ... ]
-
Liste officielle :
<xsl:output
method = "xml" | "html" | "text" | qname-but-not-ncname
version = nmtoken
encoding = string
omit-xml-declaration = "yes" | "no"
standalone = "yes" | "no"
doctype-public = string
doctype-system = string
cdata-section-elements = qnames
indent = "yes" | "no"
media-type = string />
Le rôle de certains de ces attributs du point de vue de la sortie sur
fichier est évident :
encoding
(valeur par défaut
UTF-8 ou
UTF-16, d'après la doc).
indent
(valeur par défaut "no"
)
omit-xml-declaration
(valeur par
défaut "no"
)
Les autres demandent quelques commentaires.
Il faut noter que tous ces attributs ne sont pas "linéairement
indépendants" :
le choix essentiel est celui de method
, et
l'interprétation précise des autres attributs en dépend.
-
(les deux vont
ensemble !)
version
s'applique seulement dans le cas de method
= "html"
, et sa valeur par défaut est "4.0
".
Ceci a pour conséquence que le fichier produit sera conforme à HTML-4,
et donc ne sera pas du XML correct !
Les "<br />
" soigneusement écrits dans le code XSLT
seront transcrits "<br>
"...
Or, la valeur par défaut de l'attribut method
est "html"
dès que l'élément-racine du document produit s'appelle "html"
(sans considération de casse) ! Sinon, c'est "xml"
.
Dans le cas method
= "xml"
la valeur par défaut de l'attribut version
est "1.0
".
Dans le cas method
= "text"
la question ne se pose plus.
-
Vu l'obscurité de la doc officielle, il est utile de
rappeler que
The
standalone pseudo-attribute is only relevant if a DTD is used.
et que par conséquent il ne faut déclarer standalone =
"no"
que si l'un des deux doctype est renseigné.
Bien que cela n'apparaisse pas dans la doc, on peut admettre que la
valeur par défaut de standalone
est "yes"
!
Sur le mode d'emploi de doctype
,
voir l'exemple
ci-après.
-
cdata-section-elements = "un deux trois
quatre..."
sert à expliquer que, dans le fichier de sortie,
les éléments <un>
, <deux>
, <trois>
,
etc doivent avoir des contenus en <![CDATA[...]]>
.
Rappel : ce format permet d'inclure dans un document XML du texte
incompatible avec la syntaxe de XML,
notamment du code JavaScript.
Exemple :
<?xml version='1.0'?>
<rac>
<jstxt><![CDATA[ if( x > 0
)...]]></jstxt>
<normal>alors, je lui ai dit...</normal>
</rac>
Cette spécification est utile vu le comportement de XSLT à l'égard
d'une donnée écrite avec <![CDATA[...]]>
:
cette indication est traitée sans ménagement, en transformant en
entités les caractères qui sont en contravention.
Cette manière de faire ne conduit à aucune perte d'information, certes,
mais elle rend le texte impropre à la consommation.
Voici l'effet de la feuille de style
<?xml version='1.0'?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'>
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<rec>
<res><xsl:value-of select="rac/jstxt"
/></res>
<ras><xsl:value-of select="rac/normal"
/></ras>
</rec>
</xsl:template>
</xsl:stylesheet>
sur la donnée ci-dessus :
<?xml version="1.0"?>
<rec>
<res> if( x > 0 )...</res>
<ras>alors, je lui ai dit...</ras>
</rec>
Alors que si on ajoute cdata-section-elements="res ras"
dans <xsl:output>
, on obtient :
<?xml version="1.0"?>
<rec>
<res><![CDATA[ if( x > 0 )...]]></res>
<ras><![CDATA[alors, je lui ai dit...]]></ras>
</rec>
Comme on le voit, l'information transmise est la même,
seule la forme diffère...
C'est donc bien une question de rédaction du fichier-résultat.
-
La documentation répète à l'envi que cet attribut permet
d'attribuer sa
valeur comme type MIME au fichier engendré,
l'exemple-type étant media-type = "image/svg"
(exemple,
à rectifier en remplaçant xmlns="http://www.w3.org/Graphics/SVG/SVG-19990812.dtd"
par xmlns="http://www.w3.org/2000/svg"
).
Mais le type MIME ne figure pas dans le fichier ! Quel est donc l'usage
de cet attribut ?
Voici ce que dit Microsoft :
The <xsl:output>
command includes one
additional attribute: media-type
. This attribute is
not used directly by the XSLT parser in generating output, but it
can be read from the style sheet through the DOM, and used to set the Response.ContentType
property. ContentType
creates a header in the returning
HTTP message. This header tells the browser how it should handle given
mime-types.
-
Que faut-il faire pour produire un fichier XHTML-strict et
contrôlable ?
-
La technique officielle est d'employer
<xsl:output
method="xml"
indent="yes"
doctype-public="-//W3C//DTD XHTML 1.0
Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>
qui engendre la déclaration
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
où on note que la mention SYSTEM
est
passée sous
silence, ce qui est conforme au mode de déclaration
des DTDs.
-
Bien sûr, on n'oubliera pas d'indiquer l'espace de noms
réglementaire dans la balise-racine
xsl:stylesheet
:
<xsl:stylesheet
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'>
Noter que l'emploi du préfixe vide (espace de noms par défaut) est
réservé au document produit :
si le document-source emploie lui aussi un espace de noms par défaut,
il faudra le déclarer avec un préfixe non-vide et écrire en
conséquence ses balises dans la feuille de style !
Noter également que cette manière de faire est la seule possible, car
malgré leur apparence les déclarations d'espaces de nom ne sont pas des
attributs !
Un écriture comme
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
..............
</html>
</xsl:template>
donne un résultat que les navigateurs acceptent mais qui sera rejeté
par le contrôleur http://validator.w3.org
...
-
On
peut aussi insérer la déclaration
<!DOCTYPE...>
comme du texte (au sens de <xsl:text>
) !
Il faut pour cela prendre quelques précautions.
- Comme "
<!
" et ">
" sont
incompatibles avec XML, il faut envelopper la chaîne dans un <![CDATA[...]]>
.
- Pour la même raison, il faut empêcher leur
transformation
en entités (cf. plus haut les explications sur
cdata-section-elements
).
Ceci est possible grâce à l'attribut disable-output-escaping
de la balise <xsl:text>
(existe aussi chez <xsl:value-of>
).
On arrive à :
<xsl:template match="/">
<xsl:text disable-output-escaping="yes">
<![CDATA[<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">]]>
</xsl:text>
<html xmlns="http://www.w3.org/1999/xhtml">
..............
</html>
</xsl:template>
Ce procédé n'est certes pas recommandable ici, mais son fonctionnement
est intéressant.
Il y a toujours plusieurs manières de procéder avec XSLT !