XSLT按计数对项目进行分组

时间:2013-05-16 02:38:51

标签: xslt xslt-grouping

我有以下项目清单。

<items>
    <item type="Type1">Item1</item>
    <item type="Type2">Item2<item>
    <item type="Type2">Item3<item>
    <item type="Type3">Item4<item>
    <item type="Type3">Item5<item>
    <item type="Type1">Item6<item>
    <item type="Type3">Item7<item>
    <item type="Type1">Item8<item>
    <item type="Type2">Item9<item>
    <item type="Type1">Item10<item>
<items>

我无法确定所需的XSLT,以便上面显示的是Type1(x1),Type2(x2),Type3(x4)的组,其中计数是括号中的数字或更少。换句话说,目标是创建一个重复模式:Type1的下一个项目,如果其中任何一个保留,那么接下来的两个Type2或更少,如果少于两个,则接下来的四个Type3或更少,如果更少还剩下四个人。

所以期望的输出看起来如下所示:

<div class="Items">
    <div class="Type1">Item1</div>
    <div class="Type2">Item2</div>
    <div class="Type2">Item3</div>
    <div class="Type3">Item4</div>
    <div class="Type3">Item5</div>
    <div class="Type3">Item7</div>
    <div class="Type1">Item6</div>
    <div class="Type2">Item9</div>
    <div class="Type1">Item8</div>
    <div class="Type1">Item10</div>
</div>

从上面的输出中,您可以看到订单已更改。即,&lt; = 1型1,然后&lt; = 2型2,然后&lt; = 4型3,并且该图案自身重复。我想这些项目需要被分组到所描述的模式中,并且如果项目用尽,则重复自己直到完整列表。我希望我有道理。

任何人都可以提供所需的XSLT或指针吗?

谢谢, 约翰。

1 个答案:

答案 0 :(得分:0)

请给它一个旋转:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="kType2Group" match="item[@type = 'Type2']"
           use="floor(count(preceding-sibling::item[@type = 'Type2']) div 2) + 1"/>
  <xsl:key name="kType3Group" match="item[@type = 'Type3']"
           use="floor(count(preceding-sibling::item[@type = 'Type3']) div 4) + 1"/>

  <xsl:template match="@* | node()" name="Copy">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="item[@type = 'Type1']" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="item[@type = 'Type1']">
    <xsl:call-template name="Copy" />
    <xsl:apply-templates select="key('kType2Group', position())" />
    <xsl:apply-templates select="key('kType3Group', position())" />
  </xsl:template>
</xsl:stylesheet>

在输入XML上运行时,结果为:

<items>
  <item type="Type1">Item1</item>
  <item type="Type2">Item2</item>
  <item type="Type2">Item3</item>
  <item type="Type3">Item4</item>
  <item type="Type3">Item5</item>
  <item type="Type3">Item7</item>
  <item type="Type1">Item6</item>
  <item type="Type2">Item9</item>
  <item type="Type1">Item8</item>
  <item type="Type1">Item10</item>
</items>

这种情况下的密钥用于将Type2和Type3项分成组,以便可以通过组号(1,2,3等)检索它们,确定组号的逻辑是否计数相同类型的前面项目的数量,将该数字除以每个组中的项目数,向下舍入,并添加一个。因此,例如,对前四个Type2执行的计算将是:

floor(0 div 2) + 1 = floor(0) + 1 = 0 + 1 = 1
floor(1 div 2) + 1 = floor(0.5) + 1 = 0 + 1 = 1
floor(2 div 2) + 1 = floor(1) + 1 = 1 + 1 = 2
floor(3 div 2) + 1 = floor(1.5) + 1 = 1 + 1 = 2

等等。

XSLT的一般逻辑是:

  • 匹配根元素,复制它,并将模板应用于所有Type1项目。
  • Type1项目的模板:
    • 复制项目本身。
    • 使用密钥将模板应用于其组中的Type2项目(position()将为1表示第一个Type1项目,2表示第二个,依此类推。
    • 使用密钥将模板应用于其组中的Type3项目
  • 第一个模板,即身份模板,可以复制任何没有任何其他模板的模板来匹配它。