Practical example using FOP for PDF generation (updated)

The FOP API has changed so I had to update the code in this post. The code is compatible with the latest FOP jars available at the time of writing.

Here is a practical example using FOP for PDF generation.Click on the image above to enlarge it and view the output of the program.

Code for ExampleFO2PDF follows:


package com.mattiz.fop;

//Java
import java.io.File;
import java.io.OutputStream;

//JAXP
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.sax.SAXResult;

//FOP
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;

/**
 * This class demonstrates the conversion of an XML file to PDF using JAXP
 * (XSLT) and FOP (XSL-FO).
 */
public class ExampleFO2PDF {

	/**
	 * Main method.
	 *
	 * @param args
	 *            command-line arguments
	 */
	public static void main(String[] args) {
		try {
			System.out.println("FOP ExampleXML2PDF\n");
			System.out.println("Preparing...");

			// Setup directories
			File baseDir = new File(".");
			File outDir = new File(baseDir, "out");
			outDir.mkdirs();

			// Setup input and output files
			File xmlfile = new File(baseDir, "xml/xml/test.xml");
			File xsltfile = new File(baseDir, "xml/xslt/test.xsl");
			File pdffile = new File(outDir, "ResultXML2PDF.pdf");

			System.out.println("Input: XML (" + xmlfile + ")");
			System.out.println("Stylesheet: " + xsltfile);
			System.out.println("Output: PDF (" + pdffile + ")");
			System.out.println();
			System.out.println("Transforming...");

			// configure fopFactory as desired
			FopFactory fopFactory = FopFactory.newInstance();

			FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
			// configure foUserAgent as desired

			// Setup output
			OutputStream out = new java.io.FileOutputStream(pdffile);
			out = new java.io.BufferedOutputStream(out);

			try {
				// Construct fop with desired output format
				Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF,
						foUserAgent, out);

				// Setup XSLT
				TransformerFactory factory = TransformerFactory.newInstance();
				Transformer transformer = factory
						.newTransformer(new StreamSource(xsltfile));

				// Set the value of a <param> in the stylesheet
				transformer.setParameter("versionParam", "2.0");

				// Setup input for XSLT transformation
				Source src = new StreamSource(xmlfile);

				// 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);
			} finally {
				out.close();
			}

			System.out.println("Success!");
		} catch (Exception e) {
			System.out.print("ERROR!!");
			e.printStackTrace(System.err);
			System.exit(-1);
		}
	}
}

Create a web project and put all the jars in the FOP download on the classpath.

Put the following xml and xsl files in the appropriate folder:

test.xsl


<?xml version="1.0" encoding="UTF-8"?>
<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="/">
		<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
			<fo:layout-master-set>
				<fo:simple-page-master master-name="simple"
					page-height="8.5in" page-width="11in" margin-top=".5in"
					margin-bottom=".5in" margin-left=".5in" margin-right=".5in">
					<fo:region-body margin-top="2cm" margin-bottom="2cm" />
					<fo:region-before extent="2cm" overflow="hidden" />
					<fo:region-after extent="1cm" overflow="hidden" />
				</fo:simple-page-master>
			</fo:layout-master-set>
			<fo:page-sequence master-reference="simple"
				initial-page-number="1">
				<fo:static-content flow-name="xsl-region-before">
					<fo:block font-size="13.0pt" font-family="serif"
						padding-after="2.0pt" space-before="4.0pt" text-align="center"
						border-bottom-style="solid" border-bottom-width="1.0pt">
						<xsl:text>Worth of a Man</xsl:text>
					</fo:block>
				</fo:static-content>
				<fo:static-content flow-name="xsl-region-after">
					<fo:block font-size="12.0pt" font-family="sans-serif"
						padding-after="2.0pt" space-before="2.0pt" text-align="center"
						border-top-style="solid" border-bottom-width="1.0pt">
						<xsl:text>Page</xsl:text>
						<fo:page-number />
					</fo:block>
				</fo:static-content>
				<fo:flow flow-name="xsl-region-body">
					<xsl:apply-templates select="data" />
				</fo:flow>
			</fo:page-sequence>
		</fo:root>
	</xsl:template>
	<xsl:template match="data">
		<fo:block text-align="center">
			<fo:table table-layout="fixed" width="100%">
				<fo:table-column column-width="3in" />
				<fo:table-column column-width="2in" />
				<fo:table-column column-width="1in" />
				<fo:table-body>
					<fo:table-row keep-together.within-page="always">
						<fo:table-cell>
							<fo:block font-size="10pt" font-family="sans-serif"
								background-color="grey" color="white" text-align="left"
								padding-top="3pt">
								Field
</fo:block>
						</fo:table-cell>
						<fo:table-cell>
							<fo:block font-size="10pt" font-family="sans-serif"
								background-color="grey" color="white" text-align="left"
								padding-top="3pt">
								Data Entered
</fo:block>
						</fo:table-cell>
					</fo:table-row>
				</fo:table-body>
			</fo:table>
			<fo:table table-layout="fixed" width="100%">
				<fo:table-column column-width="3in" />
				<fo:table-column column-width="2in" />
				<fo:table-column column-width="1in" />
				<fo:table-body>
					<fo:table-row keep-together.within-page="always">
						<fo:table-cell>
							<xsl:apply-templates select="field" />
						</fo:table-cell>
						<fo:table-cell>
							<xsl:apply-templates select="data-entered" />
						</fo:table-cell>
					</fo:table-row>
				</fo:table-body>
			</fo:table>
			<fo:table table-layout="fixed" width="100%">
				<fo:table-column column-width="4.2in" />
				<fo:table-column column-width="2in" />
				<fo:table-column column-width="2in" />
				<fo:table-body>
					<fo:table-row keep-together.within-page="always">
						<fo:table-cell padding="2pt" border="1pt solid black">
							<fo:block font-size="10pt" font-family="sans-serif"
								space-after.optimum="1pt" background-color="red" color="white"
								text-align="left" padding-top="3pt">
								Measure
</fo:block>
						</fo:table-cell>
						<fo:table-cell padding="2pt" border="1pt solid black">
							<fo:block font-size="10pt" font-family="sans-serif"
								space-after.optimum="1pt" background-color="red" color="white"
								text-align="left" padding-top="3pt">
								Category
</fo:block>
						</fo:table-cell>
					</fo:table-row>
				</fo:table-body>
			</fo:table>
			<fo:table table-layout="fixed" width="100%">
				<fo:table-column column-width="4.2in" />
				<fo:table-column column-width="2in" />
				<fo:table-column column-width="2in" />
				<fo:table-body>
					<fo:table-row keep-together.within-page="always">
						<fo:table-cell padding="2pt" border="1pt solid black">
							<xsl:apply-templates select="measure" />
						</fo:table-cell>
						<fo:table-cell padding="2pt" border="1pt solid black">
							<xsl:apply-templates select="category" />
						</fo:table-cell>
					</fo:table-row>
				</fo:table-body>
			</fo:table>
		</fo:block>
	</xsl:template>
	<xsl:template match="field">
		<fo:block font-size="9pt" font-family="sans-serif"
			space-after.optimum="1pt" text-align="justify">
			<xsl:value-of select="." />
		</fo:block>
	</xsl:template>
	<xsl:template match="data-entered">
		<fo:block font-size="9pt" font-family="sans-serif"
			space-after.optimum="1pt" text-align="justify">
			<xsl:value-of select="." />
		</fo:block>
	</xsl:template>
	<xsl:template match="measure">
		<fo:block font-size="9pt" font-family="sans-serif"
			space-after.optimum="1pt" text-align="justify">
			<xsl:value-of select="." />
		</fo:block>
	</xsl:template>
	<xsl:template match="category">
		<fo:block font-size="9pt" font-family="sans-serif"
			space-after.optimum="1pt" text-align="justify">
			<xsl:value-of select="." />
		</fo:block>
	</xsl:template>
</xsl:stylesheet>

test.xml


<?xml version="1.0" encoding="UTF-8"?>
<data>
	<field>First Name</field>
	<data-entered>Jock</data-entered>
	<field>Second Name</field>
	<data-entered>Hoffman</data-entered>
	<field>Middle Name</field>
	<data-entered>Luther</data-entered>
	<field>Address1</field>
	<data-entered>Rose Villa</data-entered>
	<field>Address2</field>
	<data-entered>Picadilly</data-entered>
	<field>City</field>
	<data-entered>London</data-entered>
	<field>Date Of Joining</field>
	<data-entered>6/10/2005</data-entered>
	<field>Date of Birth</field>
	<data-entered>01-01-1971</data-entered>
	<field>Sex</field>
	<data-entered>Male</data-entered>
	<field>Marital Status</field>
	<data-entered>Unmarried</data-entered>
	<field>Name of Spouse</field>
	<data-entered>Not applicable</data-entered>
	<field>Credit card Number</field>
	<data-entered>01-03222-32</data-entered>
	<field>Land Phone</field>
	<data-entered>1234567890</data-entered>
	<field>Mobile Phone</field>
	<data-entered>Not Applicable</data-entered>
	<field>Education</field>
	<data-entered>Post graduate</data-entered>
	<field>Passport Number</field>
	<data-entered>1212</data-entered>
	<field>Date of Issue</field>
	<data-entered>08-08-2004</data-entered>
	<field>Date of Expiry</field>
	<data-entered>08-09-2008</data-entered>
	<measure>
		Overall bright person with a sunny disposition and few
		prejudices
</measure>
	<category>
		An asset to our company and we are sure he will take our company
		to new heights and a prosperous future
</category>
</data>

Run the ExampleFO2PDF as a standalone application.

About cuppajavamattiz
Matty Jacob - Avid technical blogger with interests in J2EE, Web Application Servers, Web frameworks, Open source libraries, Relational Databases, Web Services, Source control repositories, ETL, IDE Tools and related technologies.

Comments are closed.

%d bloggers like this: