Wednesday, November 28, 2007

Reducing memory usage of FOP

Here is a straight forward example on using FOP to generate PDF reports:

......
<fo:page-sequence master-reference="simpleA4">
......
  <fo:flow flow-name="xsl-region-body">
    <xsl:apply-templates select="the-bean" />
  </fo:flow>
......
</fo:page-sequence>
......


The original data is in form of Java beans. A container contains multiple Java objects of "TheBean". The data is converted into XML by Castor. You can notice that the XSL file simply "apply-templates" based on the beans. FOP is smart enough to loop through all the beans of type "TheBean" to render the reports.

But this straight forward approach has a problem. FOP writes output and free up resources on a per-page-sequence basis. In the above example, the "apply-templates" tag is within a page sequence. This means FOP will loop through all the data before wriing the output PDF. In one particular test, in order to generate a report with 11MB of data in XML format (the PDF output is over 400 pages), FOP used up 1.3GB of memory.

To get around the problem, we could use a difference page sequence for each object:

......
<xsl:for-each select="the-bean">
  <fo:page-sequence master-reference="simpleA4">
......
    <fo:flow flow-name="xsl-region-body">
      <fo:block>
        <xsl:apply-templates select="." />
      </fo:block>
    </fo:flow>
......
  </fo:page-sequence>
</xsl:for-each>
......


Here, the for-each loop will iterate the beans one by one using different page sequence. Using this approach on the same 11MB XML file, the memory usage is reduced to below 48MB.

If each object needs to maintain its page number count, we could use a variable to name the "last page block" differently:

......
<xsl:for-each select="the-bean">
  <fo:page-sequence master-reference="simpleA4"
    initial-page-number="1"
    force-page-count="no-force">

    <xsl:variable name="count">
      <xsl:value-of select="position()"/>
    </xsl:variable>
......
      Page <fo:page-number/> of
      <fo:page-number-citation
      ref-id='last-page{$count}'/>
......
    <fo:flow flow-name="xsl-region-body">
      <fo:block>
        <xsl:apply-templates select="." />
      </fo:block>
      <fo:block id="last-page{$count}"/>
    </fo:flow>
......
  </fo:page-sequence>
</xsl:for-each>
......


Note the use of force-page-count="no-force". It is to prevent FOP from inserting a blank page between page sequences.

Sunday, November 25, 2007

Saturday, November 17, 2007

行呀行

之前話過每個禮拜都要出去行下運動下,不過上個星期偷懶…好在今朝戰勝睡魔。出發時天色陰暗,仲以為會落雨。點知愈行愈好天,仲有涼風,行得好鬼舒服!





Saturday, November 10, 2007

是日金句

十一月十一日,1111,四條光棍,係大陸的「光棍節」。大陸人好怕單身咩?!


剛見識到的「光棍節」名句: 『一個人吃飽,全家不餓』。 係單身的無奈,還是好處? =.=

Friday, November 9, 2007

因為豆漿濃啊

網上論壇新興的「無厘頭」回覆… 『因為豆漿濃啊!』

=.=...

Sunday, November 4, 2007

又係十下十下呀!

今晚又係同朋友打邊爐… 應該係連續五個 weekend 了… =__=...

不過今次有d唔同:第一次有七個人咁多一齊打,差d唔夠椅子添…真係唔好意思 :p 。其次係我第一次食大閘蟹!唔係講笑的。不過原來我屋企人唔食大閘蟹,因為個個都係寒底一事係堅嫁!我食完真係有d暈暈地… @.@… (不過亦都可能係我飲得太多 :P)

PS. 多謝大家俾面上來玩!