I want to turn this
Here a slightly shorter XSLT 1.0 version using following-sibling
and an empty notest as default stack value ( <xsl:param name="items" select="/@empty-node-set" />
).
But basically same as michael.hor257k solution.
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="item[1]" />
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:param name="items" select="/@empty-node-set" />
<xsl:variable name="stack" select="$items | ." />
<xsl:choose>
<xsl:when test="sum($stack/@columns) >= 12 or not(following-sibling::item)" >
<row>
<xsl:copy-of select="$stack"/>
</row>
<xsl:apply-templates select="following-sibling::item[1]" />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="following-sibling::item[1]">
<xsl:with-param name="items" select="$stack"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Using /@empty-node-set
as empty stack was from Best practice regarding empty node-set initialization:
... the expression "/@empty-node-set" which is guaranteed (for XML 1.0) to be empty because the root node can never have attribute nodes.
Here's an XSLT 2.0 solution:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="root">
<xsl:copy>
<!--
Group <item> elements, ending each group when the sum of the @columns
attribute of the current <item> element and the <item> elements that
precede it is divisible by 12.
-->
<xsl:for-each-group select="item" group-ending-with="
*[sum((
number(@columns),
for $c in preceding-sibling::item/@columns return number($c)
)) mod 12 eq 0]
">
<row>
<xsl:apply-templates select="current-group()"/>
</row>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<!-- Identity template -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Here's one way you could look at it:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:call-template name="aggregate">
<xsl:with-param name="items" select="item"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="aggregate">
<xsl:param name="items" select="/.."/>
<xsl:param name="i" select="1"/>
<xsl:variable name="stack-items" select="$items[position() <= $i]" />
<xsl:choose>
<xsl:when test="sum($stack-items/@columns) >= 12 or $i >= count($items)">
<row>
<xsl:copy-of select="$stack-items"/>
</row>
<xsl:if test="$i < count($items)">
<xsl:call-template name="aggregate">
<xsl:with-param name="items" select="$items[position() > $i]"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="aggregate">
<xsl:with-param name="items" select="$items"/>
<xsl:with-param name="i" select="$i + 1"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Do a search for sibling recursion for an alternative method.