Déboguer · Publié le

Lire une trace d'erreur Saxon sans la deviner

Les messages de Saxon nomment le fichier et la ligne, mais rarement la cause. Trois familles de messages couvrent l'essentiel, et chacune se lit différemment.

Un message d'erreur Saxon commence par un code de quatre lettres suivi de quatre chiffres. Le préfixe dit quel fichier ouvrir — et c'est l'information la plus utile de la ligne, parce qu'elle évite de relire le mauvais.

PréfixeOrigineLe fichier à ouvrir
SXXPanalyse du document sourcele XML d'entrée, pas la feuille
XPTYtype XPath incompatiblel'expression, et le type qu'elle reçoit
XTDEerreur dynamique de transformationle modèle en cours d'exécution
XTSEerreur statique de la feuillela feuille, avant toute exécution

Trois de ces familles surviennent pendant l'exécution ; la quatrième, XTSE, avant même qu'elle commence. ⚠️ La distinction compte : un XTSE signifie que rien n'a tourné, et chercher la cause dans les données est une perte de temps.

SXXP — c'est la source, pas la feuille

SXXP0003 est le plus fréquent : « Error reported by XML parser ». Saxon n'a pas transformé quoi que ce soit, il n'a pas réussi à lire le document d'entrée.

Les causes habituelles sont banales et n'ont rien à voir avec XSLT : une balise non fermée, une esperluette nue au lieu de &, un octet illégal pour l'encodage déclaré, ou une DTD référencée que le processeur ne trouve pas.

🔴 Le réflexe qui fait perdre le plus de temps est de relire la feuille de style. Ouvrez le XML d'entrée. S'il est volumineux, la ligne annoncée par le parseur est fiable — c'est un des rares cas où elle l'est complètement.

XPTY — le type reçu, pas le type attendu

XPTY0004 est le code de l'incompatibilité de type. Saxon l'accompagne presque toujours d'une phrase de la forme :

Required item type of first argument of fn:sum() is xs:anyAtomicType;
supplied value has item type element(montant)

Lisez la seconde ligne avant la première. L'attendu, vous le connaissez ; c'est le fourni qui vous apprend quelque chose — ici, que l'expression rend des éléments là où une fonction numérique attend des valeurs atomiques.

Le cas typique vient d'un chemin qui remonte des nœuds quand on croyait obtenir des nombres :

XSLT
<xsl:variable name="total" select="sum(ligne/montant)"/>

En XSLT 2.0 et au-delà, l'atomisation est implicite pour sum(), et ceci fonctionne — sauf si montant porte un type de schéma incompatible, ou contient du texte non numérique. Le message nomme alors le type réellement rencontré, et c'est la réponse.

⚠️ Un XPTY0004 sur une expression manifestement correcte signale presque toujours une donnée inattendue, pas une feuille fautive. Un seul <montant>N/A</montant> dans dix mille lignes suffit.

XTDE — pendant la transformation

Les XTDE surviennent en cours d'exécution, quand la feuille est valide mais qu'une situation la met en défaut. XTDE1490 en est un bon exemple : deux écritures dans le même fichier de sortie via xsl:result-document.

Ce qu'il faut retenir : le fichier à ouvrir est le modèle en cours, et la difficulté est de savoir lequel c'est. C'est précisément là que le numéro de ligne devient trompeur.

Pourquoi la ligne annoncée n'est pas toujours la bonne

Saxon évalue xsl:variable paresseusement : la valeur n'est calculée qu'au premier usage réel, pas à la déclaration.

XSLT
<xsl:variable name="total" select="sum(ligne/montant)"/>

<!-- ... cinquante lignes plus loin ... -->

<xsl:value-of select="$total + 1"/>

L'erreur est rapportée sur le xsl:value-of, parce que c'est là qu'elle s'est produite. La cause est sur la déclaration. Le numéro de ligne n'est pas faux — il désigne l'endroit où le problème s'est manifesté, pas celui où il a été écrit.

La même chose vaut pour une variable passée en paramètre : le message pointe le modèle appelé, la cause est chez l'appelant.

⚠️ La règle pratique : quand la ligne annoncée contient une variable, la lecture commence à la définition de cette variable, pas à la ligne annoncée.

Ce que cet article ne couvre pas

Les quatre familles ci-dessus laissent de côté au moins :

  • FORG et FOCA, les erreurs de fonctions et de conversion — FORG0001 sur un xs:date malformé, par exemple ;
  • XPDY0002, l'absence d'élément de contexte, typique d'une expression évaluée hors de tout nœud courant ;
  • XTMM9000, la terminaison volontaire par <xsl:message terminate="yes"/> — ce n'est pas une erreur du processeur mais une erreur écrite par vous, et le message est le vôtre ;
  • les erreurs remontées par une extension ou par le programme appelant, qui peuvent masquer le code d'origine.

🔴 Et un cas qu'aucune lecture de code ne rattrape : une trace tronquée. Beaucoup d'intégrations n'affichent que le premier message et jettent la cause chaînée. Si votre message se termine par une phrase générique sans code, ce n'est pas Saxon qui manque de précision — c'est ce qui l'enveloppe.

Savoir où l'on est, au lieu de le reconstituer

Les trois familles se lisent bien une fois qu'on sait quel modèle s'exécutait. Sur une feuille de quelques centaines de lignes, on le reconstitue de tête ; passé cette taille, on le devine.

Suspendre l'exécution à l'endroit signalé et remonter la pile répond à la question sans hypothèse : c'est ce que décrit le chapitre déboguer du manuel, et poser un point d'arrêt dans une feuille de style montre la manipulation. Le cas voisin — une transformation qui ne produit rien du tout, sans le moindre message — a ses propres causes, décrites dans les cinq causes silencieuses d'un XSLT vide.

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