Search

Let’s say that you need to group images in sets of three, say for grid layouts and such. What is your way of doing it? Let me show you one way.

Let’s use this XML as our sample:

<?xml version="1.0" encoding="utf-8" ?>
<data>
    <books>
        <entry>1</entry>
        <entry>2</entry>
        <entry>3</entry>
        <entry>4</entry>
        <entry>5</entry>
        <entry>6</entry>
        <entry>7</entry>
        <entry>8</entry>
        <entry>9</entry>
        <entry>10</entry>
        <entry>11</entry>
        <entry>12</entry>
        <entry>13</entry>
        <entry>14</entry>
        <entry>15</entry>
    </books>
</data>

Here is the XSLT:

<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet version="1.0" xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>

<xsl:output method='xml' version='1.0' encoding='utf-8' indent='yes'/>

<xsl:template match="data">
    <xsl:apply-templates select="books/entry[position() mod 3 = 1]"/>
</xsl:template>

<xsl:template match="books/entry">
    <div class="group">
        <xsl:apply-templates select=". | following-sibling::entry[position() &lt;= 2]" mode="content"/>
    </div>
</xsl:template>

<xsl:template match="books/entry" mode="content">
    <p><xsl:value-of select="."/></p>
</xsl:template>

</xsl:stylesheet>

If you want to change the grouping from 3 to 6, simply change the mod divisor and the following-sibling count accordingly.

This utilises the concepts found in the HTML manipulation ninja technique; using apply-templates, modes and a little XPath pizazz.

And with anything XSLT, using rule based methods always yields +10 cool points!

Note that this isn’t an utility but I’m sure someone with more time would eventually make it into one.

This is simply amazing! The power of XSLT never ceases to amaze me.

Just for clarification, the number in the following::sibling expression should always be 1 less than the number of items you want in the group, correct?

Allen, thanks so much for sharing this code! This is awesome!

Allen’s awesome example inspired me to waste some time and cook this piece up:

<xsl:template name="GroupItems">
    <xsl:param name="Items" select="./*" />
    <xsl:param name="Count" select="3" />

    <xsl:variable name="ItemName" select="string(name($Items))" />

    <xsl:for-each select="$Items[position() mod $Count = 1]">
        <xsl:variable name="Left" select="count(following-sibling::*[1]/preceding-sibling::*[name() = $ItemName])" />
        <xsl:variable name="Right" select="$Left + $Count" />

        <xsl:apply-templates select="parent::*" mode="GroupItems">
            <xsl:with-param name="Items" select="$Items[position() &gt;= $Left and position() &lt; $Right]" />
            <xsl:with-param name="Position" select="position()" />
        </xsl:apply-templates>
    </xsl:for-each>
</xsl:template>

You feed it some items like so (using the original XML):

<xsl:template match="data">
    <xsl:call-template name="GroupItems">
        <xsl:with-param name="Items" select="books/entry" />
    </xsl:call-template>
</xsl:template>

The utility will take the items and apply the item’s parent node template in the GroupItems mode, feeding it a subset of items (optionally feeding it the group number). The following templates will create lists containing the grouped items:

<xsl:template match="books" mode="GroupItems">
    <xsl:param name="Items" select="entry" />
    <xsl:param name="Position" />
    <ol class="Group">
        <xsl:apply-templates select="$Items" mode="GroupItems" />
    </ol>
</xsl:template>

<xsl:template match="books/entry" mode="GroupItems">
    <li>
        <xsl:value-of select="."/>
    </li>
</xsl:template>

Thanks, Allen and sirlancelot. This is sure to come in handy.

yeah xslt rocks!

I used something like this years back, I had a horizontal layout of 400px and needed navigation boxes to stack up nicely till max heigth , and then move to the next row. Floating them was no option (ugly, doesnt fill up row) so I had something like:

<xsl:variable name="items" select=". | following-sibling::thenode[position() &lt; $maxItemsColumn]" />

It was based on something from jeni

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details