XSL中的列表的递归列表

时间:2010-02-23 16:32:08

标签: xslt recursion

我有一个递归节点,我正在尝试为jquery-checktree设置。节点看起来像

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

如果任何栏可能有或没有一个或多个栏位节点,但任何栏都有ID和NAME,可能有CHECKED。

我希望将其转变为

<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>

我可以通过以下方式获得第一级:

    <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>

但是我不知道如何递归到“bar”中的嵌入式“bar”,可能会有很多级别。

3 个答案:

答案 0 :(得分:5)

这是一种方式:

<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>

这依赖于“自动”模板匹配。为确保匹配发生,您可以在原始代码的<xsl:apply-templates/>循环中放置<xsl:for-each>,但是,您甚至可以改进所有内容并使用此模板替换原始代码:

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

如果您想要更多控制权,还可以使用<xsl:for-each select="bar">并在循环内调用命名模板(<xsl:template name="some-name">...<xsl:call-template>)。请参阅:http://www.w3.org/TR/xslt#named-templates

答案 1 :(得分:3)

这是一个完全由输入驱动的推式解决方案(仅模板匹配,无条件,无命名模板)的示例(实际上是概念证明):

<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>

当应用于此输入XML时(根据您的问题推断):

<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>

它产生这个输出:

<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>

答案 2 :(得分: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>