The watered-down version of the problem I'm having is this. For an XML file like:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item cols="1">Item 1</item>
<item cols="1">Item 2</item>
<item cols="1">Item 3</item>
<item cols="1">Item 4</item>
<item cols="1">Item 5</item>
<item cols="1">Item 6</item>
<item cols="1">Item 7</item>
<item cols="1">Item 8</item>
<item cols="1">Item 9</item>
<item cols="2">Item 10</item>
<item cols="1">Item 11</item>
<item cols="1">Item 12</item>
<item cols="1">Item 13</item>
<item cols="1">Item 14</item>
<item cols="1">Item 15</item>
<item cols="1">Item 16</item>
<item cols="1">Item 17</item>
<item cols="1">Item 18</item>
</items>
I need to be able to print the 'item's that have 'cols=1' in a single column page layout, and the 'item's that have 'cols=2' in a double column page layout. The ordering of the items has to be preserved. All contiguous 'item's with the same value of @cols needs to appear as a continuous flow. Any time the @cols value changes, I need to break to a new page and change the layout as necessary.
I'm doing something like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="one-column-page-master">
<fo:region-body margin-top="3cm" region-name="body" column-count="1"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="two-column-page-master">
<fo:region-body margin-top="3cm" region-name="body" column-count="2"/>
<fo:region-before region-name="header" extent="2cm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="one-column-page">
<fo:repeatable-page-master-reference master-reference="one-column-page-master"/>
</fo:page-sequence-master>
<fo:page-sequence-master master-name="two-column-page">
<fo:repeatable-page-master-reference master-reference="two-column-page-master"/>
</fo:page-sequence-master>
</fo:layout-master-set>
<xsl:for-each select="//item">
<xsl:choose>
<xsl:when test="@cols = preceding-sibling::item[1]/@cols">
<!--cols value hasn't changed, don't create a new page-sequence-->
<!--But we cannot directly add fo:flow as the child of fo:root! -->
<xsl:call-template name="itemtemplate"/>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="@cols = 1">
<fo:page-sequence master-reference="one-column-page">
<xsl:call-template name="itemtemplate"/>
</fo:page-sequence>
</xsl:when>
<xsl:otherwise>
<fo:page-sequence master-reference="two-column-page">
<xsl:call-template name="itemtemplate"/>
</fo:page-sequence>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</fo:root>
</xsl:template>
<xsl:template name="itemtemplate">
<fo:flow flow-name="body">
<fo:block margin-bottom="5cm">
<xsl:apply-templates/>
</fo:block>
</fo:flow>
</xsl:template>
</xsl:stylesheet>
But of course, the problem is that I either have to include a <fo:page-sequence..> in my stylesheet, or not, I cannot 'dynamically' decide to put in one based on note attributes. (Unless I have a meta program that creates the stylesheet dynamically in the first place, but I was hoping to accomplish this using just plain static stylesheets).
Here is an XSLT 2.0 solution that uses
xsl:for-each-group
withgroup-adjacent
:Output:
You want finally group adjacent
item
elements according the value of@cols
in the proper fo page sequence.XSLT 1.0 instructions like
xsl:choose
andxsl:for-each
are not really suitable to this task. I think you have to change your mind a bit. Here an example of how to achieve the result grouping by recursion.It's not really clear what you want to include inside each flow element, then I decided to show you just how to group elements; then, you can adapt the code to your requirements.
[XSLT 1.0]
When applied to the sample input provided in the question produces:
@empo: Excellent! So the basic approach is to handle the critical 'item's (where @cols changes) in the main loop, and handle the adjacent nodes to these in the recursive template call. I've used your approach and made a few changes to make the code simpler, but this works great!