How to insert page break in XML using XSLT

2.3k Views Asked by At

I am having trouble in producing a PDF document with a page break using XML and XLST stylesheet. This is existing code that I am trying to fix with little understanding of XML! This is my first time looking at it.

I have tried to use break-before="page" but with no luck.

This is the XSLT stylesheet:

 <xsl:template match="/">
   <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <fo:layout-master-set>
     <fo:page-sequence-master master-name="alternating">
      <fo:repeatable-page-master-alternatives maximum-repeats="no-limit">
        <fo:conditional-page-master-reference master-reference="lastsimpleA4" odd-or-even="odd"/>
        <fo:conditional-page-master-reference master-reference="lastsimpleA4"/>
        <fo:conditional-page-master-reference master-reference="lastsimpleA4" odd-or-even="even"/>
       </fo:repeatable-page-master-alternatives>
     </fo:page-sequence-master>
     <fo:simple-page-master master-name="lastsimpleA4" page-height="29.7cm" page-width="20.99cm" margin-right="1cm" margin-left="1cm" margin-bottom="1cm" margin-top="1cm">
          <fo:region-body margin-bottom="41mm"/>
          <fo:region-after extent="41mm"/>
      </fo:simple-page-master>
    </fo:layout-master-set>
  </fo:root>
 </xsl:template>

  <fo:page-sequence master-reference="alternating" initial-page-number="1">
      <fo:static-content flow-name="xsl-region-after">
        <fo:block>
          <xsl:apply-templates select="root/footer"/>
        </fo:block>
      </fo:static-content>
      <fo:flow flow-name="xsl-region-body">
        <xsl:apply-templates select="root/application"/>
      </fo:flow>
  </fo:page-sequence>

  <xsl:template match="block">
       <fo:block break-before="page">         
       </fo:block>       
   <xsl:apply-templates/>
  </xsl:template>
  <xsl:template match="/root/application">
      <xsl:apply-templates/>
  </xsl:template>
  <xsl:template match="/root/footer">
      <xsl:apply-templates/>
  </xsl:template>

This is a simple XML example:

<root>
    <application><block></block><data>TEST1</data></application>
    <footer><data>TEST2</data></footer>

    <application><block></block><data>TEST1</data></application>
    <footer><data>TEST2</data></footer>
</root>

Below is an example of the PDF being generated:

PDF example

I need a page break after the footer section ('TEST2' should only appear once and then break). Any help would be great. If you need any other information I'll provide it!

1

There are 1 best solutions below

0
XMLSchemer On

I agree with @MartinHonnen that you should "consider to show us a minimal but complete XML sample to demonstrate the problem, together with the minimal but complete and working XSLT," but I am posting this in the hopes that you can come to understand it, that it can contribute to solving your problem, and that you and anyone else new to XSL-FO can learn from the post.

Consider this stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fo="http://www.w3.org/1999/XSL/Format">

    <xsl:template match="/">
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>

                <fo:page-sequence-master master-name="alternating">
                    <fo:repeatable-page-master-alternatives maximum-repeats="no-limit">
                        <fo:conditional-page-master-reference master-reference="lastsimpleA4" odd-or-even="odd"/>
                        <fo:conditional-page-master-reference master-reference="lastsimpleA4"/>
                        <fo:conditional-page-master-reference master-reference="lastsimpleA4" odd-or-even="even"/>
                    </fo:repeatable-page-master-alternatives>
                </fo:page-sequence-master>

                <fo:simple-page-master master-name="lastsimpleA4" page-height="29.7cm" page-width="20.99cm" margin-right="1cm" margin-left="1cm" margin-bottom="1cm" margin-top="1cm">
                    <fo:region-body margin-bottom="41mm"/>
                    <fo:region-after extent="41mm"/>
                </fo:simple-page-master>

            </fo:layout-master-set>

            <xsl:for-each select="/root/page">
                <fo:page-sequence master-reference="alternating" format="1">
                    <fo:static-content flow-name="xsl-region-after">
                        <fo:retrieve-marker retrieve-class-name="footer" retrieve-position="first-starting-within-page"/>
                    </fo:static-content>

                    <fo:flow flow-name="xsl-region-body">
                        <fo:block>
                            <xsl:apply-templates select="application"/>
                        </fo:block>

                        <fo:block break-after="page">
                            <!-- dynamic footer content -->
                            <fo:marker marker-class-name="footer">
                                <fo:block>
                                    <xsl:apply-templates select="footer"/>
                                </fo:block>
                            </fo:marker>
                        </fo:block>
                    </fo:flow>
                </fo:page-sequence>
            </xsl:for-each>

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

</xsl:stylesheet>

And this XML...

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <page>
        <application>APP #1</application>
        <footer>FOOTER #1</footer>
    </page>

    <page>
        <application>APP #2</application>
        <footer>FOOTER #2</footer>
    </page>
</root>

Now I know you seem to be in charge of the XSL, but I don't know what control you have over your incoming data. Nevertheless, both the XML and XSL in this example ought to be relatively easily editable to meet your needs. The XML is an example of a setup where new pages are clearly demarcated by tags (in this example, <page> tags.

Notice the following:

  • We use something called <fo:marker> as a placeholder, setting it as we might set a variable when defining its value. In the example, this occurs whenever we match the tag that we want as its content (in this case, <footer>.)

  • Above it, in the <fo:static-content> definition that actually displays the footer, we use <fo:retrieve-marker> and its attributes to state that you want the marker named "footer"'s value (whatever it turns out to be) as your footer content.

  • We do the above on a page-by-page basis, each page determined by the presence of a <page> tag. Now your content doesn't have to be as explicit as this (it can be made to work without these <page> parent tags), and you just might have to do that if you have non-explicit data coming in that you can't control. But again, it is a simple matter to key page display start off of every <application> tag, for example. I just set it up this way for demonstration purposes.

  • And last but not least, as was the original question, the page break block is wrapped around the marker, and break-after is used with a value of page to achieve the desired breaking effects.

Skilled use of markers in FO is often crucial to advanced print formatting where display of dynamic content in certain document sections is concerned (tables are another area where these are very useful).

Please study the example and let me know if it was of help. I think this just might be where you were wanting to go with what you posted.