Search

I'll just set the stage:

  1. I have a datasource of products that could be any number.
  2. I have 4 layout group possibilities that I want to iterate over (1 to 4) and re-iterate over and over agian.
  3. I want to add 4 products per group.

I know how to use modulo to count every 4 products and apply a div wrapper to every 4, but what I can't wrap my head around is how to tell each div to have a class name of one, two, three, or four dependant on which iteration it is at, based on my layout groups.

Am I looking at this wrong? Should I be using just recursion here or have I got the right idea with modulo? How would I combine the two to achieve the following html

<div class="group two">
    <article class="product"></article>
    <article class="product"></article>
    <article class="product"></article>
    <article class="product"></article>
</div>
<div class="group three">
    <article class="product"></article>
    <article class="product"></article>
    <article class="product"></article>
    <article class="product"></article>
</div>
<div class="group four">
    <article class="product"></article>
    <article class="product"></article>
    <article class="product"></article>
    <article class="product"></article>
</div>

But with continuing over and over again.

The modulo stuff I have is:

<xsl:apply-templates select="/data/products/entry[position() mod 4 = 1]" mode="group"/>

<xsl:template match="products/entry" mode="group">
    <!-- I need to add classes one to four per iteration to this div -->        
    <div class="group">
        <xsl:apply-templates select=". | following-sibling::entry[position() &lt; 4]" mode="product"/>
    </div>
</xsl:template>

<xsl:template match="products/entry | products/entry" mode="product">
    <article class="product"></article>
</xsl:template-match>    

Does this make sense what I need to achieve?

position() gives you the info you seek. Perhaps something like this?

<xsl:template match="products/entry" mode="group">
    <!-- I need to add classes one to four per iteration to this div -->        
    <div class="group group-{position()}">
        <xsl:apply-templates select=". | following-sibling::entry[position() &lt; 4]" mode="product"/>
    </div>
</xsl:template>

I recommend using group-1, group-2 etc instead of words because words don't scale well whilst numbers do. However, if you're stuck with wordish classes, you can use a small template like this:

<xsl:template name="num-to-word">
    <xsl:param name="num"/>

    <xsl:choose>
        <xsl:when test="$num = 1">one</xsl:when>
        <xsl:when test="$num = 2">two</xsl:when>
        <xsl:when test="$num = 3">three</xsl:when>
        <xsl:when test="$num = 4">four</xsl:when>
        ...
    </xsl:choose>
</xsl:template>

Of course, silly me.

For some reason I forgot that the position() is relative to the matched set, not (as I was thinking) the entire set.

Thanks very much for your insight there.

Proof of the pudding

Apart from, it doesn't reset the count after 4 and just keeps counting.

I need to count one to four, one to four, one to four etc etc

I guess I'd need modulo again in the number template?

Answered my own question about the last little bit.

Thanks again!

You're welcome. Glad you figured it out.

Have I lately told you that I love XSLT? OK, it's rather verbose — but it's also a damned elegant concept.

+1, michael.

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