19

I am using XSLT to generate PDF report. My requirements are to display page number in the format of Page N of N (e.g.Page 1 of 3) at the footer of the report. For static values it works fine and it repeats on each page. As total number of pages in the report are not known and it changes run time, so how I will accomplish this task.

My XSLT code snippet

<xsl:template name="footerall">
<xsl:variable name="maxwidth" select="7.07000" />
<fo:static-content flow-name="xsl-region-after">
<fo:block>
<xsl:variable name="tablewidth29" select="$maxwidth * 1.00000" />
<xsl:variable name="sumcolumnwidths29" select="0.04167 + 1.56250 + 0.04167" />
<xsl:variable name="factor29">
<xsl:choose>
<xsl:when
test="$sumcolumnwidths29 &gt; 0.00000 and $sumcolumnwidths29 &gt; $tablewidth29">
<xsl:value-of select="$tablewidth29 div $sumcolumnwidths29" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="1.000" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="defaultcolumns29" select="1" />
<xsl:variable name="defaultcolumnwidth29">
<xsl:choose>
<xsl:when test="$factor29 &lt; 1.000">
<xsl:value-of select="0.000" />
</xsl:when>
<xsl:when test="$defaultcolumns29 &gt; 0">
<xsl:value-of
select="($tablewidth29 - $sumcolumnwidths29) div $defaultcolumns29" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="0.000" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="columnwidth29_0" select="$defaultcolumnwidth29" />
<xsl:variable name="columnwidth29_1" select="1.56250 * $factor29" />
<fo:table width="{$tablewidth29}in" border-collapse="separate"
border-separation="0.04167in" color="black" display-align="center">
<fo:table-column column-width="{$columnwidth29_0}in" />
<fo:table-column column-width="{$columnwidth29_1}in" />
<fo:table-body>
<fo:table-row>
<fo:table-cell number-columns-spanned="2"
padding-top="0.00000in" padding-bottom="0.00000in" padding-left="0.00000in"
padding-right="0.00000in">
<fo:block padding-top="1pt" padding-bottom="1pt">
<fo:block text-align="center" space-before.optimum="-8pt">
<fo:leader leader-length="100%" leader-pattern="rule"
rule-thickness="1pt" color="black" />
</fo:block>
</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell
font-size="inherited-property-value(&apos;font-size&apos;) - 2pt"
text-align="left" padding-top="0.00000in" padding-bottom="0.00000in"
padding-left="0.00000in" padding-right="0.00000in">
<fo:block padding-top="1pt" padding-bottom="1pt">
<fo:inline font-family="Courier" font-size="10px">
<xsl:value-of select="$My XPath to varaible" />
</fo:inline>
<fo:inline font-family="Courier" font-size="10px">
<xsl:text> - </xsl:text>
<xsl:text>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</xsl:text>
<xsl:text>Page 1 of 1</xsl:text>
</fo:inline>
<fo:inline font-family="Courier" font-size="10px">
<xsl:value-of select="$My XPath to varaible" />
</fo:inline>
</fo:block>
</fo:table-cell>
<fo:table-cell
font-size="inherited-property-value(&apos;font-size&apos;) - 2pt"
text-align="right" padding-top="0.00000in" padding-bottom="0.00000in"
padding-left="0.00000in" padding-right="0.00000in">
<fo:block padding-top="1pt" padding-bottom="1pt" />
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
</fo:static-content>
</xsl:template>

I will replace the string (Page 1 of 1) by a variable but how to handle this.

Please help me.

glmxndr
  • 45,516
  • 29
  • 93
  • 118
naeemgik
  • 2,232
  • 4
  • 25
  • 47

2 Answers2

29

I solved my problem by following below instructions.

Put a formatting object with an id at the end of the area. You can then do a to the labeled block that appears on the last page of the document. Here's how the markup looks:

<fo:flow flow-name="xsl-region-body">
... Lots and lots of content here
<fo:block id="TheVeryLastPage"> </fo:block>
</fo:flow>

The code creates a block with an id of TheVeryLastPage (a value that's unlikely to be used by anyone), and now you can refer to that id to get the page number of the last page of the document. Here's how the content in the area should look:

<fo:block text-align="end">
Page <fo:page-number/> of 
<fo:page-number-citation 
ref-id="TheVeryLastPage"/>
</fo:block>

When FOP formats this markup, it generates something like "Page 2 of 5".

My reference URL is: http://www.ibm.com/developerworks/xml/tutorials/x-xslfo2/section4.html

naeemgik
  • 2,232
  • 4
  • 25
  • 47
  • 3
    A better solution without adding an empty block is the previous answer as long as you place the ID attribute referenced on an object that ends on the last page (like fo:flow in your example). That way you have fo:flow flow-name="xsl-region-body" id="document" and then you use fo:page-number-citation-last ref-id="document" – Kevin Brown Oct 10 '13 at 00:42
10

You should add an id attribute to your fo:page-sequence element, and then use a page-number-citation-last.

<fo:page-sequence id="my-sequence-id">
  ...
  <xsl:text>Page </xsl:text>
  <fo:page-number-citation />
  <xsl:text> of </xsl:text>
  <fo:page-number-citation-last page-citation-strategy="all" ref-id="my-sequence-id"/>
  ...
</fo:page-sequence>

See the specs: http://www.w3.org/TR/xslfo20/#fo_page-number-citation and http://www.w3.org/TR/xslfo20/#fo_page-number-citation-last

Vaidas
  • 1,494
  • 14
  • 21
glmxndr
  • 45,516
  • 29
  • 93
  • 118
  • 1
    Minor typo at the third line in the sample code. – masche Feb 17 '15 at 13:49
  • 2
    Page / for a working version. – Jan Aug 26 '15 at 12:38
  • 1
    This fails for multi region page sequence. it shows page number as below 1 of 4, 2 of 4, 3 of 4, 5 of 4, 6 of 6, 7 of 6, 8 of 8 – c.sankhala Jul 17 '20 at 12:38
  • 1
    Whit this i get the error `Invalid property encountered on "fo:page-number-citation-last": page-citation-strategy (No context info available)`. Any idea what to do? Without 'page-citation-strategy="all"' the error disappears, but then i get wrong total page number '1 of 1', '2 of to2', etc. – Cengiz Jan 13 '21 at 13:28