2010-02-23 9 views
1

J'ai un nœud récursif que j'essaye de configurer pour jquery-checktree. Les nœuds ressemblentListe récursive des listes dans XSL

foo/bar/ID 
     /NAME 
     /CHECKED 
     bar/ID 
      /NAME 
      /CHECKED 
    /bar/ID 
     /NAME 
    /bar/ID 
     /NAME 
     /bar/ID 
      /NAME 
      /CHECKED 
      /bar/ID 
       /NAME 
       /CHECKED 

Lorsqu'une barre peut ou ne peut pas avoir un ou plusieurs noeuds de barre ci-dessous, mais une barre aura ID et le nom et pourraient avoir un BAGAGES.

et je veux le transformer en

<ul> 
    <li><input type="checkbox" name="..." value="..." checked="checked"></input> 
     <label for="...">...</label> 
     <ul> 
     <li><input type="checkbox" name="..." value="..." checked="checked"></input> 
      <label for="...">...</label> 
     </li> 
     </ul> 
    <li>....</li> 
</ul> 

je peux obtenir le premier niveau en faisant:

<ul class="tree"> 
    <xsl:for-each select="/foo/bar/"> 
     <li><input type="checkbox" name="{ID}" value="{ID}"> 
      <xsl:if test="CHECKED = 'Y'"><xsl:attribute name="checked">checked</xsl:attribute></xsl:if> 
      </input><label for="{ID}"><xsl:value-of select="NAME"/></label> 
     </li> 
    </xsl:for-each> 
    </ul> 

Mais je ne sais pas comment récursion jusqu'à l'embarqué « bar » dans la "barre", jusqu'à de nombreux niveaux, il pourrait y avoir.

+0

@Paul: Résistez à l'envie d'utiliser ''. Il constitue la plupart du temps une solution élégante. Essayez de faire les choses avec '' à la place, non seulement cela réduit la complexité d'imbrication de votre feuille de style, mais cela vous permet également de produire une transformation basée sur le contenu plutôt que itérative/impérative. – Tomalak

+0

@Tomalak: Je suis plutôt d'accord - si vous le pouvez, la mise en correspondance des modèles offre le design le plus clair. Mais je trouve que je ne peux pas toujours utiliser le match d'une manière directe pour résoudre mes propres problèmes. Mais dans ce cas, je suis tout à fait d'accord, la correspondance est meilleure que pour chaque + appel –

Répondre

5

est ici une façon:

<xsl:template match="bar"> 
    <li> 
     <input type="checkbox" name="{ID}" value="{ID}"> 
      <xsl:if test="CHECKED = 'Y'"> 
       <xsl:attribute name="checked">checked</xsl:attribute> 
      </xsl:if> 
     </input> 
     <label for="{ID}"><xsl:value-of select="NAME"/></label> 
     <!-- 

      If we have bar children, make a list and recurse 

     --> 
     <xsl:if test="bar"> 
      <ul> 
       <xsl:apply-templates select="bar"/> 
      </ul> 
     </xsl:if> 
    </li> 
</xsl:template> 

Cela repose sur la mise en correspondance de modèle "automatique". Pour assurer la mise en correspondance a lieu, vous pouvez soit mettre un <xsl:apply-templates/> dans la boucle <xsl:for-each> de votre code d'origine, cependant, vous pouvez même améliorer tout et remplacer ce code d'origine avec ce modèle:

<xsl:template match="/foo"> 
    <ul class="tree"> 
     <xsl:apply-templates select="bar"/> 
    </ul> 
</xsl:template> 

Si vous voulez plus contrôle, vous pouvez également utiliser <xsl:for-each select="bar"> et appeler un modèle nommé (<xsl:template name="some-name">... et <xsl:call-template>) à l'intérieur de la boucle. Voir: http://www.w3.org/TR/xslt#named-templates

+0

+ 1 solution parfaite. – Tomalak

+0

Il ne semble pas trouver la première "barre". –

+0

Merci, Tomalak :) –

2

<xsl:template match="foo"> 
    <ul class="tree"> 
     <xsl:apply-templates/> 
    </ul> 
</xsl:template> 

<xsl:template match="bar" name="wunderbar"> 
<!-- we want to match all bars, not only /foo/bars --> 
    <li> 
     <input type="checkbox" name="{ID}" value="{ID}"> 
     <xsl:if test="CHECKED = 'Y'"><xsl:attribute name="checked">checked</xsl:attribute></xsl:if> 
     </input><label for="{ID}"> 
      <xsl:value-of select="NAME"/> 
     </label> 
     <!-- If there is some bar, the next template is applied --> 
     <xsl:apply-templates/> 
    </li> 
</xsl:template> 

<xsl:template match="bar/bar"> 
<!-- Just adds <ul> around bar included in bar and calls the usual template --> 
    <ul> 
     <xsl:call-template name="wunderbar"/> 
    </ul> 
</xsl:template> 

3

Ceci est un exemple (preuve de concept, en fait) pour une solution complètement axée sur l'entrée, de style pousser (modèle correspondant uniquement, pas conditionals, aucun modèle nommé):

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 

    <xsl:template match="*[bar]"> 
    <ul class="tree"> 
     <xsl:apply-templates select="bar" mode="li" /> 
    </ul> 
    </xsl:template> 

    <xsl:template match="bar" mode="li"> 
    <li> 
     <xsl:apply-templates select="." mode="checkbox" /> 
     <xsl:apply-templates select="(.)[bar]" /> 
    </li> 
    </xsl:template> 

    <xsl:template match="bar" mode="checkbox"> 
    <input type="checkbox" id="{ID}" name="{NAME}"> 
     <xsl:apply-templates select="CHECKED" /> 
    </input> 
    <label for="{ID}"> 
     <xsl:value-of select="NAME" /> 
    </label> 
    </xsl:template> 

    <xsl:template match="CHECKED"> 
    <xsl:attribute name="checked">checked</xsl:attribute> 
    </xsl:template> 

</xsl:stylesheet> 

Lorsque appliqué à ce XML d'entrée (extrapolée à partir de votre question):

<foo> 
    <bar> 
    <ID>nd1</ID> 
    <NAME>Node 1</NAME> 
    <CHECKED /> 
    <bar> 
     <ID>nd2</ID> 
     <NAME>Node 2</NAME> 
     <CHECKED /> 
    </bar> 
    </bar> 
    <bar> 
    <ID>nd3</ID> 
    <NAME>Node 3</NAME> 
    </bar> 
    <bar> 
    <ID>nd4</ID> 
    <NAME>Node 4</NAME> 
    <bar> 
     <ID>nd5</ID> 
     <NAME>Node 5</NAME> 
     <CHECKED /> 
     <bar> 
     <ID>nd6</ID> 
     <NAME>Node 6</NAME> 
     <CHECKED /> 
     </bar> 
    </bar> 
    </bar> 
</foo> 

Il produit cette sortie:

<ul class="tree"> 
    <li> 
    <input type="checkbox" id="nd1" name="Node 1" checked="checked" /> 
    <label for="nd1">Node 1</label> 
    <ul class="tree"> 
     <li> 
     <input type="checkbox" id="nd2" name="Node 2" checked="checked" /> 
     <label for="nd2">Node 2</label> 
     </li> 
    </ul> 
    </li> 
    <li> 
    <input type="checkbox" id="nd3" name="Node 3" /> 
    <label for="nd3">Node 3</label> 
    </li> 
    <li> 
    <input type="checkbox" id="nd4" name="Node 4" /> 
    <label for="nd4">Node 4</label> 
    <ul class="tree"> 
     <li> 
     <input type="checkbox" id="nd5" name="Node 5" checked="checked" /> 
     <label for="nd5">Node 5</label> 
     <ul class="tree"> 
      <li> 
      <input type="checkbox" id="nd6" name="Node 6" checked="checked" /> 
      <label for="nd6">Node 6</label> 
      </li> 
     </ul> 
     </li> 
    </ul> 
    </li> 
</ul> 
+0

Cool! Merci d'avoir partagé :) –

Questions connexes