Xsl for-each: add code block every n lines?

I am trying to convert an xml bit that represents a gallery of images into an html table. (this should be done using html, not css). How to add line break </tr><tr> every six or so columns using xsl?

I have it:

 <xsl:for-each select="//email/gallery" > <td> <img> <xsl:attribute name="src"> <xsl:value-of select="gallery-image-location"/> </xsl:attribute> <xsl:attribute name="alt"> <xsl:value-of select="gallery-image-alt"/> </xsl:attribute> </img> </td> <xsl:if test="????"> </tr> <tr> </xsl:if> <xsl:for-each> 

In Javascript, I would do something like:

 for (i=0; i<gallery.length; i++) { htm += '<td><img src="' + gallery[i].gallery-image-location + '" alt="'+ gallery[i].gallery-image-alt +'"></td>'; if (i%6 == 5 && i != gallery.length-1) { htm += '</tr><tr>'; } } 
+4
source share
3 answers

How to add a line break every six or so columns with xsl?

In XSLT, you do not!

XSLT processes nodes, not tags.

Here is the XSLT path of positioning grouping :

 <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:template match="gallery[position() mod 6 = 1]"> <tr> <xsl:apply-templates mode="proc" select=".|following-sibling::gallery[not(position() > 5)]" /> </tr> </xsl:template> <xsl:template match="gallery" mode="proc"> <td> <img src="{gallery-image-location}" alt="{gallery-image-alt}"/> </td> </xsl:template> <xsl:template match="gallery[not(position() mod 6 = 1)]"/> </xsl:stylesheet> 

when this conversion is applied to the following XML document :

 <email> <gallery> <gallery-image-location>http://server/picts/1</gallery-image-location> <gallery-image-alt>Description 1</gallery-image-alt> </gallery> <gallery> <gallery-image-location>http://server/picts/2</gallery-image-location> <gallery-image-alt>Description 2</gallery-image-alt> </gallery> <gallery> <gallery-image-location>http://server/picts/3</gallery-image-location> <gallery-image-alt>Description 3</gallery-image-alt> </gallery> <gallery> <gallery-image-location>http://server/picts/41</gallery-image-location> <gallery-image-alt>Description 4</gallery-image-alt> </gallery> <gallery> <gallery-image-location>http://server/picts/5</gallery-image-location> <gallery-image-alt>Description 5</gallery-image-alt> </gallery> <gallery> <gallery-image-location>http://server/picts/6</gallery-image-location> <gallery-image-alt>Description 6</gallery-image-alt> </gallery> <gallery> <gallery-image-location>http://server/picts/7</gallery-image-location> <gallery-image-alt>Description 7</gallery-image-alt> </gallery> <gallery> <gallery-image-location>http://server/picts/8</gallery-image-location> <gallery-image-alt>Description 8</gallery-image-alt> </gallery> <gallery> <gallery-image-location>http://server/picts/9</gallery-image-location> <gallery-image-alt>Description 9</gallery-image-alt> </gallery> </email> 

required, the correct result is obtained :

 <tr> <td> <img src="http://server/picts/1" alt="Description 1"/> </td> <td> <img src="http://server/picts/2" alt="Description 2"/> </td> <td> <img src="http://server/picts/3" alt="Description 3"/> </td> <td> <img src="http://server/picts/41" alt="Description 4"/> </td> <td> <img src="http://server/picts/5" alt="Description 5"/> </td> <td> <img src="http://server/picts/6" alt="Description 6"/> </td> </tr> <tr> <td> <img src="http://server/picts/7" alt="Description 7"/> </td> <td> <img src="http://server/picts/8" alt="Description 8"/> </td> <td> <img src="http://server/picts/9" alt="Description 9"/> </td> </tr> 
+9
source

If you are using XSLT 2

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="email"> <xsl:for-each-group select="gallery" group-by="(position() - 1) idiv 6"> <tr> <xsl:apply-templates select="current-group()"/> </tr> </xsl:for-each-group> </xsl:template> <xsl:template match="gallery"> <td> <img src="{gallery-image-location}" alt="{gallery-image-alt}"/> </td> </xsl:template> </xsl:stylesheet> 
+5
source

First, assuming you are using XML or HTML output format, I donโ€™t think you can place unrivaled tags in your segment </tr><tr> . XSL (in these modes) doesnโ€™t just print the string output the way you would with your Javascript. (I could be wrong about that, though.)

What you do is closely related to paging; You can see the swap scripts.

Here's a (unverified) suggestion from me:

 <!-- For every sixth item, starting with the first... --> <xsl:for-each select="//email/gallery[position() mod 6 = 1]"> <tr> <!-- Get that item position... --> <xsl:variable name="thisPos" select="position()" /> <!-- and select the six (or less) items starting with that position. --> <xsl:for-each select="//email/gallery[position() &gt;= $thisPos and position() &lt; $thisPos + 6]"> <td><img> <xsl:attribute name="src"> <xsl:value-of select="gallery-image-location"/> </xsl:attribute> <xsl:attribute name="alt"> <xsl:value-of select="gallery-image-alt"/> </xsl:attribute> </img></td> </xsl:for-each> </tr> </xsl:for-each> 

Oh and IIRC, the inside of the loop can also be shortened:

 <td><img src="{gallery-image-location}" alt="{gallery-image-alt}" /></td> 

These braces will help maintain your sanity in long scenarios.

+1
source

All Articles