Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1926 connectés 

  FORUM HardWare.fr
  Programmation
  XML/XSL

  [Résolu] XSLT : grouper et sommer

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Résolu] XSLT : grouper et sommer

n°1759198
Lhalfelin
Posté le 14-07-2008 à 15:38:51  profilanswer
 

Bonjour,
 
Je suis nouveau dans le monde merveilleux du XSLT. Pour remettre dans le contexte, je fais un front-end pour une base Domino (Lotus Notes) en utilisant leur système de génération de XML (?ReadViewEntries pour ceux qui connaissent). Le problème est que la structure obtenue représente une succession de lignes (les <viewentry> ) avec des colonnes qu'elles ont toutes en commun (<entrydata> ), mais que je veux les grouper par la valeur de l'une de ces colonnes (en l'occurence la première, "auteur" ).
 
Fichier exemple :

<viewentries>
  <viewentry>
    <entrydata columnnumber="0" name="auteur">
      <text>NomDuPremierAuteur</text>
    </entrydata>
    <entrydata columnnumber="1" name="projet">
      <text>NomDuProjet</text>
    </entrydata>
    <entrydata columnnumber="2" name="nombre1">
      <text>12</text>
    </entrydata>
    <entrydata columnnumber="3" name="nombre2">
      <text>0</text>
    </entrydata>
    ... (il y a une dizaine d'autres valeurs numeriques similaires)
  </viewentry>
  <viewentry>
    <entrydata columnnumber="0" name="auteur">
      <text>NomDuPremierAuteur</text>
    </entrydata>
    <entrydata columnnumber="1" name="projet">
      <text>NomDunAutreProjet</text>
    </entrydata>
    ...
  </viewentry>
  <viewentry>
    <entrydata columnnumber="0" name="auteur">
      <text>NomDuSecondAuteur</text>
    </entrydata>
    <entrydata columnnumber="1" name="projet">
      <text>NomDEncoreUnAutreProjet</text>
    </entrydata>
    ...  
  </viewentry>
  ...
</viewentries>


 
La structure est un peu étrange (mais on peut pas avoir mieux en sortie de Lotus Notes hélas)
Les projets forment les "lignes", les enregistrements sont groupés par auteur.
 
Maintenant mes questions :  
1. Est-il possible, en XSL, d'aboutir à une structure XML où les <viewentry> seraient regroupés par auteur avec des balises <auteur nom=""> insérées entre <viewentries> et les <viewentry>, pour ensuite transformer facilement cette structure intermédiaire en HTML ?
 
2. Si la réponse à la question 1. est non, sachant que les <viewentry> sont triés par l'auteur (contenu dans le <text> contenu dans <entrydata columnnumber="0"> ) et que ce fichier XML est transformé en un tableau html montrant les valeurs numériques de chaque projet (les viewentry aux numéros de colonne >= 2), est-il possible d'afficher un tableau par auteur, pour mettre son nom en en-tête plutôt que dans chaque ligne ?
 
3. S'il y a une solution à la question 2, est-ce qu'il est possible, pour chaque tableau d'auteur, de rajouter une dernière ligne "total" faisant la somme des valeurs numériques des différents projets ?
 
Ce que je veux obtenir, c'est ça :

--- NomDuPremierAuteur ---
Projet           |donnee1|donnee2|....
NomDuProjet      |     12|      0|....
NomDunAutreProjet|     15|      5|....
Total            |     27|      5|....
 
--- NomDuSecondAuteur ---
Projet                 |donnee1|donnee2|....
NomDEncoreUnAutreProjet|      3|     10|....
Total                  |      3|     10|....
 
.......


 
Tout ça se ferait facilement avec un langage de script ou alors avec un fichier XML mieux structuré, mais j'ai que le XSL, qui m'a l'air suffisamment puissant pour faire ça.
 
 
J'ai tenté différentes choses :

<xsl:template match="viewentries">
<xsl:for-each select="viewentry/entrydata[@columnnumber='0']/text">


Le problème est qu'il me sélectionnait le même nom plusieurs fois, ce qui est logique.
 
J'ai essayé de mettre le nom de l'auteur dans une variable pour ensuite dé. Les "variables" d'XSL ont l'air d'être des constantes et les param ont l'air d'être le seul moyen de pouvoir stocker des valeurs... à condition d'appeler un template, ce qui oblige la récursivité, que je ne peux pas utiliser à cause de la génération de HTML dans ma template.
 
 
Enfin bref.
 
Des experts du XSL par ici ? :D
 
Merci beaucoup


Message édité par Lhalfelin le 18-07-2008 à 15:12:58
mood
Publicité
Posté le 14-07-2008 à 15:38:51  profilanswer
 

n°1760678
avander
Posté le 17-07-2008 à 09:22:37  profilanswer
 

Si tu pouvais donner un exemple de ce que tu veux pour chaque question ce serait plus précis.  
 
Je vois rien d'impossible dans le cahier des charges. Regarde la fonction Xpath sum(), xsl:sort, le XSLT c'est fait pour triturer du XML dans tout les sens de toute façon...


Message édité par avander le 17-07-2008 à 09:26:42
n°1760959
Lhalfelin
Posté le 17-07-2008 à 15:50:29  profilanswer
 

Bonjour avander
 
Pour la question 1, j'aimerais obtenir un XML intermédiaire plus commode

<viewentries>  
  <auteur nom="NomDuPremierAuteur">
    <viewentry>
      <entrydata columnnumber="0" name="auteur">
        <text>NomDuPremierAuteur</text>
      </entrydata>
      <entrydata columnnumber="1" name="projet">
        <text>NomDuProjet</text>
      </entrydata>
      <entrydata columnnumber="2" name="nombre1">
        <text>12</text>
      </entrydata>
      <entrydata columnnumber="3" name="nombre2">
        <text>0</text>
      </entrydata>
      ...  
    </viewentry>
    <viewentry>
      ...
    </viewentry>  
  </auteur>
 
  <auteur nom="NomDuSecondAuteur">
    <viewentry>
    ...  
    </viewentry>  
  </auteur>
</viewentries>


 
Evidemment si j'ai la possibilité de faire déjà ça je mettrai des balises plus explicites, mais ma question était surtout : est-il possible de faire un "group by" en xslt. J'ai continué à cherché hier sur le web mais les tutos et exemples en xlt sur le web cassent rarement des briques.  

Spoiler :

Heureusement les ressources sur MS Sharepoint (où est intégré mon XML/XSL) sont pires  :D


 
Pour les questions 2 et 3, le tableau façon ascii-art montre ce que je cherche à avoir avec la source donnée au début du post.
 
 
___________________________________
 
 
Pour faire ce que je veux, il faudrait dans mon "algo" :  
1) trouver la liste des auteurs rencontrés dans le fichier XML, sans doublon.
2) balayer le fichier pour chacun de ces auteurs et récupérer leurs projets respectifs
3) rajouter une ligne de somme pour chacun de ces auteurs
 
Je n'ai aucune idée de comment me débarasser des doublons dans le (1)
J'ai des problèmes avec la somme (voir ci-dessous)
 
___________________________________
 
J'ai fais des essais avec sum(), qui m'a systématiquement revoyé "0" ou "". [:lhalfelin]  
 

<x id=1><a>1</a><b>2</b><c>3</c></x>
<x id=2><a>3</a><b>4</b><c>5</c></x>
<x id=3><a>5</a><b>5</b><c>7</c></x>


 
Je sais que sum() est très fort si je veux pour chaque x faire a+b+c
Mais avec le XML dont je dispose, ce que je veux sommer est plutôt a[x id=1] + a[x id=2] + a[x id=3]
Sachant que les <x> sont très nombreux et que je ne souhaite que ceux qui contiennent, disons, une certaine valeur de <c> (dans mon exemple pratique c'est l'auteur).
 
 
Je vais jeter un oeil à xsl:sort

n°1761016
avander
Posté le 17-07-2008 à 17:25:06  profilanswer
 

Un début de réponse, il faut utiliser ce qu'on appelle une algo de 'munchian grouping', y'a un lien dans le code.
 

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<root>
<viewentries>
  <viewentry>
    <entrydata columnnumber="0" name="auteur">
      <text>NomDuPremierAuteur</text>
    </entrydata>
    <entrydata columnnumber="1" name="projet">
      <text>NomDuProjet</text>
    </entrydata>
    <entrydata columnnumber="2" name="nombre1">
      <text>12</text>
    </entrydata>
    <entrydata columnnumber="3" name="nombre2">
      <text>0</text>
    </entrydata>
    <!-- ... (il y a une dizaine d'autres valeurs numeriques similaires) -->
  </viewentry>
  <viewentry>
    <entrydata columnnumber="0" name="auteur">
      <text>NomDuPremierAuteur</text>
    </entrydata>
    <entrydata columnnumber="1" name="projet">
      <text>NomDunAutreProjet</text>
    </entrydata>
    <!-- ... -->
  </viewentry>
  <viewentry>
    <entrydata columnnumber="0" name="auteur">
      <text>NomDuSecondAuteur</text>
    </entrydata>
    <entrydata columnnumber="1" name="projet">
      <text>NomDEncoreUnAutreProjet</text>
    </entrydata>
    <!-- ... -->
  </viewentry>
  <!-- ... -->
</viewentries>
</root>
<!-- eof -->


 

<?xml version="1.0" encoding="ISO-8859-1"?>
 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 
<!-- general settings -->
  <xsl:output method="html" omit-xml-declaration="no" encoding="ISO-8859-1"/>
 
<!-- parameters -->
 
<!-- global variables -->
 
<!-- transformations -->
  <xsl:key name="nom-auteur" match="entrydata[@name='auteur']" use="text" />
 <!-- http://www.jenitennison.com/xslt/grouping/muenchian.xml -->
 
<xsl:template match="/">
  <xsl:text>DBG - Start XSLT
</xsl:text>
  <xsl:apply-templates /><!-- on amorce la tranformation -->
</xsl:template>
 
<xsl:template match="viewentries">
 
  <!-- boucle sur les noms d'auteur uniques ( basé sur muenchian grouping) -->
  <xsl:for-each select="//entrydata[@name='auteur'][generate-id() = generate-id( key('nom-auteur', text)[1])]">
 
    <xsl:variable name="vAuteurId" select="text" />
 
    <!-- relancer le traitement pour tous les viewentry d'un auteur particulier -->
    <auteur nom="{$vAuteurId}">
      <xsl:apply-templates select="//viewentry[entrydata[@name='auteur' and text=$vAuteurId]]" />
    </auteur><xsl:text><!-- retour a la ligne en xslt ! -->
</xsl:text>
 
  </xsl:for-each>
</xsl:template>
 
<xsl:template match="viewentry">
  <!-- le traitement c'est de copier-coller le sous-arbre entierement -->
  <xsl:copy-of select="."/>
</xsl:template>
 
</xsl:stylesheet>
<!-- eof -->


 
L'algo de regroupage est un peu chaude de premier abord, j'en conviens... le résultat est a la hauteur:

DBG - Start XSLT
 
<auteur nom="NomDuPremierAuteur"><viewentry>
    <entrydata columnnumber="0" name="auteur">
      <text>NomDuPremierAuteur</text>
    </entrydata>
    <entrydata columnnumber="1" name="projet">
      <text>NomDuProjet</text>
    </entrydata>
    <entrydata columnnumber="2" name="nombre1">
      <text>12</text>
    </entrydata>
    <entrydata columnnumber="3" name="nombre2">
      <text>0</text>
    </entrydata>
    <!-- ... (il y a une dizaine d'autres valeurs numeriques similaires) -->
  </viewentry><viewentry>
    <entrydata columnnumber="0" name="auteur">
      <text>NomDuPremierAuteur</text>
    </entrydata>
    <entrydata columnnumber="1" name="projet">
      <text>NomDunAutreProjet</text>
    </entrydata>
    <!-- ... -->
  </viewentry></auteur>
<auteur nom="NomDuSecondAuteur"><viewentry>
    <entrydata columnnumber="0" name="auteur">
      <text>NomDuSecondAuteur</text>
    </entrydata>
    <entrydata columnnumber="1" name="projet">
      <text>NomDEncoreUnAutreProjet</text>
    </entrydata>
    <!-- ... -->
  </viewentry></auteur>
 


 
Enfin, je pense...  
 

n°1761311
Lhalfelin
Posté le 18-07-2008 à 11:00:58  profilanswer
 

Waouw !!! :love:  
 

<xsl:for-each select="//entrydata[@name='auteur'][generate-id() = generate-id( key('nom-auteur', text)[1])]">

Je pense que j'aurais été incapable de faire ça moi-même à ce stade de connaissance du XSLT.  
 
J'essaye ça et j'update.

n°1761375
Lhalfelin
Posté le 18-07-2008 à 11:58:31  profilanswer
 

Juste pour dire que ça marche impeccablement bien, j'en reviens pas =D
 
Je m'attaque maintenant à la somme. Je suppose qu'il va me falloir une template par variable numérique de la viewentry ? Ah zut y'en a 12 !

n°1761389
avander
Posté le 18-07-2008 à 12:08:47  profilanswer
 

Si c'est possible je ferais deux stylesheets:  
- un qui modifie la structure pour le regroupement par auteur
- un autre qui s'occuppe de la présentation finale

n°1761395
avander
Posté le 18-07-2008 à 12:12:30  profilanswer
 

Lhalfelin a écrit :

Waouw !!! :love:  
 

<xsl:for-each select="//entrydata[@name='auteur'][generate-id() = generate-id( key('nom-auteur', text)[1])]">

Je pense que j'aurais été incapable de faire ça moi-même à ce stade de connaissance du XSLT.  
 
J'essaye ça et j'update.


 
C'est le muenchian grouping qui fonctionne comme ça, faut bien décomposer l'expression pour comprendre... revoir le fonctionnement de xsl:key ça aide aussi ( faut je m'y remets à chaque fois, je te rassure).  :whistle:  

n°1761445
Lhalfelin
Posté le 18-07-2008 à 13:13:07  profilanswer
 

J'ai gardé tout ensemble
 

<xsl:value-of select="sum(//viewentry[entrydata[@name='auteur' and text=$vAuteurId]]/entrydata[@columnnumber='2']/text)" />


 
Copié collé 12 fois, avec column number qui change
 
Merci un million de fois pour ton aide !  :jap:
 
 
/edit : si j'ai le temps je ferai une récursivité pour être plus propre et incrémenter le columnnumber dynamiquement.


Message édité par Lhalfelin le 18-07-2008 à 15:15:26

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  XML/XSL

  [Résolu] XSLT : grouper et sommer

 

Sujets relatifs
[Résolu][Batch] handle de la fenêtre active[résolu]Jointure externe et GROUP BY
compiler les exemples directX [résolu][resolu] Ajax et XML. Mon script ne fonctionne pas.
[Résolu] lightbox et Flash[Resolu] Recuperer l'index d'un noeud dans sont parent (DOM).
[AS3-résolu] Créer une classe[Résolu] SQL liste meilleur score pour 1 joueur
[Résolu] Comment "pré-stocker" des réponses à des boutons d'un .exe ?[Résolu] AppendChild qui insere mais pas de css sous IE
Plus de sujets relatifs à : [Résolu] XSLT : grouper et sommer


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR