XSLT包装新容器中的每个项目

时间:2013-03-28 18:47:12

标签: xml xslt xslt-1.0

所以我过去曾写过基本的XSLT,但我遇到了一个新问题。

我们正在使用网格系统,因此,简单的for-each是不够的。相反,我需要每3个项目在HTML输出中创建一个新的row

简而言之,我需要帮助编写XSLT(从头开始),以便发生这种情况:

理念:

<!-- The below div ("group") should repeat every group -->
<div class="group">
  <h2>Group #</h2>
  <!-- The below div ("row") should repeat every 3 items -->
  <div class="row">
    <!-- The below div ("four columns") should be repeated every item -->
    <div class="four columns">
      <div class="item">...</div>
    </div>
  </div>
</div>

XML:

<group name="Group 1">
  <item name="Item 1" />
  <item name="Item 2" />
  <item name="Item 3" />
  <item name="Item 4" />
</group>

<group name="Group 2">
  ...
</group>

它的外观应该是什么:

<div class="group">
  <h2>Group 1</h2>
  <div class="row">
    <div class="four columns">
      <div class="item">Item 1</div>
    </div>
    <div class="four columns">
      <div class="item">Item 2</div>
    </div>
    <div class="four columns">
      <div class="item">Item 3</div>
    </div>
  </div>

  <div class="row">  
    <div class="four columns">
      <div class="item">Item 4</div>
    </div>
  </div>
</div>

<div class="group">
  <h2>Group 2</h2>
  ...
</div>

1 个答案:

答案 0 :(得分:5)

假设您有一个参数来表示您希望分组的行数,您可以先选择 item 元素和当前 group 元素。第1,第4,第7等位置。

<xsl:apply-templates select="item[position() mod $rows = 1]" mode="group"/>

(注意使用模式,因为您将有两个匹配元素的模板)

然后,在与之匹配的模板中,您将选择组中的所有项目,如此

<xsl:apply-templates select="self::*|following-sibling::item[position() &lt; $rows]"/>

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:param name="rows" select="3"/>

   <xsl:template match="group">
      <div class="group">
         <h2><xsl:value-of select="@name"/></h2>
         <xsl:apply-templates select="item[position() mod $rows = 1]" mode="group"/>
      </div>
   </xsl:template>

   <xsl:template match="item" mode="group">
      <div class="row">
         <xsl:apply-templates select="self::*|following-sibling::item[position() &lt; $rows]"/>
      </div>
   </xsl:template>

   <xsl:template match="item">
      <div class="four columns">
         <div class="item"><xsl:value-of select="@name"/></div>
      </div>
   </xsl:template>
</xsl:stylesheet>

应用于以下XML

<groups>
    <group name="Group 1">
        <item name="Item 1"/>
        <item name="Item 2"/>
        <item name="Item 3"/>
        <item name="Item 4"/>
    </group>
    <group name="Group 2">
        <item name="Item 1"/>
        <item name="Item 2"/>
        <item name="Item 3"/>
        <item name="Item 4"/>
    </group>
</groups>

以下是输出

<a>
   <div class="group">
      <h2>Group 1</h2>
      <div class="row">
         <div class="four columns">
            <div class="item">Item 1</div>
         </div>
         <div class="four columns">
            <div class="item">Item 2</div>
         </div>
         <div class="four columns">
            <div class="item">Item 3</div>
         </div>
      </div>
      <div class="row">
         <div class="four columns">
            <div class="item">Item 4</div>
         </div>
      </div>
   </div>
   <div class="group">
      <h2>Group 2</h2>
      <div class="row">
         <div class="four columns">
            <div class="item">Item 1</div>
         </div>
         <div class="four columns">
            <div class="item">Item 2</div>
         </div>
         <div class="four columns">
            <div class="item">Item 3</div>
         </div>
      </div>
      <div class="row">
         <div class="four columns">
            <div class="item">Item 4</div>
         </div>
      </div>
   </div>
</a>

编辑:在回答您的评论时,如果您想更改最后一列的班级名称(如果没有确切的列数),您可以使用 xsl:choose 执行此操作检查它是否是最后一项,并且它的位置与所需的数字不匹配。

<xsl:template match="item">
   <div>
      <xsl:attribute name="class">
         <xsl:choose>
            <xsl:when test="not(following-sibling::item) and position() mod $rows != 0">end</xsl:when>
            <xsl:otherwise>four columns</xsl:otherwise>
         </xsl:choose>
      </xsl:attribute>
      <div class="item">
         <xsl:value-of select="@name"/>
      </div>
   </div>
</xsl:template>