Tout d’abord, je salue tous les développeurs de ce Forum, qui m’a beaucoup aidé au cours de mon développement.
Je suis un nouveau posteur, mais cela va faire un mois que je lis attentivement les threads de ce forum.
Présentation : Je suis actuellement stagiaire en informatique financière dans un groupe aéronautique et une partie de ma mission est d’extraire de façon automatique des données XML issues de Crystal Reports (Reporting financier), pour les transformer en HTML en utilisant XSLT.
Tout était au beau fixe jusqu'à ce que je tombe sur un os, trier des données de façon dynamique.
PS : J’ai simplifié et randomisé mon code par souci de clarté et de compréhension.
Je m’explique :
Mon XML se présente de la manière suivante :
Des éléments « <Container> » qui représentent chacun une Row de tableau.
Des sous éléments « <Object> » qui sont en fait les Cells du tableau.
Dans chaque élément « <Object> », il y a un child « Value » qui contient le texte des données.
Chaque élément <Object> contient des informations qui sont contextuelles et comptable,
Ainsi, le contexte est désigné par un attribut de la façon suivante :
obj1 => Nom de la filiale
obj2 => Nom du service
obj3 => Ecriture comptable
Voici le XML source :
Ce fichier XML, je le transforme en HTML par l’intermédiaire de la feuille XSL suivante :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 <?xml version="1.0" encoding="UTF-8" ?> <?xml-stylesheet type="text/xsl" href="test.xsl"?> <Test> <Container> <Object Name="obj1"> <Value>OEM</Value> </Object> <Object Name="obj2"> <Value>fin</Value> </Object> <Object Name="obj3"> <Value>-8985</Value> </Object> </Container> <Container> <Object Name="obj1"> <Value>OEM</Value> </Object> <Object Name="obj2"> <Value>sec</Value> </Object> <Object Name="obj3"> <Value>-23</Value> </Object> </Container> <Container> <Object Name="obj1"> <Value>ETD</Value> </Object> <Object Name="obj2"> <Value>fin</Value> </Object> <Object Name="obj3"> <Value>-1524</Value> </Object> </Container> <Container> <Object Name="obj1"> <Value>ETD</Value> </Object> <Object Name="obj2"> <Value>sec</Value> </Object> <Object Name="obj3"> <Value>-365</Value> </Object> </Container> </Test>
L’Output HTML est correct et me pond le tableau suivant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl = 'http://www.w3.org/1999/XSL/Transform' xmlns:html="http://www.w3.org/TR/REC-html40" version="1.0"> <xsl:output method="html"/> <xsl:template match="/"> <TABLE> <xsl:for-each select="//Container"> <tr> <xsl:for-each select="Object"> <td> <xsl:value-of select="Value"/> </td> </xsl:for-each> </tr> </xsl:for-each> </TABLE> </xsl:template> </xsl:stylesheet>
PROBLEME :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 OEM | fin | -8985 OEM | sec | -23 ETD | fin | -1524 ETD | sec | -365
Vous l’aurez remarqué, il y a des récurrences dans le tableau : OEM/fin OEM/sec ETD/fin ETD/sec.
Pour pouvoir calculer des sous totaux, j’ai donc besoin de trier ces éléments pour générer de façon automatique et dynamique différents tableaux pour chaque Filiale (ou obj1) et pour chaque Service (ou obj2).
Je voudrais arriver à générer un Output HTML qui ressemble à ça :
Bien entendu, j’y parviens de façon statique, en utilisant un truc du genre :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 Tableau 1 OEM / Fin OEM | fin | -8985 Tableau 2 OEM / Sec OEM | sec | -23 Tableau 3 ETD / fin ETD | fin | -1524 Tableau 4 ETD / sec ETD | sec | -365
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl = 'http://www.w3.org/1999/XSL/Transform' xmlns:html="http://www.w3.org/TR/REC-html40" version="1.0"> <xsl:output method="html"/> <xsl:template match="/"> <TABLE> <xsl:for-each select="//Container"> <tr> <xsl:choose> <xsl:when test='Object[@Name="obj1"]/Value = ("OEM")'> <xsl:for-each select="Object"> <td> <xsl:value-of select="Value"/> </td> </xsl:for-each> </xsl:when> <xsl:otherwise></xsl:otherwise> </xsl:choose> </tr> </xsl:for-each> </TABLE> </xsl:template> </xsl:stylesheet>
Le problème, c’est que les informations de contexte contenues dans l’input XML source peuvent varier extrêmement : Par exemple, si une nouvelle filiale est créée, un nouveau code filiale apparaîtra et sera tout bonnement ignoré par ma feuille XSL.
D’autre part, entrer des filtres statiques dans ma feuille XSL induit de dupliquer les blocs pour chaque tableaux de croisement Obj1/Obj2, ce qui risque d’alourdir mon code.
En fait, j’aimerais dire tout simplement à XSL une séquence du genre : « Pour chaque valeur texte d’un élément Obj1 rencontré, si identique au précédent continuer le Loop, sinon, construction d’un nouveau tableau avec Obj1 différent du précédent ». Et ainsi de suite, mais je n’arrive pas à le codé, n’étant par ailleurs pas très matheuxdans mon approche du codage.
J’aimerais donc savoir si quelqu’un ici peut me proposer une piste pour continuer, la je bloque, et j’ai pourtant essayé pleins de balises (sort, if, for-each …)
.
J’espère avoir été assez claire dans mon approche du problème pour que ce soit compréhensible, je remercie d’avance toute les bonnes âmes qui aurait le courage de lire ce thread et d’y répondre.
Edit :: Pour quelques petites précisions :
- En fait je l'ai pas dit mais je débute méchamment en XML / XSLT ( je pense que ça se voit)
- Je n'ai absolument pas le droit (ni la possibilité) de toucher au document XML source, le lien vers la feuille XSL n'est la que pour des tests. Dans les faits, les utilisateurs passerons par une "moulinette" codée en PhP.
- Voila c'est tout.
@++
Partager