简体   繁体   中英

xsl for-each: add code block every n rows?

I am trying to transform a bit of xml which represents an image gallery into an html table. (it must be done with html and not with css). How do I add the row break </tr><tr> every six or so columns with xsl?

I have this:

<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>';
    }
}

How do I add the row break every six or so columns with xsl?

In XSLT you don't!

XSLT processes nodes , not tags.

Here is the XSLT way of positional 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 transformation is applied on 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>

the wanted, correct result is produced :

<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>

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>

First, assuming that you are using an output format of XML or HTML, I don't think you can place unmatched tags as your are with the </tr><tr> segment. XSL (in these modes) doesn't just produce string output the way you would with your Javascript. (I could be wrong about this though.)

What you're doing there is closely related to paging; you might look at paging scripts.

Here's an (untested) 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's 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 interior of the loop can be shortened a little bit too:

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

Those curly braces will help save your sanity on long scripts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM