(Re)Bonjour à tous,

J'ai un petit problème avec des noeuds XPath. Voici le problème: j'ai besoin de créer un petit menu, tout simple avec des ul et des li.

Sur mon site, il y a un XML qui contient la structure de mes pages et qui s'appelle topmenu.xml.

Le code de ce xml ressemble à ceci:

<?xml version="1.0" encoding="UTF-8"?>
<topmenu>
	<cat name="Home" href="#"/>
	
	<cat name="Download" folder="download">
		<link name="Menu 1" href="#"/>
		<link name="Menu 2" href="#"/>
		<link name="Menu 3" href="#"/>
		<link name="Menu 4" href="#"/>
	</cat>
	
	<cat name="Test" folder="testfolder">
		<link name="Link 1" href="link1.html">
			<sublink name="sublink1" href="#"/>
			<sublink name="sublink2" href="http://www.google.fr"/>
			<sublink name="sublink3" href="#"/>
		</link>
		<link name="Link 2" href="link2.html"/>
	
	<link name="Link 3"  href="link3.html">
		<sublink name="sublink1" href="#"/>
		<sublink name="sublink2" href="http://www.google.fr"/>
		<sublink name="sublink3" href="#"/>
	</link>
	</cat>
</topmenu>


Bien sur ce fichier est un fichier EXTERNE, il n'est pas utilisé en tant que tel, mais uniquement au travers de la fonction document().

Maintenant, dans les fichiers XML que j'utilise (qui sont liés à une feuille XSL), y a une petite balise <menudisplay folder="testfolder"/> (testfolder, ou download, etc.. mais pour l'exemple ce sera testfolder), le chemin complet étant root/paragraphs/menudisplay.

Ce que je voudrais c'est afficher un bete menu qui prend tous les link du noeud topmenu/cat[@folder="??"], avec un <xsl:for-each> (dans une feuille xsl donc).

Plus "simplement" Smiley lol un truc du genre:

<ul>In the same category:
<xsl:for-each select="document('topmenu.xml')/topmenu/cat[@folder="<xsl:value-of select='root/paragraphs/menudisplay'/>"]/link">
<li>
<a href="#"><xsl:value-of select="document('topmenu.xml')/topmenu/cat/@name"/></a>
</li>
</xsl:for-each>
</ul>


Bien évidemment ca marche pas. Je précise également que:

<ul>In the same category:
<xsl:for-each>
<xsl:attribute name="select">
document('topmenu.xml')/topmenu/cat[@folder="
<xsl:value-of select='root/paragraphs/menudisplay'/>
"]/link">
<xsl:attribute/>

<li>
<a href="#"><xsl:value-of select="document('topmenu.xml')/topmenu/cat/@name"/></a>
</li>
</xsl:for-each>
</ul>

ne marche pas non plus, l'attribut select étant obligatoire après for-each (pas détecté en xsl-attribute par le parseur) Smiley bawling

J'ai essayé de changer les guillemets, les variables, etc etc... Rien à faire...

Quelqu'un peut m'aider? D'avance merci...

B.O.R.E.T.'
_________________________________________________________

EDIT:


P.S.: voici le code XSL, en l'état actuel et qui ne fonctionne bien évidemment pas, mais c'est peut etre plus clair pour que vous puissiez voir ce que je veux faire:



<xsl:template match="root/paragraphs/menudisplay">
<div id="display">

<xsl:choose>
 <xsl:when test="./@level='0'">
 <!-- Display same level -->
<ul>In the same category:
   <xsl:for-each select="document('topmenu.xml')/topmenu/cat[@folder="
   <xsl:value-of select='root/paragraphs/menudisplay/@folder'/>"]/link">

      <li>
         <a><xsl:attribute name="href">
         <xsl:value-of select="document('topmenu.xml')/topmenu/cat[@folder="
         <xsl:value-of select="root/paragraphs/menudisplay/@folder/>/link/@href"/>
         <xsl:attribute/>
         <xsl:value-of select="document('topmenu.xml')/topmenu/cat[@folder="
         <xsl:value-of select="root/paragraphs/menudisplay/@folder/>/link/@name"/>
         </a>
      </li>
   </xsl:for-each>

</ul>

</xsl:when>

<xsl:when>
...
</xsl:when>

<xsl:otherwise>
...
</xsl:otherwise>

</xsl:choose>
</div>
</xsl:template>

Modifié par B.O.R.E.T. (13 Jul 2007 - 13:09)
Hum... il me semble que ce que tu recherches est à trouver dans les fonctions EXSLT, plus particulièrement dyn:evaluate. Si j'ai bien compris, dans ton cas il faudrait quelque chose comme

<xsl:value-of select="document('topmenu.xml')/topmenu/cat[@folder=dyn:evaluate('root/paragraphs/menudisplay')]" />


Je l'ai un jour testée, mais sans toutefois l'utiliser en combinaison avec document().
Merci pour ta réponse, le problème étant que je ne connais pas EXSLT... Et ca marche en dehors de Xalan? Parce que j'utilise xsltproc (libxslt package) de Cygwin...

En fait ce que je veux par exemple, quand j'écris ce code:


      <li>
         <a><xsl:attribute name="href">
         <xsl:value-of select="document('topmenu.xml')/topmenu/cat[@folder="
         <xsl:value-of select="root/paragraphs/menudisplay/@folder/>/link/@href"/>
         <xsl:attribute/>

         <xsl:value-of select="document('topmenu.xml')/topmenu/cat[@folder="
         <xsl:value-of select="root/paragraphs/menudisplay/@folder/>/link/@name"/>
         </a>
      </li>


... ce que je veux, c'est créer un anchor dont l'attribut href est défini les lignes d'après de la manière suivante:
1. Lors de la création du XML initial (celui utilisé avec le XSLT), on crée un tag, avec un attribut folder qui sert à définir son appartenance à tel ou tel dossier. La valeur de folder, imaginons qu'elle soit appelée XXX
Voici le début du code d'un XML type qui est couplé à la XSLT.


<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://boret/xml/isolde2.xsl"?>
<root>
	<title><![CDATA[This is the title of theZ page]]></title>
	<subtitle><![CDATA[You can also add a subtitle]]></subtitle>
	<paragraphs>
		<menudisplay level="0" folder="testfolder"/>


Le fameux tag est menudisplay, où on y voit l'attribut folder...

2. on parse le document externe, pour trouver un noeud avec un attribut "folder", cet attribut étant égal à XXX

3.Puis ensuite on descend "d'un noeud" dans le document externe, pour y trouver l'attribut "link" et le copier dans l'attribut Href.

Même chose pour le nom du lien, sauf qu'on y copie la valeur de l'attribut "name".

pour donner un code du type:
<ul>
<li href="...">Nom du lien 1</li>
<li href="...">Nom du lien 2</li>
<li href="...">Nom du lien 3</li>
etc...
</ul>

C'est un grand bazar finalement pour pas grand-chose... Smiley cligne (bon sinon ce serait pas vraiment de l'informatique...).

Maintenant que (je crois?) c'est un peu plus clair, Gilles, tu penses que c'est possible avec EXSLT?
Je crois que cela devrait aller avec EXSLT.

Car, et je crois que ce sera une bonne nouvelle dyn:evaluate peut être inclus dans xsltproc. Et le lien que je viens de te donner devrait t'expliquer comment le faire. Elle est pas belle la vie Smiley hippy Smiley lol :
a écrit :

1. declare the EXSLT::Dynamic namespace and bind it to a prefix (say "dyn")
2. call dyn:evaluate in your XPath expressions

Modifié par Gilles (13 Jul 2007 - 17:23)
Merci bien Gilles, mais en fait la bonne réponse était:

<xsl:variable name="folder" select="root/paragraphs/menudisplay/@folder"/>
<ul><a>In the same category:</a>
<xsl:for-each select="document('topmenu.xml')/topmenu/cat[@folder=$folder]/link">
<li><a>
<xsl:attribute name="href">
<xsl:value-of select="./@href"/>
</xsl:attribute>
<xsl:value-of select="./@name"/>
</a></li>
</xsl:for-each>
</ul>


Suffisait tout bêtement d'introduire une variable... Smiley lol
B.O.R.E.T. a écrit :
Merci bien Gilles, mais en fait la bonne réponse était:
(...)
Suffisait tout bêtement d'introduire une variable... Smiley lol


La bonne réponse est rarement unique -sauf dans les QCM que je donne à mes étudiants Smiley deal -et encore Smiley lol !

En fait, "la" bonne réponse dépend souvent du contexte. Je préfère éviter les variables -question de goût Smiley cligne
Modifié par Gilles (15 Jul 2007 - 20:00)
Gilles a écrit :
En fait, "la" bonne réponse dépend souvent du contexte
C'est vrai indubitablement.
Gilles a écrit :
Je préfère éviter les variables -question de goût
La préférence exprimée étant explicitement subjective, il n'y a aucune raison d'aller à son encontre.

En revanche sur un plan beaucoup plus terre à terre, je pense qu'il est possible de classer les 2 réponses en terme d'efficacité et même de pureté. Sur ces critères je juge celle de B.O.R.E.T. supérieure puisque son code se cantonne à un ensemble plus restreint d'outils et en particulier au strict XSL 1.0, ce qui lui donne une portabilité nettement supérieure.
Personnellement je préconiserais donc l'emploi de la variables. Mais c'est vrai que personnellement j'adore les paramètres Smiley cligne
bonjour à tous ,

je suis toujours avec interêt les dicussions sur l'utilisation du Xslt ( que j'apprends petit à petit) ,et je me demandais si la syntaxe :


<xsl:for-each select="document('topmenu.xml')/topmenu/cat[@folder=$folder]/link">

n'impliquait pas trop d'"aller retour" document() et d'exécution de l'instruction Xpath suivant cette fonction ...!? Smiley murf

Question d'étudiant !! Smiley hein
En fait, ici, tu n'as pas le choix: il faut utiliser la fonction document() puisque ces informations ne figurent pas dans l'arbre transformé.

Maintenant, le plus rapide (car n'obligeant pas à charger le document à chaque itération) serait effectivement probablement de charger l'arborescence dans une variable et de travailler sur cette dernière.

@Xavier: j'ai pour ma part tendance à essayer de simplifier les instructions XPath. Créer une variable alors qu'une fonction existe et permet de faire le même boulot me semble inutile: si une fonction existe et est supportée par le parseur que j'utilise, alors je fonce. Ici, evaluate marchait puisqu'elle est supportée par xsltproc... C'est aussi pour cela que je parlais de contexte Smiley cligne . Je l'ai proposée dès le début car elle est quand même largement répandue, et qu'elle cadrait parfaitement avec ce que demandait BORET. Il va de soi que si la solution devait être portable sur des environnements a priori inconnus, je ne l'aurais pas proposée Smiley smile
a écrit :
En fait, ici, tu n'as pas le choix: il faut utiliser la fonction document() puisque ces informations ne figurent pas dans l'arbre transformé.

Maintenant, le plus rapide (car n'obligeant pas à charger le document à chaque itération) serait effectivement probablement de charger l'arborescence dans une variable et de travailler sur cette dernière.
Je pense que les processeurs doivent faire cela d'eux mêmes (lorsque qu'il y a de la mémoire disponible). La situation d'un select exécuté en boucle est bien trop courante, du fait notamment de l'emploi généralisé de la récursivité, pour que le processeur plombe les performances à ce point lors de l'emploi de document() en effectuant un nouveau parsing du même doc à chaque fois.

a écrit :
j'ai pour ma part tendance à essayer de simplifier les instructions XPath. Créer une variable alors qu'une fonction existe et permet de faire le même boulot me semble inutile: si une fonction existe et est supportée par le parseur que j'utilise, alors je fonce. Ici, evaluate marchait puisqu'elle est supportée par xsltproc... C'est aussi pour cela que je parlais de contexte. Je l'ai proposée dès le début car elle est quand même largement répandue, et qu'elle cadrait parfaitement avec ce que demandait BORET. Il va de soi que si la solution devait être portable sur des environnements a priori inconnus, je ne l'aurais pas proposée
Je n'avais pas pensé à introduire le processeur dans le contexte, mais vu sous cet angle tu as 100% raison.
Je dois être un peu obnubilé par la portabilité, et une arrière pensée qui m'habite poussant à toujours axer un développement vers le plus générique et le plus réutilisable...