Search code examples
xsltxsl-foapache-fop

XSL-FO: How can I control which simple-page-master is used for each element via attributes?


I would like to add the simple-page-master name to each element in xml that should be used for that element. Consecutive elements with the same simple page master should be rendered consecutively. An element that has a different simple page master as attribute should start on a new page.

Each element should be responsible for its simple page master.

According to Need to dynamically change the simple-page-master's master-name I've already tried

...
<xsl:apply-templates select="*" mode="pagemasterTemplate"/>

</fo:root>
    </xsl:template>   

    <xsl:template match="element" mode="pagemasterTemplate">
        <xsl:for-each-group select="*" group-adjacent="pagemaster">
            <fo:page-sequence>
                <xsl:attribute name="master-reference"><xsl:value-of select ="pagemaster"/></xsl:attribute>
                <fo:flow flow-name="xsl-region-body">
                    <xsl:for-each select="current-group()">
                       <xsl:apply-templates select="."/>
                    </xsl:for-each>
                </fo:flow>
            </fo:page-sequence>
      </xsl:for-each-group>
    </xsl:template>

but my XML elements nest across multiple hierarchy levels and I don't get the depth I need.

These are my examples simple-page master

<fo:simple-page-master master-name="RED-PAGE">
    <fo:region-body backgound-color="red"/>
</fo:simple-page-master>

<fo:simple-page-master master-name="BLUE-PAGE">
    <fo:region-body backgound-color="blue"/>
</fo:simple-page-master>

<fo:simple-page-master master-name="YELLOW-PAGE">
    <fo:region-body backgound-color="yellow"/>
</fo:simple-page-master>

Example XML

<root>
  <report>
    <reportelements>
        <section name="sec 1">
            <pagemaster>RED-PAGE</pagemaster>
            <reportelements>
                <chapter name="cha 1.1">
                    <pagemaster>RED-PAGE</pagemaster>
                    <reportelements>
                        <paragraph name="par 1.1.1">
                            <reportelements/>
                            <pagemaster>RED-PAGE</pagemaster>
                        </paragraph>
                    </reportelements>
                </chapter>
            </reportelements>
        </section>
        <section name="sec 2">
            <pagemaster>BLUE-PAGE</pagemaster>
            <reportelements>
                <chapter name="cha 2.1">
                    <pagemaster>YELLOW-PAGE</pagemaster>
                    <reportelements>
                        <picture name="pic 2.1.1">
                            <reportelements/>
                            <pagemaster>YELLOW-PAGE</pagemaster>
                        </picture>
                    </reportelements>
                </chapter>
            </reportelements>
        </section>
    </reportelements>
  </report>
</root>

What i want is an Output that looks like this:

|‾‾‾‾‾‾‾‾‾‾‾‾‾‾|
|   RED-PAGE   | 
|   sec 1      |
|   cha 1.1    |
|   par 1.1.1  |
|              |
|              |
|              |
 ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|‾‾‾‾‾‾‾‾‾‾‾‾‾‾|
|   BLUE-PAGE  | 
|   sec 2      |
|              |
|              |
|              |
|              |
|              |
 ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
|‾‾‾‾‾‾‾‾‾‾‾‾‾‾|
|  YELLOW-PAGE | 
|   cha 2.1    |
|   pic 2.1.1  |
|              |
|              |
|              |
|              |
 ‾‾‾‾‾‾‾‾‾‾‾‾‾‾

Solution

  • If you simply change <xsl:apply-templates select="*" mode="pagemasterTemplate"/> to

    <xsl:for-each-group select=".//element" group-adjacent="pagemaster">
               <fo:page-sequence master-reference="{current-grouping-key()}">
                    <fo:flow flow-name="xsl-region-body">
                        <xsl:apply-templates select="current-group()"/>
                    </fo:flow>
                </fo:page-sequence>
    </xsl:for-each-group>
    

    and then set up an

    <xsl:template match="element">
      <fo:block>
        <fo:block><xsl:value-of select="@name"/></fo:block>
      </fo:block>
    </xsl:template>
    

    then I think you should get the "page" structure you want, I am not sure which content needs to be output and whether it needs to preserve some nesting, the above would somehow flatten the nested input to some flat output