Accueil

Exemples XSLT

Afficher plein écran
 
Emmanuel Lazinier
Création de la page : 2001-04-09
Dernière mise à jour : 2001-06-28

Réaliser un histogramme en SVG (XSLT 1.0)

Soit le fichier xml suivant (effectifs.xml), présentant les effectifs d'une startup répartis par année d'entrée dans l'entreprise :
<?xml version="1.0" encoding="ISO-8859-1"?>
<effectifs>
   <classe>
      <annee_arrivee>1997</annee_arrivee>
      <nb_personnes>13</nb_personnes>
   </classe>
   <classe>
      <annee_arrivee>1998</annee_arrivee>
      <nb_personnes>20</nb_personnes>
   </classe>
   <classe>
      <annee_arrivee>1999</annee_arrivee>
      <nb_personnes>8</nb_personnes>
   </classe>
   <classe>
      <annee_arrivee>2000</annee_arrivee>
      <nb_personnes>5</nb_personnes>
   </classe>
   <classe>
      <annee_arrivee>2001</annee_arrivee>
      <nb_personnes>2</nb_personnes>
   </classe>
</effectifs>
On se propose de représenter ces effectifs sous forme d'un diagramme à barres, avec en abscisses les années d'ancienneté (de 0 à 5 ans) et en ordonnées le pourcentage du personnel ayant dépassé l'ancienneté considérée.


Voir le diagramme en SVG (plug-in requis)

Au moyen de l'élément SVG nous allons déclarer que notre image occupe tout l'écran et que dans notre espace utilisateur les abscisses iront de 0 à 1500 et les ordonnées de 0 à 1000 (unités utilisateur)

<svg width="100%" height="100%" viewBox="0 0 1500 1000">
La position de l'origine de notre système de coordonnées, la largeur des barres, le coefficient multiplicateur à appliquer aux ordonnées, l'espacement des barres vont être déclarés au tout début de la feuille de style, au moyen de paramètres dont la valeur sera exprimée en "unités utilisateur".
<xsl:param name="Ox" select="200" />
<xsl:param name="Oy" select="800" />
<xsl:param name="largeur_barre" select="200" />
<xsl:param name="pas_y" select="5" />
<xsl:param name="intervalle" select="30" />
Notre modèle de plus haut niveau sera donc de la forme suivante :
<xsl:template match="/">
<svg width="100%" height="100%" viewBox="0 0 1500 1000">
<title>Ancienneté à MarkupMyWeb</title>
<xsl:apply-templates/>
</svg>
</xsl:template>
Un second modèle va se contenter de mettre un titre à la page, de sélectionner l'ensemble des noeuds classe, de les classer par ordre décroissant de millésimes, puis de passer (récursivement) la main à un troisième modèle chargé de traiter spécifiquement ces noeuds classe
<xsl:template match="anciennetes">
<text style="font-size:60; font-family:'Comic Sans MS'; color:teal; text-anchor:middle;" x="750" y="100">
Répartition de l'ancienneté à <tspan style="color:red; font-style:italic">MarkupMyWeb</tspan>
</text>

<g style="filter:url(#MyFilter)">
<xsl:apply-templates>
<xsl:sort select="annee_arrivee" data-type="number" order="descending"/>
</xsl:apply-templates>
</g>
</xsl:template>

Le troisième modèle fait l'essentiel du travail. Il détermine la couleur de la barre en fonction de la position du noeud courant dans l'ensemble des noeuds sélectionnés. Il calcule le pourcentage des personnes entrées dans la société pendant l'année courante par rapport au cumul des personnes entrées pendant l'année courante et toutes les années précédentes. Et il appelle le modèle nommé barre chargé de générer la barre, en lui transmettant cette valeur, une légende à inscrire en-dessous de la barre, la position horizontale de la barre et sa couleur.
<xsl:template match="classe">

<xsl:variable name="couleur">
<xsl:choose>
<xsl:when test="position() mod 5 = 1">red</xsl:when>
<xsl:when test="position() mod 5 = 2">blue</xsl:when>
<xsl:when test="position() mod 5 = 3">green</xsl:when>
<xsl:when test="position() mod 5 = 4">purple</xsl:when>
<xsl:otherwise>orange</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:variable name="cumul">
<xsl:choose>
<xsl:when test="preceding-sibling::*"><xsl:value-of select="sum(preceding-sibling::*/nb_personnes)" /></xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<xsl:call-template name="barre">
<xsl:with-param name="valeur" select="round((nb_personnes + $cumul) div $total * 100)" />
<xsl:with-param name="legende">> <xsl:value-of select="2001 - annee_arrivee"/> année<xsl:if test="(2001 - annee_arrivee) &gt; 1">s</xsl:if>
</xsl:with-param>
<xsl:with-param name="posx" select="$Ox + (position() - 1)*($largeur_barre + $intervalle)" />
<xsl:with-param name="couleur" select="$couleur"/>
</xsl:call-template>

</xsl:template>

Note. On a tenu compte, dans l'évaluation de la variable cumul, du fait que pour l'année la plus ancienne, l'ensemble de noeuds preceding-sibling::* est vide : sum(preceding-sibling::*/nb_personnes) ne rend pas alors la valeur 0 mais la valeur null. Un test était donc nécessaire pour traiter convenablement ce cas particulier.

Le modèle nommé barre va dessiner le rectangle correspondant à la barre et le positionner par translation à l'endroit convenable. Il va porter la légende en dessous de la barre, et  inscrire au-dessus de la barrre la valeur correspondante suivie de l'unité convenable (% en l'occurence) -- elle-même définie comme paramètre au tout début de la feuille de style.

<xsl:template name="barre">

<xsl:param name="valeur"/>
<xsl:param name="posx"/>
<xsl:param name="legende"/>
<xsl:param name="couleur"/>

<xsl:variable name="hauteur" select="$valeur * $pas_y"/>

<g transform="translate({$posx}, {$Oy - $hauteur})" style="font-size: 30">
<text x="{$largeur_barre div 2}" y="-20" style="text-anchor:middle">
<xsl:value-of select="concat($valeur,' ',$unite)"/>
</text>
<rect width="{$largeur_barre}" height="{$hauteur}" style="fill:{$couleur}"/>
<text x="{$largeur_barre div 2}" y="{$hauteur + 40}" style="text-anchor:middle">
<xsl:value-of select="$legende"/>
</text>

</g>
</xsl:template>

Voir/Télécharger les fichiers de l'exemple :

Afficher l'histogramme "à la volée"

Attention : l'exemple présenté ci-dessus Existe-t-il une solution à ce problème ? Oui, et elle nous est fournie par Chris Bayes sur son site XML/XSL Portal (rubrique Inline SVG (IE5/Adobe SVG). Chris nous propose de :
  1. enchâsser le SVG généré dans une page HTML ;
  2. différentier le SVG par la référence à son espace de nommage ;
  3. donner un attribut id à l'élément SVG de plus haut niveau <svg:svg> ;
  4. associer le page HTML à un script (inlinesvg_2.js dans sa version actuelle).
Et le tour est joué !
Voir/Télécharger les fichiers correspondants :


Contribuez ! Faites-nous profiter de vos exemples les plus significatifs.

Retour à la page d'accueil.