Skip to content

Filtrer sur un critère – N°9/XXX

08/03/2010

Nous sommes restés dans le billet précédent (n°8) sur une question haletante : pourquoi le tri sur le critère « Pourcentage d’inscrits dans la population » ne fonctionne pas ?

La réponse était fournie dans le billet n°7 (opérations mathématiques) :

Notez au passage certaines cellules comportant la valeur NaN, signifiant Not a Number. Cela signifie qu’il n’y avait pas de nombre pour le nombre d’inscrits dans le fichier : la population est toujours connue, mais le nombre d’inscrits n’est pas toujours fourni… Donc « rien » divisé par la population, ça ne donne pas 0 : ça ne donne rien.

Si on définit un critère de tri, en indiquant (en plus !) qu’il s’agit d’un nombre (data-type="number") et que le processeur trouve des données non conformes (NaN n’est pas une valeur, ce n’est même pas du texte, une chaîne de caractères : c’est l’indication d’une absence de valeur), le tri ne peut fonctionner.

Comment faire ?

La première solution consiste à indiquer au processeur que dans la boucle <xsl:for-each> ne vont entrer que des <ville> pour lesquels le nombre d’inscrits en 2008 est connu.

<xsl:for-each select="dll/ville[an2008/inscrits &gt; 0]">

Le processeur cherche donc, pour chaque noeud <ville>, s’il y a un noeud enfant <an2008> avec un noeud <inscrits> dont la valeur est supérieure à 0.

Deux remarques :

  1. le contenu des crochets suit la même syntaxe que le XPath « normal ».
  2. la condition supérieur à devrait s’écrire >, mais il faut mettre &gt;.

Supérieur, inférieur, et tous ces sortes de choses

& &amp;
< &lt;
> &gt;

Quelques caractères ont une signification pour le programme XSLT (et pour tout fichier XML, d’ailleurs).

  • Le chevron < ouvre une balise
  • le chevron > la ferme
  • le caractère & sert à définir des entités XML.
    En début de fichier XML, on peut définir un mot par une abréviation, que l’on précèdera dans tout le corps du fichier XML par le caractère &.
    Par exemple si je veux parler de la Mission de l’information scientifique et technique et du réseau documentaire, je vais écrire en tête de fichier que <!ENTITY MISTRD "Mission de l’information scientifique et technique et du réseau documentaire">. Et dans la suite de mon fichier je pourrai écrire &MISTRD;, le fichier m’affichera toujours le libellé complet.
    Bref, quand il voit le caractère &, le processeur considère qu’il a affaire à une entité XML (qui va du & au point-virgule suivant).

Si donc on veut réellement utiliser ces trois caractères, il faut écrire à la place leurs codes correspondants (qui sont, d’ailleurs, des entités XML :-)).

Donc interdiction d’écrire tels quels ces caractères, sauf pour mettre des balises ou des entités (soit dit en passant : il ne m’arrive jamais de créer des entités).

Revenons à nos moutons inscrits

Voici le fichier XSL permettant de trier sur le critère « pourcentage d’inscrits en 2008 ».

Le début et la fin sont déjà expliqués dans le billet 7 et n’ont pas bougé depuis. Je n’y reviens pas.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="html"/>
<xsl:template match="/">
<html>
<head>
<title>Stats DLL : Pourcentage d'inscrits dans la population</title>
</head>
<body>
<h3>Pourcentage d'inscrits en bibliothèque publique pour chaque ville, en 2005 et 2008</h3>
<table border="1"> <tbody>
Déjà vu dans le billet n°7
<tr>
<th>Rang</th>
<th>Ville</th>
<th>% en 2005</th>
<th>% en 2008</th>
</tr>
J’ai rajouté une colonne « Rang »
Comme les villes vont être triées par ordre de pourcentage décroissant (les villes ayant le plus grand nombre d’inscrits au regard de leur population), il peut être intéressant de parcourir la liste en ayant le rang fourni systématiquement
<xsl:for-each select="dll/ville[an2008/inscrits &gt; 0]"> La boucle est toujours au niveau des <ville>
Mais seules les villes correspondant à la condition (nombre d’inscrits de 2008 > 0) seront prises en compte
<xsl:sort select="(an2008/inscrits div an2008/population)" order="descending"/> Tri sur la valeur du pourcentage

L’attribut data-type n’est pas nécessaire : comme c’est le processeur XSL lui-même qui effectue le calcul, il sait quel genre de données est en sortie.

(J’ai enlevé la multiplication par 100 : il s’agit de faire un tri, donc multiplier par 100 chaque résultat de la division ou non fournira de toute façon la liste dans le même ordre)

<tr>
<td><xsl:value-of select="position()"/></td> Pour chaque ville, on ajoute une colonne.
Dans cette colonne, utilisation de la fonction position(), qui indique la place du noeud en cours (donc de la ville) dans la liste générée par la boucle <xsl:for-each>
Il s’agit bien de la position dans la liste produite (donc après le tri <xsl:sort>), pas de la position dans le fichier d’origine.

Ce rang ne prend pas en compte les villes « évacuées » (c’est-à-dire des villes dont le nombre d’inscrits de 2008 n’est pas connu)

<td><xsl:value-of select="@nom"/></td> On retrouve ici le code du fichier présenté dans le billet n°7
<td><xsl:value-of select="(an2005/inscrits div an2005/population)*100"/></td>
<td><xsl:value-of select="(an2008/inscrits div an2008/population)*100"/></td>
</tr>
</xsl:for-each>
</tbody> </table> </body> </html> </xsl:template> </xsl:stylesheet>

Notez dans le tableau qui en résulte que les 5 premières villes ont plus de 100% d’inscrits. On les applaudit bien fort !

Pour résumer ce qui a été vu ici

Si vous avez lu trop vite, je vous rappelle donc que vous auriez dû voir :

  1. les codes pour les caractères <, > et &.
  2. la position(), permettant de connaître le rang d’un élément dans une liste
  3. le filtre sur un critère, par l’utilisation des crochets [ ]

Exercice : deux trois conditions pour le prix d’une

Déjà deux billets sans exercice : je ne pouvais pas vous laisser plus longtemps sans vous en proposer un !

Il faut générer un fichier HTML qui contienne un tableau avec les villes, les pourcentages d’inscrits en 2005 et 2008 (donc même structure qu’ici).

(pour l’instant, c’est exactement ce que je viens de faire)

Ce tableau ne contiendra que les villes dont le nombre d’inscrits en 2008 est connu, et dont la proportion d’inscrits a augmenté entre ces deux dates.

Le tri doit être fait sur l’augmentation de ce pourcentage : en tête viendront les villes dont la proportion d’inscrits a le plus augmenté.

Je crois que cet exercice-là est assez sympa 😉

Coup de pouce : puisque le pourcentage de 2005 entre en compte dans le critère de tri, il faut donc que lui-non plus ne soit pas NaN. Donc il faut d’abord que ces valeurs-là soient filtrées.

Et pour savoir comment mettre plusieurs conditions simultanées en XSL, vous avez le droit d’utiliser Internet…

Publicités
11 commentaires
  1. 09/03/2010 16:02

    Bonjour,

    Allez je me lance (entre 2 mises à jour de revues numériques) :

    pour être sur d’avoir des chiffres en 2008 et 2005


    et dont la proportion d’inscrits a augmenté entre ces deux dates.

    ...

    pour le tri qui doit être fait sur l’augmentation de ce pourcentage : en tête viendront les villes dont la proportion d’inscrits a le plus augmenté.

    … comme je n’ai pas encore installer de quoi faire tourner le xslt, ce n’est que pure conception !

    Une remarque : le résultat du traitement demandé méritera un titre très explicite, puisqu’il laissera dans l’ombre plusieurs villes.

  2. 09/03/2010 16:03

    ARgghhh il a masqué tout ce qui était entre et
    pouratnt « You can use basic XHTML in your comment »
    : -((

  3. 09/03/2010 16:07

    je voulais dire
    ARgghhh il a masqué tout ce qui était entre <code> et </code>
    pourtant « You can use basic XHTML in your comment »
    : -((

  4. 09/03/2010 16:12

    pour être sur d’avoir des chiffres en 2008 et 2005
    <xsl:for-each select="dll/ville[an2008/inscrits &gt; 0 and an2005/inscrits &gt; 0]">

    et dont la proportion d’inscrits a augmenté entre ces deux dates
    <xsl:if test="(an2008/inscrits div an2008/population) &gt; (an2005/inscrits div an2005/population)"> ... </xsl:if>

    pour le tri qui doit être fait sur l’augmentation de ce pourcentage : en tête viendront les villes dont la proportion d’inscrits a le plus augmenté.
    <xsl:sort select="(an2008/inscrits div an2008/population) &gt; (an2005/inscrits div an2005/population)" order="descending"/>

  5. 09/03/2010 16:43

    @Dominique : bravo, enfin qqun qui propose ce qu’il obtient. Et bravo pour le code proposé.
    La première ligne est parfaite.
    Pour la seconde : elle est très bien aussi, mais pour l’instant je n’ai pas encore parlé de la fonction <xsl:if/>.
    Donc en fait, ce que vous mettez dans cette condition, je l’inclus plutôt dans le filtre entre crochets dans le <xsl:for-each>

    Pour la 3e ligne (le tri), vous vous êtes planté : vous voulez trier sur le critère
    Pourcentage d’inscrits en 2008 > pourcentage d’inscrits en 2005, ce qui ne veut rien dire : pour deux villes ayant une proportion supérieure en 2008, comment sont-elles triées entre elles ?
    (et comme toutes les villes qui seront affichées correspondent à cette condition, la liste n’est pas du tout triée).

  6. 09/03/2010 17:32

    @Lully … oui c’est vrai que mon critère de tri est stupide !! : -\
    … Et si je trie par écart décroissant :

    <xsl:sort select="(an2008/inscrits div an2008/population) - (an2005/inscrits div an2005/population)" order="descending"/>

    ?

  7. 09/03/2010 18:23

    @Dominique : disons que j’étais arrivé au même résultat 🙂

Trackbacks

  1. Filtrer sur un critère (autres exemples) – N°10/XXX « Bibliothèques [reloaded]
  2. Techno-fil (21/03/10) « pintiniblog
  3. Définir un format pour les nombres — N°11/XXX « Bibliothèques [reloaded]
  4. Série XSL : Petite synthèse des billets passés (2) « Bibliothèques [reloaded]

Les commentaires sont fermés.

%d blogueurs aiment cette page :