代码之家  ›  专栏  ›  技术社区  ›  John B

如何将<xsl:foreach>拆分为多个部分?

  •  3
  • John B  · 技术社区  · 15 年前

    我有一个元素列表,我想把它分成3个单独的列表。最终结果是这样的:

    <ul>
        <li>element</li>
        <li>element</li>
    </ul>
    <ul>
        <li>element</li>
        <li>element</li>
    </ul>
    <ul>
        <li>element</li>
        <li>element</li>
    </ul>
    

    我的XSLT是这样的,但它不起作用,因为我不能插入 </ul> ,不能插入小于号( < )

    <ul>
        <xsl:for-each select="$myroot/item">
            <li></li>
    
            <xsl:if test="position() mod $maxItemsPerColumn = 0">
                <!-- I want to close my ul, and start a new one here, but it doesn't work! -->
            </xsl:if>
        </xsl:for-each>
    </ul>
    

    有什么想法吗?事先谢谢!

    4 回复  |  直到 15 年前
        1
  •  9
  •   Robert Rossney    15 年前

    你不需要做像递归这样的花哨的事情。上帝啊,别想用CDATA。

    您只需要像XSLT那样思考,然后问:“我要将什么输入元素转换为输出元素?”

    假设每个 ul 应该包含n item s,您要转换每个第n个输入 项目 从第一个开始,变成一个 UL :

    <xsl:variable name="n" select="number(4)"/>
    
    <xsl:template match="/">
      <output>
        <xsl:apply-templates select="/root/item[position() mod $n = 1]"/>
      </output>
    </xsl:template>
    

    每一个 项目 元素变为 保险商实验室 包含该项及其每个n-1以下同级项的:

    <xsl:template match="item">
      <ul>
        <xsl:for-each select=". | following-sibling::item[position() &lt; $n]">
          <li>
            <xsl:value-of select="."/>
          </li>
        </xsl:for-each>
      </ul>
    </xsl:template>
    

    假设输入文档如下:

    <root>
      <item>1</item>
      <item>2</item>
      <item>3</item>
      <item>4</item>
      <item>5</item>
      <item>6</item>
      <item>7</item>
      <item>8</item>
      <item>9</item>
    </root>
    

    …如果 $n 设置为4:

    <output>
      <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
      </ul>
      <ul>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
      </ul>
      <ul>
        <li>9</li>
      </ul>
    </output>
    
        2
  •  1
  •   Greg Hewgill    15 年前

    您可以使用递归解决方案:

    <xsl:call-template name="group">
      <xsl:with-param name="items" select="$myroot/item" />
    </xsl:call-template>
    
    <xsl:template name="group">
      <xsl:param name="items" />
      <xsl:if test="count($items) > 0">
        <ul>
          <xsl:for-each select="$items[position() &lt;= 3]">
            <li>...</li>
          </xsl:for-each>
        </ul>
        <xsl:call-template name="group">
          <xsl:with-param name="items" select="$items[position() > 3]" />
        </xsl:call-template>
      </xsl:if>
    </xsl:template>
    

    这就是所谓的 group 整个项目列表的模板。这个 模板写出列表的前三个元素(如果没有三个元素,则少于三个)。 <ul> ... </ul> 标签。然后,它再次调用自己,而项目列表的其余部分省略了前三项。当列表为空时, 模板不起作用。

    XSLT是一种非常实用的语言,遵循规则(即不使用 disable-output-escaping 因此,当您需要再次修改模板时,可以避免将来的许多痛苦和痛苦。

        3
  •  0
  •   Pierre    15 年前

    你可以尝试这样的方法(没有测试,但你有这个想法)

    (...)
    <xsl:call-template name="recursive">
     <xsl:with-param name="root" select="$myroot"/>
     <xsl:with-param name="index" select="number(1)"/>
    </xsl:call-template>
    (...)
    
    
    <xsl:template name="recursive">
    <xsl:param name="root"/>
    <xsl:param name="index"/>
    <ul>
    <li><xsl:value-of select="$root/item[$index]"/></li>
    <li><xsl:value-of select="$root/item[$index +1 ]"/></li>
    </ul>
    <xsl:if test="$root/item[$index+2]">
    <xsl:call-template name="recursive">
     <xsl:with-param name="root" select="$root"/>
     <xsl:with-param name="index" select="$index+2"/>
    </xsl:call-template>
    </xsl:if>
    </xsl:template>
    
        4
  •  -1
  •   Jared xxtesaxx    15 年前

    你可以的

    <xsl:text disable-output-escaping="yes"><![CDATA[</ul>]]></xsl:text>
    
    <xsl:text disable-output-escaping="yes"><![CDATA[<ul>]]></xsl:text>
    

    所以在你的例子中:

    <ul>
        <xsl:for-each select="$myroot/item">
            <li></li>
    
            <xsl:if test="position() mod $maxItemsPerColumn = 0">
                <xsl:text disable-output-escaping="yes"><![CDATA[</ul>]]></xsl:text>
                <xsl:text disable-output-escaping="yes"><![CDATA[<ul>]]></xsl:text>                
            </xsl:if>
        </xsl:for-each>
    </ul>
    

    更新: 我读了皮埃尔和格雷格的答案后删除了这个,但我决定继续读下去,因为它确实回答了你的问题,而且在某个地方,它可能对某人有用。

    更新2: 是的,我理解为什么这会让我的同龄人感到恐惧,并激发了纳兹格»L-型的恐惧感,是的,我自己也曾试图拒绝投票,不过我认为这个答案对将来的某个人可能会有所帮助。

    推荐文章