2010-03-15 5 views
3

J'essaie de parcourir un document XML en utilisant xsl: foreach mais j'ai besoin que select = "" soit dynamique, donc j'utilise une variable comme source. Voici ce que j'ai essayé:Utilisation de xsl: variable dans une instruction select xsl: foreach

...

<xsl:template name="SetDataPath"> 
    <xsl:param name="Type" /> 

    <xsl:variable name="Path_1">/Rating/Path1/*</xsl:variable> 
    <xsl:variable name="Path_2">/Rating/Path2/*</xsl:variable> 

    <xsl:if test="$Type='1'"> 
    <xsl:value-of select="$Path_1"/> 
    </xsl:if> 

    <xsl:if test="$Type='2'"> 
    <xsl:value-of select="$Path_2"/> 
    </xsl:if> 
<xsl:template> 

...

<!-- Set Data Path according to Type --> 
    <xsl:variable name="DataPath"> 
    <xsl:call-template name="SetDataPath"> 
     <xsl:with-param name="Type" select="/Rating/Type" /> 
    </xsl:call-template> 
    </xsl:variable> 

...

<xsl:for-each select="$DataPath"> 

...

Le foreach a lancé une erreur indiquant: "XslTransformException - Utiliser un fragment d'arbre de résultat dans une expression de chemin, convertissez-le d'abord en un ensemble de nœuds en utilisant la fonction msxsl: node-set(). "

Lorsque j'utilise la fonction msxsl: node-set(), mes résultats sont vides.

Je suis conscient que je mets $ DataPath à une chaîne, mais la fonction node-set() ne devrait-elle pas en créer un ensemble de nœuds? Est-ce que je manque quelque chose? Lorsque je n'utilise pas de variable:

<xsl:for-each select="/Rating/Path1/*"> 

Je reçois les résultats appropriés.

Voici le fichier de données XML J'utilise:

<Rating> 
    <Type>1</Type> 
    <Path1> 
     <sarah> 
      <dob>1-3-86</dob> 
      <user>Sarah</user> 
     </sarah> 
     <joe> 
      <dob>11-12-85</dob> 
      <user>Joe</user> 
     </joe> 
    </Path1> 
    <Path2> 
     <jeff> 
      <dob>11-3-84</dob> 
      <user>Jeff</user> 
     </jeff> 
     <shawn> 
      <dob>3-5-81</dob> 
      <user>Shawn</user> 
     </shawn> 
    </Path2> 
</Rating> 

Ma question est simple, comment vous exécutez un foreach sur 2 chemins différents?

+0

Difficile à dire sans voir au moins un fragment XML. – Oded

Répondre

3

Essayez ceci:

<xsl:for-each select="/Rating[Type='1']/Path1/* 
         | 
          /Rating[Type='2']/Path2/*"> 
+0

C'est la solution EXACT que je cherchais, merci beaucoup! Élégant et efficace = D – Nefariousity

0

La fonction node-set() que vous mentionnez peut convertir des fragments d'arborescence de résultats en ensembles de nœuds, c'est correct. Mais: Votre XSLT ne produit pas de fragment d'arbre de résultat.

Votre modèle SetDataPath génère une chaîne, qui est ensuite stockée dans votre variable $DataPath. Lorsque vous faites <xsl:for-each select="$DataPath">, le processeur XSLT s'étouffe sur le fait que DataPath ne contient pas un ensemble de nœuds, mais une chaîne.

Votre feuille de style entière semble tourner autour de l'idée de sélectionner/évaluer dynamiquement des expressions XPath. Laisse tomber cette pensée, ce n'est ni possible ni nécessaire.

Montrez votre entrée XML et spécifiez la transformation que vous voulez faire et je peux essayer de vous montrer un moyen de le faire.

+0

Merci pour votre aide. J'ai ajouté les données XML que j'utilise. Alors, comment utiliseriez-vous 2 chemins différents dans la même déclaration foreach? – Nefariousity

+0

@Nefariousity: Non, votre question n'est pas "Comment lancez-vous un foreach sur 2 chemins différents?", Car c'est la solution que vous essayez de mettre en œuvre. Indiquez votre * problème *, pas la solution que vous pensez pour le résoudre. – Tomalak

+0

Comme indiqué dans mon fichier XML, j'ai les mêmes attributs dans 2 chemins différents. Comment puis-je accéder à ces attributs dans une boucle foreach sans devoir copier deux fois la boucle, dans 2 instructions if différentes? – Nefariousity

3

standard XSLT 1.0 ne prend pas en charge l'évaluation dynamique de XPath. Cependant, vous pouvez obtenir le résultat souhaité par la restructuration de votre solution pour appeler un modèle nommé, en passant le jeu de nœud que vous voulez traiter comme paramètre:

<xsl:variable name="Type" select="/Rating/Type"/> 
<xsl:choose> 
    <xsl:when test="$Type='1'"> 
     <xsl:call-template name="DoStuff"> 
      <xsl:with-param name="Input" select="/Rating/Path1/*"/> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:when test="$Type='2'"> 
     <xsl:call-template name="DoStuff"> 
      <xsl:with-param name="Input" select="/Rating/Path2/*"/> 
     </xsl:call-template> 
    </xsl:when> 
</xsl:choose> 

...

<xsl:template name="DoStuff"> 
    <xsl:param name="Input"/> 
    <xsl:for-each select="$Input"> 
     <!-- Do stuff with input --> 
    </xsl:for-each> 
</xsl:template> 
+0

Cela fonctionne très bien, merci beaucoup pour aider = D – Nefariousity