allez on n'a le droit au following-sibling ca fera plaisir au vieux![]()
allez on n'a le droit au following-sibling ca fera plaisir au vieux![]()
bon voici une solution qui a l'air de fonctionner :
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 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="racine"> <xsl:call-template name="sommeniveau"> <xsl:with-param name="resultat" select="0"/> <xsl:with-param name="noeud" select="n[position()=1]"/> </xsl:call-template> </xsl:template> <xsl:template name="sommeniveau"> <xsl:param name="resultat"/> <xsl:param name="noeud"/> <xsl:choose> <xsl:when test="$noeud"> <xsl:variable name="ssres"> <xsl:if test="$noeud/n"> <xsl:call-template name="sommeniveau"> <xsl:with-param name="resultat" select="0"/> <xsl:with-param name="noeud" select="$noeud/n[position()=1]"/> </xsl:call-template> </xsl:if> <xsl:if test="not($noeud/n)">0</xsl:if> </xsl:variable> <xsl:variable name="somme"> <xsl:choose> <xsl:when test="$noeud/@valeur > number($ssres)"> <xsl:value-of select="$resultat+number($ssres)+$noeud/@valeur"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$resultat+number($ssres)"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:call-template name="sommeniveau"> <xsl:with-param name="resultat" select="number($somme)"/> <xsl:with-param name="noeud" select="$noeud/following-sibling::*"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$resultat"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>![]()
Bravo grégory !![]()
Maintenant, à moi de poser un défi : transformer une structure linéaire en structure arborescente
Soit le document XML suivant :
A chaque section est attribué un niveau qui indique sa position dans le plan du document. Ainsi, les sections de niveau 1 sont les chapitres principaux du document, les sections de niveau 2 les sous-chapitres de ces chapitres, etc. (les connaisseurs auront reconnu une version (très) simplifiée des documents Writer de OpenOffice
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 <?xml version="1.0" encoding="ISO-8859-1"?> <document> <section niveau="1" titre="1"/> <texte>aaaa</texte> <section niveau="2" titre="1.1"/> <texte>bbbb</texte> <section niveau="3" titre="1.1.1"/> <texte>cccc</texte> <section niveau="3" titre="1.1.2"/> <texte>dddd</texte> <section niveau="2" titre="1.2"/> <texte>eeee</texte> <section niveau="3" titre="1.2.1"/> <texte>ffff</texte> <section niveau="2" titre="1.3"/> <texte>gggg</texte> <texte>hhhh</texte> <section niveau="3" titre="1.3.1"/> <section niveau="4" titre="1.3.1.1"/> <texte>iiii</texte> <section niveau="4" titre="1.3.1.2"/> <texte>jjjj</texte> <section niveau="1" titre="2"/> <texte>kkkk</texte> <section niveau="2" titre="2.1"/> <texte>llll</texte> <section niveau="2" titre="2.2"/> <texte>mmmm</texte> </document>)
Ecrire la feuille de style XSL qui transformera ce document en une arborescence :
Les règles de transformation sont les suivantes :
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 <?xml version="1.0" encoding="UTF-8"?> <document> <section titre="1"> <texte>aaaa</texte> <section titre="1.1"> <texte>bbbb</texte> <section titre="1.1.1"> <texte>cccc</texte> </section> <section titre="1.1.2"> <texte>dddd</texte> </section> </section> <section titre="1.2"> <texte>eeee</texte> <section titre="1.2.1"> <texte>ffff</texte> </section> </section> <section titre="1.3"> <texte>gggg</texte> <texte>hhhh</texte> <section titre="1.3.1"> <section titre="1.3.1.1"> <texte>iiii</texte> </section> <section titre="1.3.1.2"> <texte>jjjj</texte> </section> </section> </section> </section> <section titre="2"> <texte>kkkk</texte> <section titre="2.1"> <texte>llll</texte> </section> <section titre="2.2"> <texte>mmmm</texte> </section> </section> </document>
- Chaque section devient un enfant de la section de niveau inférieur qui la précède immédiatement
- Chaque noeud texte devient enfant de la section qui le précède immédiatement
- Les attributs titre sont recopiés tels quels (ils ne sont là que pour faciliter la compréhension ; leur contenu étant arbitraire, il est interdit de se baser dessus pour résoudre le problème !)
Ben il est ou le defi:
Bon allez j'exagere, ca m'a quand meme prix 45mn pour le trouver et 10 pour l'optimiser.Sympa,un peu facile mais sympa 8)
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 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:template match="/"> <xsl:element name="document"> <xsl:apply-templates select="document/section[1]"/> </xsl:element> </xsl:template> <xsl:template match="section"> <xsl:variable name="pos" select="@niveau"/> <xsl:copy> <xsl:attribute name="titre"><xsl:value-of select="@titre"/></xsl:attribute> <xsl:apply-templates select="following-sibling::*[1][name()='texte']"/> <xsl:apply-templates select="following-sibling::section[1][@niveau > $pos]"/> </xsl:copy> <xsl:apply-templates select="following-sibling::section[@niveau <= $pos][1][@niveau=$pos]"/> </xsl:template> <xsl:template match="texte"> <xsl:copy-of select="."/> <xsl:apply-templates select="following-sibling::*[1][name()='texte']"/> </xsl:template> </xsl:stylesheet>
Pas mal, y'a de l'idée. Mais il y aussi beaucoup plus simple. Tu peux notamment faire l'économie de ta variable $pos et de deux apply-templates.
Trop de récursivité, mon petit, trop de récursivité...![]()
Ok colonel, vous n'êtes pas enccore si rouillé que çaEnvoyé par GrandFather
![]()
Cela vous siet-il plus?
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 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:template match="/"> <xsl:element name="document"> <xsl:apply-templates select="document/section[@niveau=1]"/> </xsl:element> </xsl:template> <xsl:template match="section"> <xsl:copy> <xsl:attribute name="titre"> <xsl:value-of select="@titre"/> </xsl:attribute> <xsl:apply-templates select="following-sibling::texte[(generate-id(./following-sibling::section[1])=generate-id(current()/following-sibling::section[1]))]"/> <xsl:apply-templates select="following-sibling::section[@niveau =current()/@niveau+1 and (generate-id(./preceding-sibling::section[@niveau=current()/@niveau][1])=generate-id(current()))]"/> </xsl:copy> </xsl:template> <xsl:template match="texte"> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet>
Bravo erwy ! Chapeau !![]()
Je me permets de poster mon corrigé uniquement parce que tu t'es un peu compliqué la vie pour les noeuds texte et qu'il est un peu plus optimisé (l'id du noeud courant n'est calculé qu'une seule fois, plutôt qu'à chaque évaluation de prédicat)
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" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/document"> <xsl:copy> <xsl:apply-templates select="section[@niveau = 1]"/> </xsl:copy> </xsl:template> <xsl:template match="section"> <xsl:variable name="id_noeud" select="generate-id(.)"/> <xsl:copy> <xsl:copy-of select="@titre"/> <xsl:apply-templates select="following-sibling::texte[generate-id(preceding-sibling::section[1]) = $id_noeud]"/> <xsl:apply-templates select="following-sibling::section[(@niveau = current()/@niveau + 1) and (generate-id(preceding-sibling::section[@niveau = current()/@niveau][1]) = $id_noeud)]"/> </xsl:copy> </xsl:template> <xsl:template match="texte"> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet>
En effet, mais c'est tjrs le pb quand tu viens de taper un xpath de trois lignesEnvoyé par GrandFather
quand tu en ecris un 1,5 ligne derriere tu as l'impression de l'avoir optimise
![]()
Par contre pour la variable je suis vexéta precedente reflexion m'avait fait penser que tu n'en utilisais pas
![]()
![]()
j'ai l'impression que les défis ne résistent pas bien longtemps ici
par contre erwy et grandfather, pourriez vous expliquer un peu les points qui peuvent paraitre difficiles dans vos solutions?
Je vais surtout detaille les <section> ,le traitement des <texte> en decoule en plus simple.
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" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/document"> <xsl:copy> <xsl:apply-templates select="section[@niveau = 1]"/> </xsl:copy> </xsl:template> <xsl:template match="section"> <xsl:variable name="id_noeud" select="generate-id(.)"/> <xsl:copy> <xsl:copy-of select="@titre"/> <xsl:apply-templates select="following-sibling::texte[generate-id(preceding-sibling::section[1]) = $id_noeud]"/> <xsl:apply-templates select="following-sibling::section[(@niveau = current()/@niveau + 1) and (generate-id(preceding-sibling::section[@niveau = current()/@niveau][1]) = $id_noeud)]"/> </xsl:copy> </xsl:template> <xsl:template match="texte"> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet>
L'algo en lui meme est asez simple,le point complique est le xpath utilise pour selectionner tous les "enfants" du noeud que l'on est en train de recopier.
Un premier point le generate-id(nodeset),attribut un identifiant unique a chaque noeud de l'arbre, pour verifier que deux xpath pointe sur le meme noeud il suffit donc de comparer generate-id(xpath1)=generate-id(xpath2)
quels sont les propriétes d'un "enfant"
-Il suit le noeud pere et est une section >>following-sibling::section
-son niveau est incrementé de 1 par rapport au pere>> niveau = current()/@niveau + 1
-Son pere est le premier element de niveau inferieur(c'est l'element courant) qui est au dessus de lui
pere=current()
premier element...= preceding-sibling::section[@niveau = current()/@niveau][1]
il ne reste plus qu' a comparer leur id
(generate-id(preceding-sibling::section[@niveau = current()/@niveau][1]) = $id_noeud)
et a additioner tous ces element avec un et pour produire le bon xpath![]()
following-sibling::section[(@niveau = current()/@niveau + 1) and (generate-id(preceding-sibling::section[@niveau = current()/@niveau][1]) = $id_noeud)]
Vous en avez pas d'autre, car j'adore cette idée de défie, je suis débutant dans le xsl mais je vais essayer de faire les premiers qui ont été posté.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager