e-Zest members share technology ideas to foster digital transformation.

Integrating Apache FOP with Java project to generate .PDF files

Written by Debasmita Sahoo | Apr 11, 2012 1:08:30 PM

Apache FOP

FOP (Formatting Objects Processor) is from the apache group. It is said to be the print formatter driven by XSL formatting objects (XSL-FO). FOP can be downloaded from http://xmlgraphics.apache.org/fop/

Its ability to convert XSL files (*.fo) to PDF certainly makes it worth mention. Basically FOP is great for template based PDF generation. Simple programs can fetch data from any data source and populate such a template, and generate PDF’s on the fly !

XSL-FO (Extensible Stylesheet Language Formatting Objects)

XSL-FO is a language for formatting XML data for output to screen, paper or other media

Required Jars

  1. xml-apis.jar
  2. jaxb-api-2.2.3.jar
  3. fop-1.0.jar
  4. avalon-framework-4.1.3.jar
  5. commons-io-2.0.1.jar
  6. commons-logging-1.0.3.jar
  7. xmlgraphics-commons-1.4.jar

Steps to generate PDF

Step 1: Create the template(.xsl) for formatting the output in resource folder

Step 2: Convert the java object to XML

Step 3: call the transformer code to convert the xml source to pdf using the xsl template.

Example Code:

template.xsl

<?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"
                xmlns:barcode="org.krysalis.barcode4j.xalan.BarcodeExt" xmlns:common="http://exslt.org/common"
                xmlns:xalan="http://xml.apache.org" exclude-result-prefixes="barcode common xalan">
                <xsl:template match=" EmployeeData">
                                <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
                                                <fo:layout-master-set>
                                                                <fo:simple-page-master master-name="simple"
                                                                                page-height="20cm" page-width="10.5cm" margin-left="0.2cm"
                                                                                margin-right="0.2cm">
                                                                                <fo:region-body margin-top="0.5cm" />
                                                                </fo:simple-page-master>
                                                </fo:layout-master-set>
                                                <fo:page-sequence master-reference="simple">
                                                                <fo:flow flow-name="xsl-region-body">

                                                                                <fo:block font-family="Arial" font-size="7pt" font-weight="normal">
                                                                                                <fo:table>
                                                                                                                <fo:table-column column-number="1" column-width="3cm" />
                                                                                                                <fo:table-column column-number="2" column-width="2cm" />
                                                                                                                <fo:table-column column-number="3" column-width="5cm" />
                                                                                                                <fo:table-body  height="10cm">
                                                                                                                                <xsl:for-each select="./employeeList/employee">
                                                                                                                                                <fo:table-row border="solid 0.1mm black">

                                                                                                                                                                <fo:table-cell text-align="left">
                                                                                                                                                                                <fo:block>
                                                                                                                                                                                                <xsl:value-of select="name" />
                                                                                                                                                                                </fo:block>

                                                                                                                                                                </fo:table-cell>
                                                                                                                                                                <fo:table-cell text-align="center">
                                                                                                                                                                                <fo:block>
                                                                                                                                                                                                <xsl:value-of select="employeeId" />
                                                                                                                                                                                </fo:block>

                                                                                                                                                                </fo:table-cell>
                                                                                                                                                                <fo:table-cell text-align="left">
                                                                                                                                                                                <fo:block>
                                                                                                                                                                                                <xsl:value-of select="address" />
                                                                                                                                                                                </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>

EmployeeData.java

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

/**
 *
 */

/**
 * @author Debasmita.Sahoo
 *
 */
@XmlRootElement(name="EmployeeData")
public class EmployeeData {
	public EmployeeData () {
	}

	private List employeeList;

	@XmlElementWrapper(name = "employeeList")
	@XmlElement(name = "employee")
	public List getEmployeeList() {
		return employeeList;
	}
	public void setEemployeeList (List employeeList) {
		this.employeeList = employeeList;
	}

}

Employee.java

/**
 * @author Debasmita.Sahoo
 *
 */
public class Employee {
	private String name;
	private String employeeId;
	private String address;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	public String getEmployeeId() {
		return employeeId;
	}

	public void setEmployeeId(String employeeId) {
		this.employeeId = employeeId;
	}
	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

}

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
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;

public class PDFHandler {
	public static final String EXTENSION = ".pdf";
	public String PRESCRIPTION_URL = "template.xsl";

	public String createPDFFile(ByteArrayOutputStream xmlSource, String templateFilePath) throws IOException {
		File file = File.createTempFile("" + System.currentTimeMillis(), EXTENSION);
		URL url = new File(templateFilePath + PRESCRIPTION_URL).toURI().toURL();
		// creation of transform source
		StreamSource transformSource = new StreamSource(url.openStream());
		// 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 pdfoutStream = new ByteArrayOutputStream();
		StreamSource source = new StreamSource(new ByteArrayInputStream(xmlSource.toByteArray()));
		Transformer xslfoTransformer;
		try {
			TransformerFactory transfact = TransformerFactory.newInstance();

			xslfoTransformer = transfact.newTransformer(transformSource);
			// Construct fop with desired output format
			Fop fop;
			try {
				fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, pdfoutStream);
				// 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 save PDF file use the following code
					OutputStream out = new java.io.FileOutputStream(file);
					out = new java.io.BufferedOutputStream(out);
					FileOutputStream str = new FileOutputStream(file);
					str.write(pdfoutStream.toByteArray());
					str.close();
					out.close();

				} catch (TransformerException e) {
					e.printStackTrace();
				}
			} catch (FOPException e) {
				e.printStackTrace();
			}
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerFactoryConfigurationError e) {
			e.printStackTrace();
		}
		return file.getPath();
	}

	public ByteArrayOutputStream getXMLSource(EmployeeData data) throws Exception {
		JAXBContext context;

		ByteArrayOutputStream outStream = new ByteArrayOutputStream();

		try {
			context = JAXBContext.newInstance(EmployeeData.class);
			Marshaller m = context.createMarshaller();
			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			m.marshal(data, outStream);
		} catch (JAXBException e) {

			e.printStackTrace();
		}
		return outStream;

	}

}

Call the PDF handler Code

TestPDF.java

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
/**
 * @author Debasmita.Sahoo
 *
 */
public class TestPDF {
	public static void main(String args[]){
		System.out.println("Hi Testing");
		ArrayList employeeList = new ArrayList();
		String templateFilePath ="D:/Projects/Sample/pdftest/src/";

		Employee e1= new Employee();
		e1.setName("Debasmita1 Sahoo");
		e1.setEmployeeId("10001");
		e1.setAddress("Pune");
		employeeList.add(e1);

		Employee e2= new Employee();
		e2.setName("Debasmita2 Sahoo");
		e2.setEmployeeId("10002");
		e2.setAddress("Test");
		employeeList.add(e2);

		Employee e3= new Employee();
		e3.setName("Debasmita3 Sahoo");
		e3.setEmployeeId("10003");
		e3.setAddress("Mumbai");
		employeeList.add(e3);

		EmployeeData data = new EmployeeData();
		data.setEemployeeList(employeeList);
		PDFHandler handler = new PDFHandler();

		try {
			ByteArrayOutputStream streamSource = handler.getXMLSource(data);

			handler.createPDFFile(streamSource,templateFilePath);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}