XSLT et Saxon · Publié le

Choisir l'encodage de sortie d'un XSLT, et le vérifier

xsl:output encoding ne convertit pas toujours ce qu'on croit, et l'éditeur qui relit le fichier ment souvent sur le résultat.

XSLT
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>

Cette déclaration décide de deux choses, et de deux seulement : les octets que le sérialiseur écrit, et l'encodage annoncé dans la déclaration XML de tête. Elle ne dit rien de la lecture du document source, et 🔴 elle est ignorée quand ce n'est pas le sérialiseur qui écrit les octets.

C'est ce second cas qui produit les accents faux, et il est le seul des trois causes courantes qui laisse un fichier réellement corrompu.

Le piège du flux déjà encodé

Quand l'appelant fournit un Writer — un StringWriter, un OutputStreamWriter construit avec un encodage —, la conversion caractères → octets a déjà été décidée en dehors de la feuille. Le sérialiseur y écrit des caractères ; il n'a plus la main sur les octets.

⚠️ Mais il continue d'écrire la déclaration XML. Le fichier annonce donc encoding="UTF-8" pendant que ses octets sont en CP1252 : un document qui ment sur lui-même, et que le prochain analyseur rejettera ou lira de travers.

🔴 Le correctif tient en un mot : fournir un OutputStream, jamais un Writer. L'encodage redevient la décision de xsl:output, et déclaration et octets ne peuvent plus diverger.

Les trois causes, et où elles se situent

CauseOù elle se situeLe fichier est-il corrompu ?
source dont la déclaration ment sur son encodageà l'entréeoui, et souvent l'analyse échoue
sortie écrite via un flux déjà encodéà la sérialisationoui, et silencieusement
éditeur qui réinterprète le fichiernulle partnon — seul l'affichage est faux

⚠️ La troisième ligne fait perdre le plus de temps. L'éditeur devine l'encodage à l'ouverture, et il devine mal sur un fichier court ou peu accentué. Le fichier est correct, le rendu ne l'est pas, et on passe l'après-midi à corriger une feuille qui n'a rien.

Vérifier les octets, pas l'affichage

Le seul contrôle qui ne ment pas est le dump. Un é occupe deux octets en UTF-8 (c3 a9) et un seul en Latin-1 (e9) :

Shell
head -c 200 sortie.xml | od -A d -t x1z
  • c3 a9 avec encoding="UTF-8" déclaré : correct ;
  • e9 seul avec encoding="UTF-8" déclaré : le fichier ment, c'est le cas du flux déjà encodé ;
  • c3 83 c2 a9 : double encodage — les octets UTF-8 ont été relus comme du Latin-1 puis réencodés, et le fichier est passé deux fois par une conversion.

✅ Ces trois signatures se distinguent en un coup d'œil, et elles désignent chacune une cause différente. Aucune ne se lit dans un éditeur.

Ce que l'encodage ne règle pas

⚠️ Un caractère qui manque n'est pas un caractère mal encodé. Si la sortie perd du texte au lieu de l'abîmer, le problème est en amont : espaces conservés ou supprimés, modèle qui ne s'applique pas. Voir les espaces blancs, ou pourquoi la sortie a changé sans raison.

⚠️ Chaque document produit décide de son propre encodage. Un xsl:output global ne descend pas dans les résultats secondaires : c'est le point détaillé dans sorties multiples : ce que Saxon exige vraiment.

Ce que cet article ne couvre pas

  • method="html" et la balise meta charset que le sérialiseur injecte, qui ajoutent un troisième endroit où l'encodage est annoncé ;
  • les tables de caractères (xsl:character-map), qui remplacent des caractères plutôt que de les encoder ;
  • l'indicateur d'ordre des octets (byte-order-mark), utile en UTF-16 et nuisible en UTF-8 sur bien des chaînes de traitement.

Le chapitre transformer et exporter du manuel montre où se choisit le format de sortie et ce qui est écrit sur le disque.

Sur le même sujet

Recevoir les nouveaux articles

Un message quand un article paraît. Rien d'autre : ni promotion, ni relance, ni lettre d'information.

Votre adresse ne sert qu'à cela et n'est transmise à personne. Un lien de désinscription accompagne chaque message. Confidentialité

Tous les articles