Вместо того, чтобы перебирать все свои элементы и определять положение каждого из них, вместо этого по очереди, вы должны попытаться сопоставить соответствующий элемент в 1-й, 4-й, 7-й (и т. Д.) Позиции.
Например, предположим, что ваш входной XML был следующим
<brochures>
<brochure>Brochure 1</brochure>
<brochure>Brochure 2</brochure>
<brochure>Brochure 3</brochure>
<brochure>Brochure 4</brochure>
<brochure>Brochure 5</brochure>
</brochures>
Вы бы получили каждый третий элемент, как так
<xsl:apply-templates select="brochure[position() mod 3 = 1]" mode="first"/>
После размещения в таких строках вы можете просто выписать свой div, а затем сопоставить три строки, требуемые в этой группе.
<div class="row">
<xsl:apply-templates select="self::*|following-sibling::*[position() < 3]"/>
</div>
Вот полный XSLT. Обратите внимание, что я параметризовал количество строк на деление, чтобы сделать его более настраиваемым.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="rows" select="3" />
<xsl:template match="/brochures">
<section>
<xsl:apply-templates select="brochure[position() mod $rows = 1]" mode="first"/>
</section>
</xsl:template>
<xsl:template match="brochure" mode="first">
<div class="row">
<xsl:apply-templates select="self::*|following-sibling::*[position() < $rows]"/>
</div>
</xsl:template>
<xsl:template match="brochure">
<article class="brochure"/>
</xsl:template>
</xsl:stylesheet>
(Обратите внимание на использование режима для различения двух шаблонов, соответствующих элементу брошюра )
При применении к приведенному выше образцу XML возвращается следующее
<section>
<div class="row">
<article class="brochure" />
<article class="brochure" />
<article class="brochure" />
</div>
<div class="row">
<article class="brochure" />
<article class="brochure" />
</div>
</section>
Надеюсь, это даст вам достаточно информации, чтобы адаптировать ее к вашему собственному XML!