2010-01-12 5 views
1

Je suppose que mon problème est assez courant, donc il doit y avoir une solution facile. Considérons l'extrait de code XML suivant:XSLT: Correspondance des attributs Xpath aux attributs de chaque portée

<categories> 
    <category name="cat1" /> 
    <category name="cat2" /> 
    <category name="cat3" /> 
    <category name="cat4" /> 
    </categories> 
    <data> 
    <catval name="cat2">foo</catval> 
    <catval name="cat4">bar</catval> 
    <catval name="cat3">boo</catval> 
    </data> 

J'ai besoin de sortir les valeurs catval dans l'ordre défini dans l'élément de catégories (y compris les catégories qui ont pas de données). S'il vous plaît noter que dans l'entrée réelle xml, il ya plusieurs données éléments partout et la sortie est beaucoup plus complexe, donc la création d'un modèle pour catégories n'est pas possible. J'utilise une construction comme ce qui suit:

<xsl:template match="data"> 
    <xsl:variable name="currentdata" select="." /> 
    <xsl:for-each select="../categories/category"> 
     <xsl:value-of select="@name" />: 
     <xsl:value-of 
     select="$currentdata/catval[@[email protected]]" /> <!-- ??? --> 
    </xsl:for-each> 
</xsl:template> 

Je ne sais pas si cela est la meilleure approche pour résoudre mon problème, mais même si ce n'est pas: Comment puis-je correspondre au nom attribut $ currentdata/catval à l'attribut nom de l'élément catégorie dans le contexte de la boucle for-each?

+0

Edit: Je ne l'ai pas mentionné avant que il peut y avoir plusieurs éléments de données dans le document. – FRotthowe

Répondre

1

Utilisez une variable pour enregistrer la valeur d'attribut de la <xsl:for-each> portée:

<xsl:template match="data"> 
    <xsl:variable name="currentdata" select="." /> 
    <xsl:for-each select="../categories/category"> 
    <xsl:variable name="name" select="@name"/> 
    <xsl:value-of select="$name" />: 
    <xsl:value-of 
     select="$currentdata/catval[@name=$name]" /> <!-- ??? --> 
    </xsl:for-each> 
</xsl:template> 
+0

N'a pas pensé à ça, merci. Mais est-ce vraiment le seul moyen de le faire? Pour moi, il semble assez étrange que j'ai besoin d'une variable pour faire référence à la portée en dehors de la boucle for-each ... – FRotthowe

+0

Je crois que vous pouvez utiliser la fonction 'current()' pour cela, de sorte que vous pouvez écrire: ' ' J'avoue que l'on me confond toujours, parce que la plupart du temps' current() 'est la même chose que '.' sauf quand ce n'est pas :) Donc je m'en tiens à stocker la valeur dans un var. –

+0

Une chose que je voudrais souligner: il n'y a pas de vérification pour voir tous les éléments de catval sont effectivement visités, même si l'ordre n'est pas défini. J'espère que ça va ... –

0

Je voudrais aller dans l'autre sens:

<xsl:template match="categories"> 
    <xsl:for-each select="category"> 
    <xsl:variable name="name" select="@name"/> 
    <xsl:apply-template select="/data/catval[@name=$name]/> 
    </xsl:for-each> 
</xsl:template> 

<xsl:template match="catval"> 
    <!-- Your output logic here --> 
</xsl:template> 

Ainsi, une fois que vous êtes dans le modèle "de catval" , vous êtes sûr que la commande est déjà faite et que vous devez juste vous concentrer sur le formatage de la sortie.

+0

ouais c'est plus agréable. J'aurais dû lire plus attentivement. Il y a une chose cependant, à laquelle je n'ai pas pensé non plus ... il n'y a pas de vérification pour voir tous les objets de catval qui sont effectivement visités, même si l'ordre n'est pas défini. –

+0

Je le ferais, mais dans le vrai xml il y a plusieurs * data * éléments partout mais juste une définition des catégories en haut. – FRotthowe

+0

Ok, dans ce cas, vous pouvez également envisager d'utiliser l'élément , pour récupérer tout l'élément dans le document. – gizmo

3

Simple, élégant et efficace: sortie

<xsl:key name="catvalByName" match="catval" use="@name" /> 

<xsl:template match="category"> 
    <xsl:value-of select="@name" /> 
    <xsl:text>: </xsl:text> 
    <xsl:value-of select="key('catvalByName', @name)" /> 
    <xsl:text>&#10;</xsl:text> 
</xsl:template> 

Would:

 
cat1: 
cat2: foo 
cat3: boo 
cat4: bar 

lorsqu'il est appelé comme celui-ci, par exemple:

<xsl:template match="categories"> 
    <xsl:apply-templates select="category" /> 
</xsl:template>