2009-04-22 5 views
1

J'ai un fichier XML:Comment sélectionner les nœuds dynamiquement dans XSLT

<?xml version="1.0" standalone="yes"?> 
<Questionnaire> 
    <Temp_GridTypeTable_6> 
    <Column2>Select Yes/No</Column2> 
    </Temp_GridTypeTable_6> 
    <Temp_GridTypeTable_1> 
    <Column2>Rank 1,2,3</Column2> 
    </Temp_GridTypeTable_1> 
    <Temp_GridTypeTable_1> 
    <Column1>I needed the income</Column1> 
    <Column2>Why did you take a job on this project?</Column2> 
    </Temp_GridTypeTable_1> 
    <Temp_GridTypeTable_1> 
    <Column1>Other</Column1> 
    <Column2></Column2> 
    </Temp_GridTypeTable_1> 
    <Temp_GridTypeTable_2> 
    <Column2>Select "Yes/No"</Column2> 
    </Temp_GridTypeTable_2> 
    <Temp_GridTypeTable_2> 
    <Column1>No jobs</Column1> 
    <Column2>344</Column2> 
    </Temp_GridTypeTable_2> 
    <Temp_GridTypeTable_3> 
    <Column2>Input</Column2> 
    </Temp_GridTypeTable_3> 
    <Temp_GridTypeTable_3> 
    <Column1>Unit</Column1> 
    <Column2>123</Column2> 
    </Temp_GridTypeTable_3> 
</Questionnaire> 

Je veux accéder

<xsl:for-each select="Questionnaire/concat('Temp_GridTypeTablenode_',"1"))> 

mais cette déclaration ne fonctionne pas.

+0

Salut si votre collage XML assurez-vous d'envelopper comme un «échantillon de code» (le bouton avec 1s et 0s) – eddiegroves

Répondre

11

Ceci est tout à fait un exemple de comment ne pas utiliser XML. Les nombres "Temp_GridTypeTable" et "Column" sont des données, pas une structure, ils ne devraient pas être contenus dans les noms d'éléments. Alors pourquoi ne pas vous utilisez quelque chose de moins douloureux, disent:

<Questionnaire> 
    <Temp_GridTypeTable type="6"> 
    <Column num="2">Select Yes/No</Column> 
    </Temp_GridTypeTable> 
    <Temp_GridTypeTable type="1"> 
    <!-- ... --> 
    <Temp_GridTypeTable> 
    <!-- ... --> 
</Questionnaire> 

Cela dit, pour votre situation actuelle, cela est nécessaire:

<xsl:for-each select="Questionnaire/*[ 
    local-name() 
    = 
    concat('Temp_GridTypeTable_', '1') 
]"> 

Pour la version « moins douloureuse » de l'entrée , cela aurait été nécessaire:

<xsl:for-each select="Questionnaire/Temp_GridTypeTable[@type = 1]"> 

Malgré le fait que la deuxième expression est beaucoup plus simple et plus simple, il se produira également beaucoup mieux. Si vous pouvez l'aider, je recommande de changer le XML d'entrée.


EDIT: Suite à l'argument selon lequel se déroula dans les commentaires, je tente de souligner la différence entre les local-name() et name() fonctions XPath, et où la différence importe:

 
          | XML has namespaces | XML has no namespaces 
----------------------------+---------------------+----------------------- 
I care about namespaces  | use `name()`  | use either function 
          |      | 
don't care about namespaces | use `local-name()` | use either function 

En général: Si vous tombez dans le groupe "ne vous souciez pas des espaces de noms" (la plupart des novices XML ou des utilisateurs XML occasionnels), il est bon (parfois même bénéfique) de toujours utiliser local-name(). Cependant, préparez-vous à en apprendre davantage sur les espaces de noms XML lorsque les résultats obtenus et les résultats attendus commencent à diverger. À ce stade, vous n'appartenez plus au groupe dit.

Si vous appartenez au groupe "Je me préoccupe des espaces de noms", vous n'avez pas besoin de ce conseil de toute façon. ;-)

+0

Dans le passé, j'ai soulevé le problème que l'utilisation de nom local() n'est pas une bonne pratique et généralement produire des résultats indésirables et inattendus. L'utilisation de la fonction name() est presque toujours la meilleure réponse. –

+0

Et comme toujours je trouve cette vue centrée sur le domaine et en contradiction avec la réalité pratique. C'est comme choisir un côté fortement ou faiblement typé: les deux peuvent être corrects selon la tâche. Je ne suis pas d'accord plus sur l'état du XML. – annakata

+0

@both: D'un point de vue académique (ce qui est généralement le cas de Dimitre Novatchev), l'utilisation de local-name() donnera potentiellement des faux positifs et est donc incorrecte. D'un point de vue pratique (que je suis enclin à prendre en regardant le XML réel dans la question), je crois que local-name() est la meilleure alternative, puisque * si * les espaces de noms XML sont impliqués d'une façon ou d'une autre , c'est presque certainement par accident. – Tomalak

1

Vous ne pouvez pas évaluer les chaînes en tant qu'expressions XPath lors de l'exécution avec XSLT pur.

Vous avez besoin d'une fonction d'extension qui peut évaluer une expression xpath au moment de l'exécution. Voir par exemple le EXSLT project.

Sur mon système, en utilisant xsltproc, je peux accomplir ce que vous voulez avec:

<!-- load the saxon extensions --> 
<xsl:stylesheet version="1.0" xmlns:xx="http://icl.com/saxon" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
... 
... 
<xsl:for-each 
    select="xx:evaluate(concat('Questionnaire/Temp_GridTypeTable_', '1'))"> 

Ici, j'utilise l'évaluation de la fonction de la bibliothèque d'extension Saxonne. La fonction d'évaluation d'EXSLT devrait fonctionner de la même manière.

Les processeurs/bibliothèques XSLT doivent disposer d'une sorte de fonction evaluate intégrée. Consultez la documentation de votre bibliothèque.

+0

Cela peut être fait sans extensions (voir ma réponse). Ce n'est pas gentil, et ça fonctionne mal. – Tomalak

+0

Bien sûr, dire que "cela ne peut pas être fait en XSLT pur sans extensions" est définitivement faux! –

+0

Je vais downvoter cette réponse dès que j'ai plus de temps disponible. –

2

Utilisation:

                Questionnaire/*[name() = concat('', $vSuffix)]

où la $vSuffix variable contient la chaîne statiquement inconnue - dans ce cas '1'.

En utilisant local-name() comme dans la réponse de Tomalak est à la fois inutilement long et imprécis, comme dans le cas général permet des éléments avec une variété de noms (éventuellement indésirables et inattendus) à sélectionner, tels que:

  • OhMy:Temp_GridTypeTable_1
  • Different:Temp_GridTypeTable_1
  • UnWanted:Temp_GridTypeTable_1
+0

Je vois ce que vous voulez dire, mais avec le cas d'espèce, je pense qu'il est raisonnable de supposer qu'ils sont loin d'utiliser des espaces de noms XML. La question montre ce qui ressemble à un document XML complet sans aucun espace de noms. Même si * si * il y avait un espace de nom par défaut impliqué quelque part, je suis presque certain qu'ils veulent l'ignorer, étant donné leur manque actuel d'expertise XML. – Tomalak

+0

@Tomalak name() fonctionne parfaitement dans le cas d'un espace de noms par défaut - pas besoin de nom local(). –

+0

Oups, vous avez raison bien sûr. Ce que j'avais à l'esprit était "... s'il y avait un espace de noms impliqué quelque part ...". Comme je l'ai dit, je peux parfaitement voir votre point de vue, c'est l'expérience pratique qui m'a fait recommander local-name() sur name(). – Tomalak

Questions connexes