There's a bug in the suggested output, as <img/>
elements must have alt
attributes in every version of HTML in which they are present.
Anyway the following does this but without those attributes that can be done from CSS instead (just to keep size down). Adding them back in if desired is trivial:
<xsl:template match="pics">
<table>
<xsl:apply-templates select="pic[position() mod 3 = 1]"/>
</table>
</xsl:template>
<xsl:template match="pic[position() mod 3 = 1]">
<tr>
<td>
<xsl:if test="2 > count(following-sibling::pic)">
<xsl:attribute name="colspan">
<xsl:value-of select="3 - count(following-sibling::pic)"/>
</xsl:attribute>
</xsl:if>
<img src="{.}" alt="" />
</td>
<xsl:apply-templates select="following-sibling::pic[3 > position()]" />
</tr>
</xsl:template>
<xsl:template match="pic">
<td><img src="{.}" alt=""/></td>
</xsl:template>
The above assumes you want the path from the file used directly, adding code to transform it in some way (say taking just the last part of the path using substring-after()
) isn't a difficult extension, assuming said transform isn't complicated itself.
Edit:
Myself and JohnB are going into further territory here, the above suffices to answer the original question.
Added to give a fuller answer to JohnB's question. The following is the equivalent code using for-each instead of apply-templates. In theory both a sequential and a state-machine base implementation of an XSLT processor should deal with this identically, though you may find differences in practice (if you told me they were different with a given processor I'd bet a small amount on it being slightly faster with sequential processing and slightly slower with state-machine processing, but I'd only bet a very small amount).
Note that we can't reuse the default template for pic. On the plus-side, if we have a different default template for pic elsewhere (if this were part of a much more complicated stylesheet), we don't need to be clever to differentiate between them, which is the main time that I personally would lean toward for-each.
<xsl:template match="pics">
<table>
<xsl:for-each select="pic[position() mod 3 = 1]">
<tr>
<td>
<xsl:if test="2 > count(following-sibling::pic)">
<xsl:attribute name="colspan">
<xsl:value-of select="3 - count(following-sibling::pic)"/>
</xsl:attribute>
</xsl:if>
<img src="{.}" alt="" />
</td>
<xsl:for-each select="following-sibling::pic[3 > position()]">
<td><img src="{.}" alt=""/></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>