gorn.ch

Tobias Ebnöther's personal blog

Multi Column Lists with XSLT

Yes still alive and starting a try to write more :)

After spending a Day trying to create a nice multi column list with CSS that works nicely on all browsers I gave up and decided to go back on the good old multi-list approach. With XSLT this can get a little ugly and I didn’t find an approach that can rely on only apply-template calls. Here is my solution with call-template:

<xsl:template name="listColumn">
    <xsl:param name="entries" /> <!-- List of all nodes -->
    <xsl:param name="columns" /> <!-- Number of columns to be created -->
    <xsl:param name="class" /> <!-- Overwrites default class -->

    <xsl:variable name="entryCount" select="count($entries)" />

    <!-- This is getting called recursively so watch out…-->
    <xsl:call-template name="createColumn">
        <xsl:with-param name="entries" select="$entries" />
        <xsl:with-param name="entryCount" select="$entryCount" />
        <xsl:with-param name="cut" select="ceiling($entryCount div $columns)" />
        <xsl:with-param name="columnNumber" select="0" />
        <xsl:with-param name="class" select="$class" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="createColumn">
    <xsl:param name="entries" /> <!-- List of all entries -->
    <xsl:param name="entryCount" /> <!-- Count of the entries -->
    <xsl:param name="cut" /> <!-- Where the list gets cut -->
    <xsl:param name="class" select="'listColumn'"/> <!-- Default or special class -->
    <xsl:param name="columnNumber" /> <!-- Current column gets incremented by recursion -->

    <xsl:variable name="min" select="$cut * $columnNumber" />
    <xsl:variable name="max" select="$cut * ($columnNumber + 1)" />

    <ul class="{$class}">
        <xsl:apply-templates select="$entries[position() &gt; $min and position() &lt;= $max]" mode="listColumn" />
    </ul>

    <!-- Call this template again if entries left -->
    <xsl:if test="$max &lt; $entryCount">
        <xsl:call-template name="createColumn">
            <xsl:with-param name="entries" select="$entries" />
            <xsl:with-param name="entryCount" select="$entryCount" />
            <xsl:with-param name="cut" select="$cut" />
            <xsl:with-param name="columnNumber" select="$columnNumber + 1" />
            <xsl:with-param name="class" select="$class" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<xsl:template match="*" mode="listColumn">
    <li>
        <xsl:apply-templates />
    </li>
</xsl:template>

It calls a template recursively and creates the necessary amount of lists. If the number of entries doesn’t match up the last list will get shorter and the distribution isn’t really optimized. Any comments and improvements are welcome :)

 Permalink
Powered by Flux CMS