Click here to Skip to main content
6,629,377 members and growing! (19,467 online)
Email Password   helpLost your password?
Languages » Java » General     Beginner License: The Code Project Open License (CPOL)

PDF Generation using XSLFO and FOP

By Shyam S

An article describes how to create PDF document programmatically using XSLFO and FOP
Java, Windows, Java, Dev
Posted:26 Jun 2009
Views:5,064
Bookmarked:6 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
3 votes for this article.
Popularity: 2.23 Rating: 4.67 out of 5

1

2

3
1 vote, 33.3%
4
2 votes, 66.7%
5

Introduction

This article describes how to create a PDF document using XSLFO and Apache FOP.

Background

While developing a JSP based web application, I came through a requirement to create a PDF document and export it on a button click. There are lot of tutorials available for exporting to Excel, Word, etc. I decided to use XSLFO and FOP for creation of PDF document.

XSLFO is XSL Formatting Objects and can be used for formatting XML data. More information is available here and here.

Apache FOP (Formatting Objects Processor) is a Java application that reads a formatting objects tree and renders the resulting pages to a specified output (here, in our case, PDF). More information is available here.

How It Works

We have an XML that holds data and an XSLT that creates an XML containing formatting objects by taking data from the first XML. This resultant XML is de-serialized into Java objects. FOP creates a PDF file using these Java objects.

Hello World XSLFO

Here is a sample XML. This XML contains name and a list of friends with contact numbers.

<?xml version="1.0" encoding="iso-8859-1"?>
<root>
<name>shyam</name>
<friend>
	<name>Abc</name>
	<phNo>90909090909</phNo>
</friend>
<friend>
	<name>Xyz</name>
	<phNo>32323232323</phNo>
</friend>
</root>

Save it as Hello.xml.

Here is the sample xslfo style sheet. This first takes a name from the above XML. Then this xslt renders a table that contains details of friends available in the above XML.

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.1"
	xmlns:xsl=http://www.w3.org/1999/XSL/Transform 
		xmlns:fo="http://www.w3.org/1999/XSL/Format"
	exclude-result-prefixes="fo">
<xsl:template match="root">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:layout-master-set>
    <fo:simple-page-master master-name="my-page">
      <fo:region-body margin="1in"/>
    </fo:simple-page-master>
  </fo:layout-master-set>

  <fo:page-sequence master-reference="my-page">
    <fo:flow flow-name="xsl-region-body">
      <fo:block>Hello, <xsl:value-of select="name" />!</fo:block>
      <fo:block>
      	<fo:table>
      		 <fo:table-body>
      		 	<fo:table-row>
                	<fo:table-cell border="solid 1px black" 
			text-align="center" font-weight="bold">
                		<fo:block>
                    		No.
                  		</fo:block>
                	</fo:table-cell>
                	<fo:table-cell border="solid 1px black" 
			text-align="center" font-weight="bold">
                		<fo:block>
                    		Name
                  		</fo:block>
                	</fo:table-cell>
                	<fo:table-cell border="solid 1px black" 
			text-align="center" font-weight="bold">
                		<fo:block>
                    		Phone Number
                  		</fo:block>
                	</fo:table-cell>
                </fo:table-row>
                <xsl:for-each select="./friend">
                	<fo:table-row>
                	<fo:table-cell border="solid 1px black" text-align="center">
                		<fo:block>
                    		<xsl:value-of select="position()" />
                  		</fo:block>
                	</fo:table-cell>
                	<fo:table-cell border="solid 1px black" text-align="center">
                		<fo:block>
                    		<xsl:value-of select="name" />
                  		</fo:block>
                	</fo:table-cell>
                	<fo:table-cell border="solid 1px black" text-align="center">
                		<fo:block>
                    		<xsl:value-of select="phNo" />
                  		</fo:block>
                	</fo:table-cell>
                </fo:table-row>
                </xsl:for-each>
      		 </fo:table-body>
      	</fo:table>
      </fo:block>
    </fo:flow>
  </fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>

Save it as HelloWorld.xsl.

Java Code

Here is the code that creates PDF:

// the XSL FO file
File xsltfile = new File("HelloWorld.xsl");
// the XML file from which we take the name
StreamSource source = new StreamSource(new File("Hello.xml"));
// creation of transform source
StreamSource transformSource = new StreamSource(xsltfile);
// create an instance of fop factory
FopFactory fopFactory = FopFactory.newInstance();
// a user agent is needed for transformation
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// to store output
ByteArrayOutputStream outStream = new ByteArrayOutputStream();

Transformer xslfoTransformer;
try
{
	xslfoTransformer = getTransformer(transformSource);
	// Construct fop with desired output format
        Fop fop;
	try
	{
		fop = fopFactory.newFop
			(MimeConstants.MIME_PDF, foUserAgent, outStream);
		// Resulting SAX events (the generated FO) 
		// must be piped through to FOP
                Result res = new SAXResult(fop.getDefaultHandler());

		// Start XSLT transformation and FOP processing
		try
		{
		        // everything will happen here..
			xslfoTransformer.transform(source, res);
			// if you want to get the PDF bytes, use the following code
			//return outStream.toByteArray();

			// if you want to save PDF file use the following code
			/*File pdffile = new File("Result.pdf");
			OutputStream out = new java.io.FileOutputStream(pdffile);
                        out = new java.io.BufferedOutputStream(out);
                        FileOutputStream str = new FileOutputStream(pdffile);
                        str.write(outStream.toByteArray());
                        str.close();
                        out.close();*/

			// to write the content to out put stream
			byte[] pdfBytes = outStream.toByteArray();
                        response.setContentLength(pdfBytes.length);
                        response.setContentType("application/pdf");
                        response.addHeader("Content-Disposition", 
					"attachment;filename=pdffile.pdf");
                        response.getOutputStream().write(pdfBytes);
                        response.getOutputStream().flush();
		}
		catch (TransformerException e) {
			throw e;
		}
	}
	catch (FOPException e) {
		throw e;
	}
}
catch (TransformerConfigurationException e)
{
	throw e;
}
catch (TransformerFactoryConfigurationError e)
{
	throw e;
}

The 'getTransformer' function. I used xslt2 processor for advanced XSLT processing. A simple XSLT processor is enough here.

private Transformer getTransformer(StreamSource streamSource)
{
	// setup the xslt transformer
	net.sf.saxon.TransformerFactoryImpl impl = 
			new net.sf.saxon.TransformerFactoryImpl();

	try {
		return impl.newTransformer(streamSource);

	} catch (TransformerConfigurationException e) {
		e.printStackTrace();
	}
	return null;
}

Following is the list of the main namespaces used in the above code:

import java.io.File;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import java.io.ByteArrayOutputStream;
import javax.xml.transform.Transformer;
import javax.xml.transform.Result;

How It Works

First normal XML-XSLT transformation occurs which creates XSLFO XML. That is Hello.xml transformed by HelloWorld.xsl creates the following XML.

<?xml version="1.0" encoding="utf-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:layout-master-set>
    <fo:simple-page-master master-name="my-page">
      <fo:region-body margin="1in" />
    </fo:simple-page-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="my-page">
    <fo:flow flow-name="xsl-region-body">
      <fo:block>Hello, shyam!</fo:block>
      <fo:block>
        <fo:table>
          <fo:table-body>
            <fo:table-row>
              <fo:table-cell border="solid 1px black" 
			text-align="center" font-weight="bold">
                <fo:block>
                  No.
                </fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" 
			text-align="center" font-weight="bold">
                <fo:block>
                  Name
                </fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" 
			text-align="center" font-weight="bold">
                <fo:block>
                  Phone Number
                </fo:block>
              </fo:table-cell>
            </fo:table-row>
            <fo:table-row>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>1</fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>Abc</fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>90909090909</fo:block>
              </fo:table-cell>
            </fo:table-row>
            <fo:table-row>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>2</fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>Xyz</fo:block>
              </fo:table-cell>
              <fo:table-cell border="solid 1px black" text-align="center">
                <fo:block>32323232323</fo:block>
              </fo:table-cell>
            </fo:table-row>
          </fo:table-body>
        </fo:table>
      </fo:block>
    </fo:flow>
  </fo:page-sequence>
</fo:root>

This XML is a serialized FO objects tree. This XML is de-serialized to FO objects and by using these objects, FOP draws a PDF file. All these processes happen in the transform; function, we don't need to worry about it!!!

Points of Interest

FOP is a great utility available to us for the creation of PDF. I hope this bit of code will help you to create PDF programmatically. Thank you.

History

  • Initial version on 24 June 2009

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Shyam S


Member
I am a software architect in a reputed software firm. Mainly I am dealing with presentation layer like creation of re-usable framework, controls, pages etc.
Occupation: Architect
Location: India India

Other popular Java articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 4 of 4 (Total in Forum: 4) (Refresh)FirstPrevNext
Generalnot bad but... Pinmembercinamon3:50 27 Jun '09  
GeneralRe: not bad but... PinmemberTefik Becirovic10:12 27 Jun '09  
GeneralXSL-FO? PinmemberTefik Becirovic2:21 27 Jun '09  
GeneralRe: XSL-FO? PinmemberDon Kackman10:39 9 Jul '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 26 Jun 2009
Editor: Deeksha Shenoy
Copyright 2009 by Shyam S
Everything else Copyright © CodeProject, 1999-2009
Web22 | Advertise on the Code Project