XSLT et transcodage

Lors de la transformation d'un fichier XML, il peut être nécessaire d'effectuer un transcodage sur certains éléments (migration d'une ancienne valeur vers une nouvelle). Les choses se compliquent si en plus ceci doit se faire à partir d'un référentiel externe contenant le mapping des données à utiliser.

Concrètement, voici un exemple de fichier XML initial :

<?xml version="1.0"?>
<OPS AD="FRA" FR="FRA">
      <LOG RC="FHZW" MA="VIAUD">
          <SPE SN="ANE" WT="5000.00">
            <PRO FF="A" PS="FRE" PR="WHL" TY="BOX" CF="1.00"></PRO>
            <RAS SR="23E6"></RAS>
          </SPE>
          <SPE SN="ANE" WT="5000.00">
            <PRO FF="A" PS="FRE" PR="WHL" TY="BOX" CF="1.00"></PRO>
            <RAS SR="24F8"></RAS>
         </SPE>
     </LOG>
</OPS>

Qui doit être convertit pour obtenir ceci (on change la valeur de l'attribut SR de l'élement RAS) :

<?xml version="1.0"?>
<OPS AD="FRA" FR="FRA">
      <LOG RC="FHZW" MA="VIAUD">
          <SPE SN="ANE" WT="5000.00">
            <PRO FF="A" PS="FRE" PR="WHL" TY="BOX" CF="1.00"></PRO>
            <RAS SR="FR23E6"></RAS>
          </SPE>
          <SPE SN="ANE" WT="5000.00">
            <PRO FF="A" PS="FRE" PR="WHL" TY="BOX" CF="1.00"></PRO>
            <RAS SR="FR24F8"></RAS>
         </SPE>
     </LOG>
</OPS>

La table de transcodage utilisée est située dans le document 'transcodage.xml' :

<mapping>
    <data>
        <item v1="23E6" v3="FR23E6" />
        <item v1="24F8" v3="FR24F8" />
    </data>
</mapping>

Pour arriver à nos fins, XSLT met à notre disposition l'élément xsl:key qui permet de définir une clé de recherche dans un document. Voici comment l'utiliser :

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
<xsl:variable name="map" select="document('transcodage.xml')"/>
<xsl:key name="mapPorts" match="/mapping/data/item" use="@v1"/>
 
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>
 
<xsl:template match="@SR[parent::RAS]">
    <xsl:variable name="codeV1" select="."/>
    <xsl:for-each select="$map">
        <xsl:attribute name="SR">
            <xsl:value-of select="key('mapPorts', $codeV1)/@v3"/>
        </xsl:attribute>
    </xsl:for-each>
</xsl:template>
 
</xsl:stylesheet>

Voici en détail le déroulement des opérations :

  • La variable map contient la table de transcodage.
  • La clé mapPorts permet d'indiquer : "je recherche tous les éléments correspondant à /mapping/data/item et je teste leur attribut v1
  • Dans le template gérant l'attribut SR du noeud RAS, on parcourt les éléments de la table de transcodage (en changeant temporairement de noeud racine grâce à xsl:for-each) afin de récupérer la valeur de l'attribut v3 de l'élément dont l'attribut v1 porte la valeur actuelle. En effet, l'appel à la fonction key() retourne l'élément qui a répondu aux conditions passées en paramètres (chemin décrit par la clé et valeur d'attribut)

Ainsi, chaque ancienne valeur sera remplacée par la valeur correspondante issue du document de mapping. Une autre syntaxe est possible, sans utiliser de clé :

<xsl:template match="@SR[parent::RAS]">
    <xsl:attribute name="SR">
       <xsl:value-of select="$map/mapping/data/item[@v1 = current()]/@v3"/>
    </xsl:attribute>
</xsl:template>

Cette solution est tout de même à modérer dans le cas de volume important de données.

Mon prochain article sera dédié au changement de namespace lors d'une transformation XSL.

Bon courage!


Fichier(s) joint(s) :

0 commentaires: