如何使用XSLT对连续数字进行分组

时间:2013-08-28 18:08:31

标签: xml xslt foreach

我有以下问题,我认为它有一个简单的解决方案,我只是没有这方面的知识。

我输入了这个例子:

<set>
  <value>8</value>
  <value>1</value>
  <value>2</value>
  <value>10</value>
  <value>4</value>
  <value>22</value>
  <value>12</value>
  <value>45</value>
  <value>11</value>
  <value>3</value>
  <value>5</value>
  <value>9</value>
  <value>21</value>
  <value>6</value>
  <value>7</value>
  <value>13</value>
</set>

我想创建最多10个元素的序列,每个元素的数字是连续的,并且按升序排列。

期望的输出:

<MOrd>
  <range>
    <value>1</value>
    <value>2</value>
    <value>3</value>
    <value>4</value>
    <value>5</value>
    <value>6</value>
    <value>7</value>
    <value>8</value>
    <value>9</value>
    <value>10</value>
  </range>
  <range>
    <value>11</value>
    <value>12</value>
    <value>13</value>
  </range> 
  <range>
    <value>21</value>
    <value>22</value>
  </range>
  <range>
    <value>45</value>
  </range>
</Mord> 

到目前为止我已经使用了这段代码但不知道如何继续:

<MOrd>
  <xsl:for-each select="$Set">
    <xsl:sort select="value" order="ascending" data-type="number"/>
    <xsl:for-each-group select="value" group-by"value">
      <range>
        <xsl:if test=".">
          <value>
            <xsl:value-of select="."/>
          </value>
        </xsl:if>
      </range>
    </xsl:for-each-group>
  </xsl:for-each>
</MOrd>

你怎么会离开这里?

2 个答案:

答案 0 :(得分:3)

我认为您只需要通过一个简单的数学表达式对元素进行分组,以确定10分为数字的次数

<xsl:for-each-group select="value" group-by="floor((number(.) - 1) div 10)">

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="set">
    <MOrd>
      <xsl:for-each-group select="value" group-by="floor((number(.) - 1) div 10)">
          <xsl:sort select="." order="ascending" data-type="number"/>
          <range>
               <xsl:for-each select="current-group()">
                     <xsl:sort select="." order="ascending" data-type="number"/>
                     <xsl:copy-of select="." />
               </xsl:for-each>
           </range>
     </xsl:for-each-group>
    </MOrd>
  </xsl:template>
</xsl:stylesheet>

当应用于输入XML时,输出以下内容

<MOrd>
   <range>
      <value>1</value>
      <value>2</value>
      <value>3</value>
      <value>4</value>
      <value>5</value>
      <value>6</value>
      <value>7</value>
      <value>8</value>
      <value>9</value>
      <value>10</value>
   </range>
   <range>
      <value>11</value>
      <value>12</value>
      <value>13</value>
   </range>
   <range>
      <value>21</value>
      <value>22</value>
   </range>
   <range>
      <value>45</value>
   </range>
</MOrd>

答案 1 :(得分:1)

我知道这是一个老问题,但似乎手头的问题,将连续数字分组,并没有(完全)回答。您可以使用XSLT 2.0中的group-starting-with执行此操作,如下所示(在对输入进行排序后):

<xsl:for-each-group select="value" 
    group-starting-with="value[xs:integer(preceding-sibling::value[1]) + 1 != xs:integer(.)]">
    <range>
        <xsl:copy-of select="current-group()"/>
    </range>
</xsl:for-each-group>

该方法有效,因为每次前一个兄弟节点不低于当前节点时,它会触发一个新组。如果您的输入为1,2,3,6,7,8,12,16,17,则会将其分组为1,2,36,7,81216,17

该解决方案适用于XSLT 2.0和3.0,但不适用于XSLT 1.0。