Monday, March 21, 2011

Generating PDF's using Apache FOP

I recently used FOP to generate PDF invoices. The site has done a great job in documenting it. But I feel that there is some confusion regarding where to start.

Here is a simplified tutorial for FOP.

1. Download Apache FOP binaries.

2. FOP uses XSL-FO as input format. So XSL-FO tutorial from w3schools xsl-fo is required reading.

3. Add the binaries in the java project. If you are using Maven it would be.

<dependency>
   <groupId>org.apache.xmlgraphics</groupId>
  <artifactId>fop</artifactId>
   <version>1.0</version>
</dependency>

4. Construct the following xsl-fo file.

<fo:page-sequence master-reference="invoiceContent">
<fo:flow flow-name="xsl-region-body">
<fo:table >
<fo:table-column column-width="3.5cm"/>
   <fo:table-column column-width="15cm"/>
    <fo:table-body>
      <fo:table-row>
       <fo:table-cell>
         <fo:block text-align="start" >
            <fo:inline><fo:external-graphic src="http://twitter.com/twitter.gif" /></fo:inline>
         </fo:block>
       </fo:table-cell>
       <fo:table-cell>
         <fo:block margin-top="5mm" text-align="start" font-family="sans-serif" font-weight="bold" font-size="14pt" color="#990000" >
            <fo:inline ><xsl:value-of select="fromCompany"/></fo:inline>
         </fo:block>
       </fo:table-cell>
      </fo:table-row>
    </fo:table-body>
   </fo:table>


5. Notice that in the above code we are using xsl transformations.

6. The following snippet of code would generate the PDF for you.

Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent,out);
 // Setup JAXP using identity transformer
 TransformerFactory factory = TransformerFactory.newInstance();
 Transformer transformer = factory.newTransformer(new StreamSource(
  xsltfile)); // identity transformer
 // Setup input stream
 Source src = invoiceViewVO.getSourceForProjectTeam();
 // Resulting SAX events (the generated FO) must be piped through to
 // FOP
 Result res = new SAXResult(fop.getDefaultHandler());
 // Start XSLT transformation and FOP processing
 transformer.transform(src, res);


In the above code snippets concentrate on the bolded text.
<xsl:value-of select="fromCompany"/>
The xsl-value would hunt for the element "fromCompany" in an xml input and replace it in the XSL before generating the PDF.

We can also provide this value from a Java object. The following line of code substitutes java object for a XML source.
Source src = invoiceViewVO.getSourceForProjectTeam();
In getSourceForProjectTeam() method we are returning a proxy which overides the SAX events for "value-of" and provides the requested element from java object.
For better understanding how this events are overrided
see the following files
1. AbstractObjectReader, 2, EasyGenerationContentHandlerProxy and 3. ExampleObj2PDF

I recommend that you go through the xsl-fo tutorial in details if you want the harness the full power of ApacheFO.

No comments:

Post a Comment