XSLT 1.0 - Grouper par liste de noeuds identiques - XML/XSL - Programmation
Marsh Posté le 30-05-2019 à 10:13:52
Si je pige bien, c'est la liste des hopper d'une sequence qui est ta clé.
Code :
|
Sur tes données, ça donne en sortie
Code :
|
J'ai mis version="3.0" mais ça marche aussi en xsl 2.0
J'ai regroupé les éléments sequence sur une clé composite obtenue en concaténant les contenus des hoppers et en séparant avec des - ce qui fait une bonne clé de tri des sequences :
string-join(tail(*)!string(), '-') ça construit la clé ainsi : tail(*) pour virer le premier fils de sequence, qui n'est pas un hopper, ça me fait la liste des hoppers, tail(*)!string() ça me fait la liste de leurs contenus, et le reste est explicite.
Et si tu veux trier en sortie les versions et/ou sequence_name, tu remplace le/les <xsl:for-each select="distinct-values(...)"> par <xsl:for-each select="sort(distinct-values(...))">
Bon, si on veut faire ça en xslt 1.0 c'est plus coton (programmer en xslt 1.0 de nos jours, c'est comme utiliser windows 95 comme OS, bref c'est obsolète et complètement dépassé). Tu as pas d'autre possibilité? parce que ça, avec la version Home Edition (gratuite) de Saxon, ça marche.
Sinon, il faudra que tu fasses du multi-passe avec des modes distincts, et transformation de ton arbre.
Bref, tu transformes tes données initiales avec la clé composite explicitement ajoutée à la main (technique à la Schwartzian transform du Perl)
Code :
|
et une seconde passe pour générer tes données regroupées par clé (mais ça va être encore du boulot pour ne pas avoir des entrées version ou sequence_name dupliquées, il faudra peut être trois passes. Bon, de toute façon, je touche plus au xslt 1.0, faut être maso pour en faire quand on voit tout ce qui a été apporté par les versions 2.0 et 3.0 et qu'il y a un outil gratuit qui le fait pour un usage perso).
A+,
Marsh Posté le 31-05-2019 à 10:35:30
Merci pour les exemples et explications.
C'est pour un usage pro avec un logiciel qui utilise PrintXML 8.1, donc je suis bloqué en version 1.0, et je ne peux par corriger le XML (même à la main, car c'est pour un usage régulier d'impression en PDF).
Quand tu parles de multi-passes, c'est possible avec un seul fichier XSL, ou il faut générer des fichiers XML intermédiaires ? (Dans ce cas, ça me paraît difficile avec PrintXML)
Marsh Posté le 01-06-2019 à 14:08:44
fred_53 a écrit : Merci pour les exemples et explications. |
Tu parles de PrinceXML je suppose. PrinceXML il imprime du XML, donc ce qui a généré le XML, il s'en fiche à priori.
Mais manifestement, tu as un outil obsolète en amont (surtout que PrinceXML, il est en 12.5 actuellement. Je ne sais pas quel est ton outil Pro, mais ça fait pas sérieux, ça).
Rien ne vaut un exemple pour expliciter la technique:
Code :
|
Le premier mode, toto, va rajouter TOTO- a tous les noms d'éléments.
Le second mode, titi, va rajouter -TITI à tous les noms d'attributs.
On applique le premier mode aux données initiales, et on stocke le résultat dans une variable, ici, pass1.
On applique le second mode au résultat de la transformation précédente, ie pass1.
Et au final on a le résultat des deux transformations successives.
Après, au prix d'un peu de mémoire et de temps d'exécution, on peut factoriser pour rendre le traitement des passes homogène :
Code :
|
A+,
Marsh Posté le 01-06-2019 à 17:09:56
Et au final tu obtiens un truc de ce genre:
Code :
|
qui fait le taff (testé en live sur tes données avec Oxygen).
L'étape 1 calcule la clé identifiant les suite de hopper identiques et l'ajoute comme élément sort-key à chaque séquence
L'étape 2 trie les sequences par sort-key
L'étape 3 traite les sequences de même sort-keys (donc successifs) en différenciant le traitement du premier de la suite de celui des suivants
L'étape 4 ordonne les version et sequence_name d'une même sequence pour pouvoir virer les doublons à l'étape 5.
Mais c'est bien lourd comparé à du xsl moderne qui fait ça en une seule template et le mode par défaut:
Code :
|
Note finale, si je choisis ~ comme séparateur des constituants des clés de tri, c'est parce que sa valeur ascii est inférieure à celle des chiffres et lettres, et que ça convient donc mieux pour ne pas perturber un tri lexicographique.
A+,
Marsh Posté le 04-06-2019 à 10:38:04
Oui il s'agit bien de PrinceXML.
J'ai testé ton code dans Oxygen XML Editor 10.3 et dans Notepad++ 7.6.3/XML Tools 2.4.11.0, et j'ai obtenu respectivement les erreurs suivantes :
E: [Saxon6.5.5] indent must be yes or no or an integer |
Unable to apply transformation on current source. Make sure that XSL is valid. |
Si je remplace true par yes dans <xsl:output indent="yes"/>, j'ai alors les erreurs suivantes :
E [Saxon6.5.5] Cannot process a result tree fragment as a node-set under XSLT 1.0 |
The transformation has generated empty document. |
Est-ce du à ma version d'Oxygen et de Notepad++ ?
Marsh Posté le 04-06-2019 à 15:02:40
La version de Saxon utilisée dans Oxygen (qui est en version 21 de nos jours, tandis que Saxon est en 9.9...).
Il faut transformer les paramètres passés a chaque passe (des arbres résultant de la transfo d'une passe) en node-set. En xsl 2.0 avec la notion de sequence, ce problème n'existe plus.
Avec ce code, ça marche (on peut encore poser saxon6.5.5 comme processeur xsl dans Oxygen 20):
Code :
|
A+,
Marsh Posté le 07-06-2019 à 17:27:20
Merci beaucoup, cela fonctionne dans Oxygen.
Il faut maintenant que je regarde comme j'intègre cela dans mon fichier XSL, car il doit se présenter sous la forme suivante :
Code :
|
Marsh Posté le 07-06-2019 à 18:06:25
Code :
|
Je suppose qu'il y a quelque chose qui fait le call <xsl:call-template name="myTemplate"/> ailleurs dans ton outil.
A+,
Marsh Posté le 10-06-2019 à 19:30:22
Une version équivalente mais qui évite d'avoir une passe 3 avec une sous passe et est un peu plus facile à suivre dans sa construction.
Code :
|
A+,
Marsh Posté le 13-06-2019 à 11:19:44
Oui, le template est appelé par un autre fichier XSL.
Encore merci pour le code, j'en ferai bon usage.
Marsh Posté le 29-05-2019 à 16:38:01
Bonjour,
J'ai un fichier XML ayant la structure suivante :
<order>
<version>
<version_name>ABO</version_name>
<sequence>
<sequence_name>ABOPAL</sequence_name>
<hopper number="0" id="11">CV</hopper>
<hopper number="1" id="12">INT</hopper>
<hopper number="2" id="13">ENC</hopper>
</sequence>
<sequence>
<sequence_name>ABOCAR</sequence_name>
<hopper number="0" id="11">CV</hopper>
<hopper number="1" id="12">INT</hopper>
<hopper number="2" id="13">ENC</hopper>
</sequence>
</version>
<version>
<version_name>GEN</version_name>
<sequence>
<sequence_name>GENPAL</sequence_name>
<hopper number="0" id="11">CV</hopper>
<hopper number="1" id="12">INT</hopper>
<hopper number="2" id="13">ENC</hopper>
</sequence>
<sequence>
<sequence_name>ABOCAR</sequence_name>
<hopper number="0" id="11">CV</hopper>
<hopper number="1" id="12">INT</hopper>
<hopper number="2" id=""></hopper>
</sequence>
</version>
</order>
Dans mon order, j'ai donc 2 versions, et dans chaque version, j'ai 2 séquences, contenant des hoppers numérotés associés ou non à des id.
Dans l'exemple ci-dessus, les 3 premières séquences sont identiques (mêmes id en face de chaque numéro de hopper).
Je souhaite grouper tout cela par séquence identique (même combinaison de hoppers), pour obtenir le résultat suivant :
<order>
<sequence>
<version>ABO</version>
<version>GEN</version>
<sequence_name>ABOPAL</sequence_name>
<sequence_name>ABOCAR</sequence_name>
<sequence_name>GENPAL</sequence_name>
<hopper number="0" id="11">CV</hopper>
<hopper number="1" id="12">INT</hopper>
<hopper number="2" id="13">ENC</hopper>
</sequence>
<sequence>
<version>GEN</version>
<sequence_name>GENCAR</sequence_name>
<hopper number="0" id="11">CV</hopper>
<hopper number="1" id="12">INT</hopper>
<hopper number="2" id=""></hopper>
</sequence>
</order>
J'ai trouvé des infos sur la page http://www.jenitennison.com/xslt/g [...] nchian.xml pour grouper à l'aide d'une clé correspondant à un champ du XML,
mais dans mon cas, la clé devrait être une liste de noeuds (les hoppers).
Quelqu'un a-t'il une idée sur la façon de procéder pour y arriver ?