2009-07-24 15 views
0

Je rencontre un problème avec les variables XSL. Je sais qu'une fois déclarée, la valeur de la variable ne peut pas être changée.Modifier la valeur de la variable dans xsl

Mais je suis confronté à un problème plutôt étrange et je ne peux pas changer la sortie XML, à la place comprendre si c'est possible avec XSL lui-même. J'utilise xsl: for-each pour faire une boucle sur certaines données dans le fichier .xml.

Les données peuvent être bouclées de trois types, disent Type1, Type2 et Type3

S'il est Type1, j'appelle un modèle pour traiter ces données. À l'intérieur du modèle, j'affiche un en-tête. J'ai besoin d'imprimer cet en-tête pour la première fois que je rencontre ces données Type1 seulement. Après cela, je n'ai pas besoin de l'afficher.

J'aurais pu transmettre un paramètre avec le modèle d'appel et l'initialiser/annuler pour déterminer si j'avais besoin d'imprimer le texte de l'en-tête. Mais si je comprends bien, étant un langage de mise en forme, l'état de la variable n'est pas conservé.

Pouvez-vous s'il vous plaît fournir vos précieuses suggestions sur la façon de mettre en œuvre cela (éventuellement sans modifications xml)?

Edit:

Le test fonctionnera pour la sortie XML mentionné par Patrice. Mais mon XML est différent.

<doc> 
<item>foobar</item> 
<item>foo</item> 
<item>bar</item> 
<item>baz</item> 
<item>foo</item> 
<item>bar</item> 
</doc> 

De ce XML, j'ai besoin d'afficher un en-tête pour la toute première fois qu'il rencontre 'foo'. L'ordre des articles pourrait être n'importe quoi aussi. Je ne peux pas prédire exactement quand 'foo' apparaîtra dans le XML.

Pouvez-vous s'il vous plaît apporter des suggestions?

+0

S'il vous plaît poster quelques de votre code afin que nous puissions vous aider. –

Répondre

3

Vous pouvez utiliser un sélecteur approprié pour cela (ce serait plus facile avec un code réel de votre part).

Exemple avec cette entrée:

<doc> 
    <item>foo</item> 
    <item>bar</item> 
</doc> 

Vous pouvez utiliser ce XSLT:

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> 
<xsl:output method='html' version='1.0' encoding='utf-8' indent='yes'/> 

    <xsl:template match="/"> 
     <xsl:apply-templates select="/doc/item" /> 
    </xsl:template> 

    <xsl:template match="item"> 
     <xsl:if test="not(preceding-sibling::item)"> 
      <h1>First</h1> 
     </xsl:if> 
     <p><xsl:apply-templates /></p> 
    </xsl:template> 

</xsl:stylesheet> 

Et vous obtiendrez cette sortie:

<h1>First</h1> 
<p>foo</p> 
<p>bar</p> 

clé est le test

<xsl:if test="not(preceding-sibling::item)"> 

Vous pouvez également changer cela pour

<xsl:if test="not(preceding::item)"> 

en fonction de la structure de votre document. Pour plus de détails, voir XPath axes pour plus de détails.

+0

J'ai aussi utilisé not (position() = 1) avec un certain succès, mais j'aime mieux votre solution, car elle explique mieux le test. – Ishmael

+0

+1 si le frère précédent est ce que j'irais faire ici, d'une façon ou d'une autre – annakata

0

Vous avez probablement juste besoin d'ajouter un prédicat mais encore une fois, sans un exemple concret de votre entrée et peu de détails sur la sortie attendue, c'est difficile à dire.

Pour le premier élément dont le contenu est « foo », remplacer l'étiquette de Patrice avec

<xsl:if test=".='foo' and not(preceding-sibling::item[.='foo'])"> 
+0

Merci pour votre aide, Josh. Le résultat attendu serait

foobar

tête

foo

bar

baz

foo

bar

Seul le premier élément 'foo' nécessite un en-tête. – jobinbasani

Questions connexes