xsltumbraco

XSLT For-Each Wrapping every nth item in a div


I have a series of nodes that are direct child nodes to a parent I want to loop over those nodes but have them wrapped in 'groups' of 4. I'm probably not wording this very clearly so this might help.

<span class="child01">@nodename</span>
<span class="child02">@nodename</span>
<span class="child03">@nodename</span>
<span class="child04">@nodename</span>
<span class="child05">@nodename</span>
<span class="child06">@nodename</span>
<span class="child07">@nodename</span>
<span class="child08">@nodename</span>
..
<span class="child32">@nodename</span>
<span class="child33">@nodename</span>
..and so on

Goal

<div class="group">
<span class="child01">@nodename</span>
<span class="child02">@nodename</span>
<span class="child03">@nodename</span>
<span class="child04">@nodename</span>
</div>
<div class="group">
<span class="child05">@nodename</span>
<span class="child06">@nodename</span>
<span class="child07">@nodename</span>
<span class="child08">@nodename</span>
</div>
<div class="group">
..
<span class="child32">@nodename</span>
</div>
<div class="group">
<span class="child33">@nodename</span>
..and so on

I have tried variations on this idea - wrapping the lot in the open and closing group tags and every fourth loop drop in a new close / open pair.

<div class="group">
<xsl:for-each select="$currentPage/*">
                      
<span>
<xsl:value-of select="@nodeName" />
</span>
         
 <!--
            =============================================================
            After very 4th item  
            =============================================================
            -->
            <xsl:if test="position() mod 4 = 0">
              <xsl:text></div><div class="page"></xsl:text>
            </xsl:if>

        </xsl:for-each>
</div>

But essentially it seems XSLT won't let me start with a closing unmatched tag.

The closest solution I have found so far is a 'fix' in jquery but I would rather not rely on javascript to format the page.


Solution

  • This transformation:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:param name="pNumCols" select="3"/>
    
     <xsl:template match="/*">
      <xsl:apply-templates select="span[position() mod $pNumCols = 1]"/>
     </xsl:template>
    
     <xsl:template match="span">
      <div>
       <xsl:copy-of select=
        ".|following-sibling::span[not(position() > $pNumCols -1)]"/>
      </div>
     </xsl:template>
    </xsl:stylesheet>
    

    when applied on the provided XML document:

    <t>
        <span class="child01">@nodename</span>
        <span class="child02">@nodename</span>
        <span class="child03">@nodename</span>
        <span class="child04">@nodename</span>
        <span class="child05">@nodename</span>
        <span class="child06">@nodename</span>
        <span class="child07">@nodename</span>
        <span class="child08">@nodename</span> .. 
        <span class="child32">@nodename</span>
        <span class="child33">@nodename</span>
    </t>
    

    produces the wanted result:

    <div>
       <span class="child01">@nodename</span>
       <span class="child02">@nodename</span>
       <span class="child03">@nodename</span>
    </div>
    <div>
       <span class="child04">@nodename</span>
       <span class="child05">@nodename</span>
       <span class="child06">@nodename</span>
    </div>
    <div>
       <span class="child07">@nodename</span>
       <span class="child08">@nodename</span>
       <span class="child32">@nodename</span>
    </div>
    <div>
       <span class="child33">@nodename</span>
    </div>