Search code examples
xmlxsltxsl-fo

How to change page-sequence based on an item's value, but returning after second page-sequence is finished?


I am trying to setup a stylesheet that based on an XML value, will change the current page-sequence used. For example, for the below XML:

<items>
    <item order="1">item1</item>
    <item order="2">item2</item>
    <item order="3">item3</item>
    <item order="0">item4</item>
    <item order="4">item5</item>
</items>

The expected result would be:

 ....<fo:page-sequence master-reference="A4PageSeq">
      <fo:flow flow-name="body">
         <fo:block>item1</fo:block>
         <fo:block>item2</fo:block>
         <fo:block>item3</fo:block>
      </fo:flow>
   </fo:page-sequence>
<fo:page-sequence master-reference="A3PageSeq">
      <fo:flow flow-name="body">
         <fo:block>item4</fo:block>
      </fo:flow>
   </fo:page-sequence>
<fo:page-sequence master-reference="A4PageSeq">
      <fo:flow flow-name="body">
         <fo:block>item5</fo:block>
      </fo:flow>
   </fo:page-sequence>..

In the past, I used the code from below, as @order could take the values of '1' or '0'. However, this is no longer working for this new input. I was trying to use a variable, however, it ends up by adding everything under the same page-sequence.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="2.0">
    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>
    <xsl:template match="/">
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master master-name="A4Page" fo:page-width="8.5in" fo:page-height="11in">
                    <fo:region-body region-name="body" margin="0.7in"/>
                </fo:simple-page-master>
                <fo:simple-page-master master-name="A3Page" fo:page-width="11in" fo:page-height="17in">
                    <fo:region-body region-name="body" margin="0.7in"/>
                </fo:simple-page-master>
                <fo:page-sequence-master master-name="A4PageSeq">
                    <fo:repeatable-page-master-reference master-reference="A4Page"/>
                </fo:page-sequence-master>
                <fo:page-sequence-master master-name="A3PageSeq">
                    <fo:repeatable-page-master-reference master-reference="A3Page"/>
                </fo:page-sequence-master>
            </fo:layout-master-set>
            <xsl:apply-templates/>
        </fo:root>
    </xsl:template>
    
    
    <xsl:variable name="groupKey">
            <xsl:choose>
                <xsl:when test="/items/item/@order != 0">1</xsl:when>
                <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
    </xsl:variable>
    
    
    <xsl:template match="items">

        <xsl:for-each-group select="item" group-adjacent="@order">
            <xsl:choose>
                <xsl:when test="$groupKey != 0">
                    <fo:page-sequence master-reference="A4PageSeq">
                        <fo:flow flow-name="body">
                            <xsl:for-each select="current-group()">
                                <xsl:apply-templates select="."/>
                                <fo:block>This is A4 page seq</fo:block>
                            </xsl:for-each>
                        </fo:flow>
                    </fo:page-sequence>
                </xsl:when>
                <xsl:otherwise>
                    <fo:page-sequence master-reference="A3PageSeq">
                        <fo:flow flow-name="body">
                            <xsl:for-each select="current-group()">
                                <xsl:apply-templates select="."/>
                            </xsl:for-each>
                        </fo:flow>
                    </fo:page-sequence>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>
    
    <xsl:template match="item">
        <fo:block>
            <xsl:apply-templates/>
        </fo:block>
    </xsl:template>
</xsl:stylesheet>

How can I group after the @order attribute so that the page sequence update each time @order=0?


Solution

  • I am not sure I have understood the logic but it seems using

    <xsl:for-each-group select="item" group-adjacent="@order != 0">
      <xsl:choose>
        <xsl:when test="current-grouping-key()">
                        <fo:page-sequence master-reference="A4PageSeq">
                            <fo:flow flow-name="body">
                                <xsl:apply-templates select="current-group()"/>
                            </fo:flow>
                        </fo:page-sequence>
       </xsl:when>
       <xsl:otherwise>
         <fo:page-sequence master-reference="A3PageSeq">
          <fo:flow flow-name="body">
             <xsl:apply-templates select="current-group()"/>
          </fo:flow>
         </fo:page-sequence>
       </xsl:otherwise>
     </xsl:choose>
    </xsl:for-each-group>
    

    might do. If there can be adjacent @order=0 items and each needs its own sequence then inside the xsl:otherwise then use for-each inside or push the current-group() to a template setting up the sequence.