XSL:列表分为列

时间:2010-03-17 11:42:33

标签: xml xslt

请帮助我。有一个节点列表。

<list>
  <item>1</item>
  <item>2</item>
  <item>3</item>
  <item>4</item>
  <item>5</item>
  <item>6</item>
  <item>7</item>
  and so on...
</list>

需要划分“n”(任意数)等份的列表。

如果节点数没有平均分配,那么让最后一组节点包含除法的剩余部分。

例如,如果输入列表包含33个元素,并且输出应该包含4个具有均匀分布元素的部分。在出口处获得3个部分到9个元素,一个部分有6个元素,总数为33。

输入

<ul>
    <li>1</li>
    <li>2</li>
    ... 
    <li>33</li>
</ul>

输出

<ul>
    <li>1</li>
    <li>2</li>
    ... 
    <li>9</li>
</ul>
<ul>
    <li>10</li>
    <li>11</li>
    ... 
    <li>18</li>
</ul>
<ul>
    <li>19</li>
    <li>11</li>
    ... 
    <li>27</li>
</ul>
<ul>
    <li>28</li>
    <li>30</li>
    ... 
    <li>33</li>
</ul>

分为4个小组。

3 个答案:

答案 0 :(得分:5)

此解决方案不要求将要分组到列中的节点作为兄弟

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vNodes" select="/*/*/text()"/>

 <xsl:param name="vNumParts" select="4"/>

 <xsl:variable name="vNumCols" select=
   "ceiling(count($vNodes) div $vNumParts)"/>

 <xsl:template match="/">
   <table border="1">
     <xsl:for-each select=
        "$vNodes[position() mod $vNumCols = 1]">
       <xsl:variable name="vCurPos" select=
         "(position()-1)*$vNumCols +1"/>
       <tr>
          <xsl:for-each select=
            "$vNodes[position() >= $vCurPos
                    and
                     not(position() > $vCurPos + $vNumCols -1)
                     ]">
           <td><xsl:copy-of select="."/></td>
          </xsl:for-each>
       </tr>
     </xsl:for-each>
   </table>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档

<list>
  <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>
  <item>10</item>
  <item>11</item>
  <item>12</item>
  <item>13</item>
  <item>14</item>
  <item>15</item>
  <item>16</item>
  <item>17</item>
  <item>18</item>
  <item>19</item>
  <item>20</item>
  <item>21</item>
  <item>22</item>
  <item>23</item>
  <item>24</item>
  <item>25</item>
  <item>26</item>
  <item>27</item>
  <item>28</item>
  <item>29</item>
  <item>30</item>
  <item>31</item>
  <item>32</item>
  <item>33</item>
</list>

生成了想要的结果

<table border="1">
   <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
      <td>4</td>
      <td>5</td>
      <td>6</td>
      <td>7</td>
      <td>8</td>
      <td>9</td>
   </tr>
   <tr>
      <td>10</td>
      <td>11</td>
      <td>12</td>
      <td>13</td>
      <td>14</td>
      <td>15</td>
      <td>16</td>
      <td>17</td>
      <td>18</td>
   </tr>
   <tr>
      <td>19</td>
      <td>20</td>
      <td>21</td>
      <td>22</td>
      <td>23</td>
      <td>24</td>
      <td>25</td>
      <td>26</td>
      <td>27</td>
   </tr>
   <tr>
      <td>28</td>
      <td>29</td>
      <td>30</td>
      <td>31</td>
      <td>32</td>
      <td>33</td>
   </tr>
</table>

答案 1 :(得分:2)

这是对OP提出的一个新问题的单独答案,他对接受的答案的评论之一是:

非常感谢,您的代码完全正常运行。没错!然后是另一个问题:如何首先按字母顺序对整个列表进行排序,然后将其除以列? - @kalininew

这几乎和以前一样简单,需要额外增加一步:

  1. 对节点进行排序

  2. 应用xxx:node-set()扩展功能(提示:exslt:node-set()由大多数浏览器实现)将上面步骤1中创建的RTF(结果树片段)转换为常规节点集

  3. 将解决原始问题的转换应用于上述步骤2的结果。

答案 2 :(得分:1)

<xsl:variable name="max" select="4" />

<xsl:template match="/">
  <xsl:apply-templates select="list" mode="split" />
</xsl:template>

<xsl:template match="list" mode="split">
  <xsl:apply-templates select="item[position() mod $max = 1]" mode="split" />
</xsl:template>

<xsl:template match="item" mode="split">
  <list>
    <xsl:copy-of select=". | following-sibling::item[position() &lt; $max]" />
  </list>
</xsl:template>