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.
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">
<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>
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:
Sort the nodes
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.
Apply the transformation that solves the original problem, to the result of step 2. above.
<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() < $max]" />
</list>
</xsl:template>