tags:

views:

63

answers:

3

Hello, help me please. There is a list of nodes.

<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>

Need to divide the list of "n" (arbitrary number) equal parts.

If the number of nodes is not divided equally, then let the last set of nodes will contain the remainder of the division.

For example, if the input list contains 33 elements and the output should have 4 parts with uniformly distributed elements. At the exit to get 3 parts to 9 of elements and one part with 6 elements in the sum of 33.

input

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

Output

<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>

Divided into 4 cols.

+1  A: 
<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>
Tomalak
This is not something that should be. You divide into groups of 4 elements in the group, and must be divided into 4 groups, which are evenly distributed all the elements.
Kalinin
@kalininew: Do you seriously want to tell me you are unable to calculate `$max` dynamically? Here's a hint `ceiling(count(/list/item) div 4)`
Tomalak
+2  A: 

This solution doesn't require that the nodes to be grouped into columns should be siblings:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <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>

When applied on this XML document:

<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>

The wanted result is produced:

<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>
Dimitre Novatchev
Thank you very much, your code is fully working. That right!Then yet another question: how can first sort the whole list alphabetically, and then divide it in columns?
Kalinin
@kalininew: Ask this as a new question and I'll be happy to answer :)More seriously, I must now prepare to go to work -- will answer in probably 3 hours.
Dimitre Novatchev
Thanks, I will wait for a response.
Kalinin
+1  A: 

This is a separate answer to a new question asked by the OP in one of his comments to the accepted answer:

Thank you very much, your code is fully working. That right! Then yet another question: how can first sort the whole list alphabetically, and then divide it in columns? – @kalininew

This is almost as easy as before, with one additional step required:

  1. Sort the nodes

  2. Apply the xxx:node-set() extension function (hint: exslt:node-set() is implemented by most browsers) to convert the RTF (Result Tree Fragment) created in step 1. above to a regular node-set.

  3. Apply the transformation that solves the original problem, to the result of step 2. above.

Dimitre Novatchev
Thank you, I went to try.
Kalinin