[Débutant][XSLT] Passage structure plane à arborescente
Bonjour
je voudrais faire une transformation XSL vers html "à plat et alphabétiquement" côté client d'un fichier xml représentant un menu vertical hiérarchique (c-à-d avec dossier et sous-dossier dont le niveau d'imbrication peut être multiple et n'est pas connu à priori)
8O La difficulté pour moi est de tester l'imbrication des dossiers sachant que chaque élément du fichier xml, chaque item du menu, possède juste 4 informations: son nom, son type (menu, dossier ou contenu) l'identifiant unique de son dossier parent (1=master étant le premier niveau) et un identifiant unique donc.
ex xml:
Code:
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="menu.xsl" type="text/xsl"?>
<plist>
<item>
<nom>master</nom>
<type>menu</type>
<parent></parent>
<idunique>1</idunique>
</item>
<item>
<nom>Dossier2</nom>
<type>dossier</type>
<parent>1</parent>
<idunique>2</idunique>
</item>
<item>
<nom>Dossier1</nom>
<type>dossier</type>
<parent>1</parent>
<idunique>3</idunique>
</item>
<item>
<nom>DossierX</nom>
<type>dossier</type>
<parent>5</parent>
<idunique>4</idunique>
</item>
<item>
<nom>Dossier</nom>
<type>dossier</type>
<parent>2</parent>
<idunique>5</idunique>
</item>
<item>
<nom>DossierY</nom>
<type>dossier</type>
<parent>5</parent>
<idunique>6</idunique>
</item>
<item>
<nom>Element</nom>
<type>contenu</type>
<parent>3</parent>
<idunique>7</idunique>
</item>
<item>
<nom>ElementA</nom>
<type>contenu</type>
<parent>4</parent>
<idunique>8</idunique>
</item>
<item>
<nom>ElementB</nom>
<type>contenu</type>
<parent>4</parent>
<idunique>9</idunique>
</item>
<item>
<nom>Element1</nom>
<type>contenu</type>
<parent>6</parent>
<idunique>10</idunique>
</item>
<item>
<nom>Element1</nom>
<type>contenu</type>
<parent>1</parent>
<idunique>11</idunique>
</item>
<item>
<nom>Element3</nom>
<type>contenu</type>
<parent>1</parent>
<idunique>12</idunique>
</item>
<item>
<nom>Element2</nom>
<type>contenu</type>
<parent>1</parent>
<idunique>13</idunique>
</item>
<item>
<nom>Element2</nom>
<type>contenu</type>
<parent>6</parent>
<idunique>14</idunique>
</item>
<item>
<nom>Element</nom>
<type>contenu</type>
<parent>2</parent>
<idunique>15</idunique>
</item>
</plist> |
je voudrais obtenir (pour le moment) ce genre de résultat simple "à plat":
Master.
-Dossier1.
--Element.
-Dossier2.
--Dossier.
---DossierX.
----ElementA.
----ElementB.
---DossierY.
----Element1.
----Element2.
--Element.
-Element1.
-Element2.
-Element3.
J'aimerais que quelqu'un me mette sur la voie, m'indiquant un lien ou un nom de méthode.
Ce doit être un cas classique qui doit s'appliquer à des menus déroulants verticaux comme à des sommaires.
Note: j'ai crée un AppleScript qui génère ce type de fichier xml à partir du menu playlist d'iTunes pour ceux que ça intéresse et pour vous donner une idée de ce que j'essaie de reproduire.
J'espère que cela vous intéressera
Merci.
8-)
premier script (basique de débutant) en xsl
Première étape: afficher le contenu d'un dossier en fonction de la variable "currentFolder"
Code:
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
|
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<xsl:variable name="IDcurrentFolder">1</xsl:variable>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css" media="all">
li {
list-style:none
}
</style>
<title>Menu</title>
</head>
<body>
<xsl:call-template name="master" />
</body>
</html>
</xsl:template>
<xsl:template name="master">
<ul><xsl:call-template name="dossier" /></ul>
<ul><xsl:call-template name="contenu" /></ul>
</xsl:template>
<xsl:template name="dossier">
<xsl:for-each select="plist/item">
<xsl:sort select="." order="ascending" />
<xsl:if test="type = 'dossier' and parent = $IDcurrentFolder">
<xsl:element name="li">
<xsl:value-of select='nom' />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="contenu">
<xsl:for-each select="plist/item">
<xsl:sort select="." order="ascending" />
<xsl:if test="type = 'contenu' and parent = $IDcurrentFolder">
<xsl:element name="li">
<xsl:value-of select='nom' />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet> |
je vais continuer aujourd'hui et essayé de faire un "traitement récursif" dans un for each pour traiter les dossiers un par un.
Je vais essayer de placer dans le template "dossier" un re-appel du template "master" avec ré-assignation de la variable de test "currentFolder".
C'est mon idée pour l'instant...
traitement récursif des sous-dossiers
en essayant ça: (traitement récursif des sous-dossiers)
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
<xsl:template name="dossier">
<xsl:for-each select="plist/item">
<xsl:sort select="." order="ascending" />
<xsl:if test="type = 'dossier' and parent = $IDcurrentFolder">
<xsl:element name="li">
<xsl:value-of select='nom' />
</xsl:element>
<-- Traitement récursif des sous-dossiers -->
<xsl:variable name="IDcurrentFolder" select='idunique' />
<xsl:call-template name="master" />
</xsl:if>
</xsl:for-each>
</xsl:template> |
et bien... ça ne change rien :(
essai avec param plutôt que variable
Code:
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" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<xsl:param name="IDcurrentFolder" select="1" />
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style type="text/css" media="all">
li {
list-style:none
}
</style>
<title>Menu</title>
</head>
<body>
<xsl:call-template name="dossier" />
</body>
</html>
</xsl:template>
<xsl:template name="dossier">
<xsl:for-each select="plist/item">
<xsl:sort select="." order="ascending" />
<xsl:if test="type = 'dossier' and parent = $IDcurrentFolder">
<xsl:element name="li">
<xsl:value-of select='nom' />
</xsl:element>
<xsl:call-template name="dossier"><xsl:with-param name="IDcurrentFolder" select="idunique" /></xsl:call-template>
</xsl:if>
</xsl:for-each>
<xsl:call-template name="contenu"><xsl:with-param name="IDcurrentFolder" select="$IDcurrentFolder" /></xsl:call-template>
</xsl:template>
<xsl:template name="contenu">
<xsl:for-each select="plist/item">
<xsl:sort select="." order="ascending" />
<xsl:if test="type = 'contenu' and parent = $IDcurrentFolder">
<xsl:element name="li">
<xsl:value-of select='nom' />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet> |
Il n'y a plus de template master, juste dossier et contenu.
J'ai également changé le "Traitement récursif des sous-dossiers"
par un "call template with param" mais ...
ça ne marche toujours pas
pas de plantage, ça n'affiche que le premier niveau (item(s) avec id=1 pour parent):
Dossier1
Dossier2
Element1
Element2
Element3
décalage par rapport à la marge gauche
j'essaie ça:
Dans un premier temps, plutôt que d'avoir des tirets "-" je veux juste avoir un chiffre qui represente le nombre de décalages (ou tiret) à afficher, soit le nombre d'ancetres .
je cherche à obtenir ceci:
Master.
1Dossier1.
2Element.
1Dossier2.
2Dossier.
3DossierX.
4ElementA.
4ElementB.
3DossierY.
4Element1.
4Element2.
2Element.
1Element1.
1Element2.
1Element3.
Code:
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
|
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<xsl:key name="cle" match="item" use="parent"/>
<xsl:param name="father" select="1" />
<xsl:param name="grandfather" select="0" />
<xsl:param name="iteration" select="1" />
<xsl:template match="/">
<xsl:apply-templates select="plist/item[not(parent)]" />
</xsl:template>
<xsl:template match="item">
<xsl:choose>
<xsl:when test="parent=$father">
<!-- Meme niveau -->
<xsl:param name="father" select="$father" />
<xsl:param name="grandfather" select="$grandfather" />
<xsl:param name="iteration" select="$iteration" />
<xsl:value-of select="$iteration" />
</xsl:when>
<!-- On change de niveau -->
<xsl:when test="parent=$grandfather">
<!-- On est remonte (!probleme:de combien de niveau? ici 1 mais peut-etre plusieurs)-->
<xsl:param name="grandfather" select="$father" />
<xsl:param name="father" select="parent" />
<xsl:param name="iteration" select="$iteration-1" />
<xsl:value-of select="$iteration" />
</xsl:when>
<xsl:otherwise>
<!-- On est descendu -->
<xsl:param name="grandfather" select="$father" />
<xsl:param name="father" select="parent" />
<xsl:param name="iteration" select="$iteration+1" />
<xsl:value-of select="$iteration" />
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="nom"/><br />
<xsl:apply-templates select="key('cle',idunique)">
<xsl:sort select="nom" order="ascending" />
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet> |
ce qui me donne
2master
1Dossier1
2Element
1Dossier2
2Dossier
2DossierX
2ElementA
2ElementB
2DossierY
2Element1
2Element2
2Element
1Element1
1Element2
1Element3
:koi:
ça marche pô bien!