Transcoder un fichier (XSLT 1.1)
Le fichier suivant comporte un certain nombre de caractères transcodés
qu'il convient de restituer à leur valeur originelle, selon le tableau
suivant :
Valeur actuelle
|
Valeur à restituer
|
%2C |
. |
%E9 |
é |
+ |
(espace) |
<?xml version="1.0" encoding="ISO-8859-1"?>
<commande>
<articles>
<article>
<ref>DCRTRV620</ref>
<quantite>1</quantite>
<garantie monnaie="USD">210%2C00</garantie>
</article>
<article>
<ref>139904</ref>
<quantite>1</quantite>
<garantie monnaie="FF">98%2C67</garantie>
</article>
</articles>
<Nom>Dupont</Nom>
<Prenom>Andr%E9-L%E9on</Prenom>
<adresse>10+chemin+des+Pr%E9s-Carr%E9s</adresse>
<Code_Postal>77300</Code_Postal>
<ville>Br%E9tigny</ville>
<email>James@positoile.com</email>
<telephone>0165487892</telephone>
<action>Envoyer</action>
</commande>
Notre feuille de transformation XSLT s'inspire de l'exemple
de transformation de fichier CSV précédemment publié
sur notre site.
La première partie de notre feuille de transformation XSLT va
consister en déclaration, sous la forme d'un paramètre, de
la table de transcodage:
<xsl:param name="transcodage">
<!-- Table de transcodage (ce pourrait être un fichier externe)-->
<item avant="%E9" apres="é"/>
<item avant="%2C" apres="."/>
<item avant="+" apres=" "/>
</xsl:param>
Chaque élément ("item") de ce fragment XML déclare
un transcodage élémentaire à effectuer. L'attribut
"avant" déclare une chaîne de caractères à transcoder
et l'attribut après le résultat attendu du transcodage de
cette chaîne.
Note.
Aux termes de la spécification XSLT 1.0, le paramètre
transcodage
tel que déclaré ici est un
fragment XML et n'est pas
considéré comme constituant du XML
bien formé.
A ce titre il est aujourd'hui illégal de naviguer, comme nous allons
le faire, à l'aide d'expressions XPath à l'intérieur
de ce fragment. Nous l'avons fait néanmoins parce que :
-
Il se trouve que le parseur MSXML
3.0, que nous avons utilisé permet depuis sa version de septembre
2000 de contourner cette interdiction par l'utilisation de la fonction
d'extension propriétaire msxsl:node-set(). Voir la Feuille
de transformation XSLT modifiée en conséquence
-
Il est très probable que cette illégalité disparaîtra
dès la version 1.1 de XSLT. Voir XSL
Transformations Requirements Version 1.1
Voir aussi
Getting
Value from XSL Parameters, par Kurt Cagle.
Viennent ensuite les templates qui sont au nombre de quatre.
Un premier template va reproduire à l'identique tous les noeuds
(éléments et attributs) du fichier source. Un deuxième
template va capturer spécifiquement les noeuds textuels du fichier
source, passer en mode "transcode" et donner le contrôle au template
de transcodage en lui passant en paramètre le noeud textuel.
<!-- Reproduire le document à l'identique
-->
<xsl:template match="@* | *">
<xsl:copy>
<xsl:apply-templates select="@* | * | text()"/>
</xsl:copy>
</xsl:template>
<!-- ...Sauf les textes, que l'on va transcoder -->
<xsl:template match="text()">
<xsl:apply-templates select="msxsl:node-set($transcodage)/*[position()=1]"
mode="transcode">
<xsl:with-param name="avanttranscodage" select="." />
</xsl:apply-templates>
</xsl:template>
Notre template de transcodage, lui, va naviguer sur la table de transcodage.
Il va la parcourir élément ("item") par élément
et à chaque fois passer la main au template nommé "substitue"
(équivalent d'une fonction dans un langage de programmation traditionnel).
Ce template va renvoyer, dans la variable 'aprestranscodage" le résultat
de la substitution correspondante. Et ainsi de suite jusqu'à ce
qu'il n'y ait plus d'élément dans la table de transcodage.
Le résultat final sera alors renvoyé au template appelant
qui va le substituer au noeud textuel initial.
<xsl:template match="*" mode="transcode">
<!-- template de transcodage. Navigue sur la table de transcodage
-->
<xsl:param name="avanttranscodage"/>
<xsl:variable name="aprestranscodage">
<xsl:call-template name="substitue">
<xsl:with-param name="atranscoder" select="$avanttranscodage"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="following-sibling::*">
<!-- Tant qu'il y a d'autres éléments dans la table
de transcodage, relancer le même template sur ces éléments
-->
<xsl:apply-templates select="following-sibling::*[position()=1]"
mode="transcode">
<xsl:with-param name="avanttranscodage" select="$aprestranscodage"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<!-- Sinon, renvoyer le résultat du transcodage -->
<xsl:value-of select="$aprestranscodage"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Le dernier template est donc un template nommé "substitue". Il substitue
une chaîne précise à une autre chaîne précise
(puisqu'il est positionné sur un élément précis
de la table de transcodage). Il le fait au coup par coup, en se rappelant
lui-même tant qu'il reste des substitutions de même type à
faire. Quand il n'en reste plus il renvoie le résultat de ces transcodages
successifs au template appelant.
<xsl:template name="substitue">
<!-- template récursif de susbstitution -->
<xsl:param name="atranscoder"/>
<xsl:choose>
<xsl:when test="contains($atranscoder,@avant)">
<!-- Si il reste qqch à transcoder, le transcoder -->
<xsl:variable name="resultat">
<xsl:value-of select="concat(substring-before($atranscoder,@avant),@apres,
substring-after($atranscoder,@avant))"/>
</xsl:variable>
<xsl:call-template name="substitue">
<!-- Relancer le même template sur le résultat pour
continuer le transcodage, s'il y a lieu -->
<xsl:with-param name="atranscoder" select="$resultat"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- Si plus rien à transcoder, ne rien faire et renvoyer
le paramètre "à transcoder" -->
<xsl:value-of select="$atranscoder"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Voir/Télécharger les fichiers de l'exemple
:
Contribuez ! Faites-nous profiter
de vos exemples les plus significatifs.
Retour à la page d'accueil.