Search

I am trying to loop 4 items in a for each loop (or applying a template for 4 items) and then take the next 4 items... normally the loop is applied per item.
here's the xml:

<data>
 <blog>
   <entry id="1">
       <title handle="item1">item1</title>
    </entry>
    <entry id="2">
       <title handle="item2">item2</title>
    </entry>
    <entry id="3">
       <title handle="item3">item3</title>
    </entry>
    <entry id="4">
       <title handle="item4">item4</title>
    </entry>
    <entry id="5">
       <title handle="item5">item5</title>
    </entry>
    <entry id="6">
       <title handle="item6">item6</title>
    </entry>
    <entry id="7">
       <title handle="item7">item7</title>
    </entry>
    <entry id="8">
       <title handle="item8">item8</title>
    </entry>
  </blog>
</data>

And the desired result:

<div class="container">
    <h1>item1</h1>
    <h1>item2</h1>
    <h1>item3</h1>
    <h1>item4</h1>
</div>
<div class="container">
    <h1>item5</h1>
    <h1>item6</h1>
    <h1>item7</h1>
    <h1>item8</h1>
</div>

So i am trying to wrap each 4 items in a div container...
Anyone knows how to accomplish this?

Take a look at this Stack Overflow answer, I think it should work:

XSLT to transform list into table with columns determined dynamically

Thanks ashooner,

I came up with this xslt that does the job:

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

<xsl:template match="entry">
    <div class="container">
    <xsl:call-template name="header"/>
    <xsl:for-each select="following-sibling::entry[position() &lt; 4]">
        <xsl:call-template name="header"/>
    </xsl:for-each>
    </div>    
</xsl:template>

<xsl:template name="header">
    <h1><xsl:value-of select="title"/></h1>
</xsl:template>

Nice. I vote this goes into the XSLT Utilities, I'm sure others will find it useful.

Nice. I vote this goes into the XSLT Utilities, I'm sure others will find it useful.

+1

When I'm writing XSLT I try to keep it as consistent as possible, in this case not mixing for-each and apply-templates too much.

Also, I see using named templates and then passing the context node as a param as bad practice; that's what matching templates are made for.

So my suggestion would be something like (notice the mode attribute):

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

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

<xsl:template name="entry" mode="content">
    <h1><xsl:value-of select="title"/></h1>
    <xsl:copy-of select="text/*" />
</xsl:template>

Thanks Nils,
That looks better, my xslt skills just did'nt reach far enough for that, but getting there!

I will submit this to the utilities, what would be a good name?

I was thinking about 'multi-item loop'? Any suggestions?

What about "Group items" or "Group by position"?

Group items it is.... :)

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