2
votes

I'm generating an invoice PDF and i want to have the block with the VAT Summary positioned at the bottom of the region-body

I read (almost) all the ibex and the more general xsl-fodocumentation and the closest i got was to learn how to absolutely position elements in the page;

But that does not suit my needs because i may have many lines with variable size and the absolutely-positioned element may overlap the lines.

I am using ibex xsl-fo generator.

EDIT: Some sample code

The full xsl-fo code can be found here

I put some sample code below so that one does not have to see the original xsl-fo that's 1200 lines long.

<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="/root">
        <fo:table>
            <fo:table-body>
                <fo:table-row>
                    <fo:table-cell>
                        <fo:block>
                            <xsl:value-of select="'I am up here'"/>
                        </fo:block>
                    </fo:table-cell>
                </fo:table-row>
                <!-- I'd like this table-row to be bottom aligned -->
                <fo:table-row>
                    <fo:table-cell>
                        <fo:block>
                            <xsl:value-of select="'I would like to be at the bottom of the region body'"/>
                        </fo:block>
                    </fo:table-cell>
                </fo:table-row>
            </fo:table-body>
        </fo:table>
    <xsl:template
</xsl:stylesheet>
3
Please share your generated FO.Navin Rawat

3 Answers

4
votes

The only way to do this in XSL FO is to use page templates for the last page and put that content in the region-after. There is no structure that yields a "rubber-banding" effect to push the content to the bottom, nor does float="bottom" exist (which would not work in your case anyway if it dod not fit, it would float to the bottom of the second page. You would use something like this from another project I have done.

 <fo:layout-master-set>
    <!-- ============== simple-page-master ============ -->
    <fo:simple-page-master master-name="simple-page-master.only" page-height="792pt" page-width="612pt">
      <fo:region-body margin-top="4.15in" margin-right="0.25in" margin-bottom="2.6in" margin-left="0.25in" />
      <fo:region-before extent="792pt" region-name="region-before.only"/>
    </fo:simple-page-master>
    <!-- ============== simple-page-master ============ -->
    <fo:simple-page-master master-name="simple-page-master.first" page-height="792pt" page-width="612pt">
      <fo:region-body margin-top="4.15in" margin-right="0.25in" margin-bottom="2.6in" margin-left="0.25in" />
      <fo:region-before extent="792pt" region-name="region-before.first"/>
    </fo:simple-page-master>
    <!-- ============== simple-page-master ============ -->
    <fo:simple-page-master master-name="simple-page-master.rest" page-height="792pt" page-width="612pt">
      <fo:region-body margin-top="0.8in" margin-right="0.25in" margin-bottom="0.64in" margin-left="0.25in" />
      <fo:region-before extent="792pt" region-name="region-before.rest"/>
    </fo:simple-page-master>
    <!-- ============== simple-page-master ============ -->
    <fo:simple-page-master master-name="simple-page-master.last" page-height="792pt" page-width="612pt">
      <fo:region-body margin-top="0.8in" margin-right="0.25in" margin-bottom="2.58in" margin-left="0.25in" />
      <fo:region-before extent="792pt" region-name="region-before.last"/>
    </fo:simple-page-master>
    <!-- ============== page-sequence-master ============ -->
  <fo:page-sequence-master master-name="page-sequence-master">
       <fo:repeatable-page-master-alternatives maximum-repeats="no-limit">
        <fo:conditional-page-master-reference master-reference="simple-page-master.last" blank-or-not-blank="blank" />
         <fo:conditional-page-master-reference master-reference="simple-page-master.only" page-position="only" />
        <fo:conditional-page-master-reference master-reference="simple-page-master.first" page-position="first" />
        <fo:conditional-page-master-reference master-reference="simple-page-master.last" page-position="last" />
        <fo:conditional-page-master-reference master-reference="simple-page-master.rest" page-position="rest" />
       </fo:repeatable-page-master-alternatives> 
  </fo:page-sequence-master>
  </fo:layout-master-set>

This creates templates for pages that are first, rest, last and a special one of only (where first is last). You then output that content you wish at the bottom of the page into the appropriate regions (both region-before.only and region-before.last).

The only caveat/trick is if you choose different sizes of page layout to accommodate the information you want at the bottom, then you should make sure the last few rows of the inside of your table are kept together to pull a few of those rows to the second page.

2
votes

You could have used an fo:footnote (see https://www.w3.org/TR/xsl11/#fo_footnote) either in the last table row or possibly immediately after the table.

If you use an empty fo:inline for the footnote marker, no marker will show in the fo:region-body, and you can put an fo:table for the VAT summary in the fo:footnote-body.

0
votes

I think the footnote it's a good solution as @Tony says in the reply above. For me this solution works:

Yes, for me this code works.

<fo:block>
    <fo:footnote>
        <fo:inline/>
        <fo:footnote-body>
            <fo:block keep-together.within-column="always">
                <fo:inline>
                    <xsl:text>Here is the text at the bottom</xsl:text>
                </fo:inline>
            </fo:block>
        </fo:footnote-body>
    </fo:footnote>
</fo:block>