Generate PDF Files Dynamically Using XSL-FO

his article shows you an easy way to generate PDF files dynamically for display in a browser by using an XSL vocabulary called XSL-FO (Extensible Stylesheet Language Formatting Objects). A special type of XSL-FO called Formatting Objects for PDF (FOP) works in conjunction with the Document Object Model (DOM) from within a Java Servlet and provides generic objects for transforming XML documents into professional-looking PDF files.

Before starting, here’s a brief introduction to XSL-FO and FOP. The W3C took two tracks with XSL. One track led to the commonly used XSLT (Extensible Stylesheet Language for Transformations) and the other, still in draft form, led to XSL-FO.

XSL-FO a transformation vocabulary used to describe how pages should look when presented to a reader. You use an XSL style sheet to transform an XML document in a semantic vocabulary into a new XML document in the XSL-FO presentational vocabulary. XSL-FO provides a more sophisticated visual layout model than does the combination of HTML and CSS, so it’s much more suitable for generating fine-grained presentational layout files.

One day perhaps, Web browsers will be able to display data marked up with XSL formatting objects directly, but for now, you must perform an additional processing step to transform the XSL-FO output document into some other, browser-displayable format, such as Adobe’s PDF. FOP is the world’s first print formatter driven by XSL formatting objects. It is a Java application that reads a formatting object tree and turns it into a PDF document or allows you to preview it directly on screen.

Generating PDF Files Dynamically.
In the sample code, I’ve used a Java Servlet to generate a PDF file and send it to a browser.

Author Note: An important point to remember when sending PDF content to the browser from a servlet is that you must set the MIME type header to application/pdf using the servlet’s setContentType() method.


Generating a PDF file is a two-step process. First, you build an intermediate .fo file using FOP and then generate the PDF from the generated .fo file. I’ve used the Java API for XML Processing (JAXP) transformer API to transform the XML into a .fo file using XSL-FO., and the org.apache.fop package within a Java Servlet to generate the PDF from the .fo file.

Author Note: Before you can run the sample code you need to put the Xalan, Xerces, fop, w3c.jar, sax.jar and Jdk1.3 packages into your classpath environment variable. .

Step 1: Transform XML Into a .fo File using XSL-FO:
Import the following JAXP packages to perform the transformation process.

   import javax.xml.transform.TransformerFactory;   import javax.xml.transform.Transformer;   import javax.xml.transform.stream.StreamSource;   import javax.xml.transform.stream.StreamResult;   import javax.xml.transform.TransformerException;   import  javax.xml.transform.      TransformerConfigurationException;
You start the process by creating a TransformerFactory instance.

   TransformerFactory tfactory =        TransformerFactory.newInstance();
Use the TransformerFactory.newTransformer() method to create an instance of the abstract Transformer class. The Transformer class transforms a source tree into a result tree.

You can use the Transformer instance to process XML from a variety of sources and write the transformation output to a variety of sinks. For example, the following code creates a Transformer object and loads it with an XSLT file:

   Transformer transformer=     tfactory.newTransformer     (new StreamSource(getServletContext().     getResource(xslPath).     toString()));
You use the Transformer.Transform() method to transform the input XML document into the output .fo file.

   transformer.transform(new StreamSource   (getServletContext().getResource(xmlPath).   toString()),new StreamResult(new    FileOutputStream(filepath )));
The Servlet constructs the file names for the xslPath and xmlPath variables from the Request object. The example passes the filenames and the servlet adds the extension.

   String xslName = request.getParameter(“xsl”);   String xmlName = request.getParameter(“xml”);   String xslPath = xslName +”.xsl”;   String xmlPath = xmlName +”.xml”;
The Transformer saves the output of the transformation (the .fo file) to the file represented by the filepath variable. That completes the first step.

Step 2: Generate a PDF File from a .fo File:
The second step is to create the PDF file from the .fo file-using FOP. Import the following FOP packages:

   import org.apache.fop.messaging.MessageHandler;   import org.apache.fop.apps.*;
First get the FOP version with the getVersion() method.

   String version = org.apache.fop.apps.Version.getVersion();
You need the version string because it’s one of the parameters you must pass to the render() method later on in the process. The sample code uses the driver.setRenderer() method.

   XMLReaderFactory.createXMLReader()    // org.xml.sax.helpers.XMLReaderFactory    // relies on a System Property.
Before calling the createXMLReader() method set the System property.

   System.setProperty(“org.xml.sax.driver”,       “org.apache.xerces.parsers.SAXParser”);
Next, instantiate a Driver object.

   org.apache.fop.apps.Driver driver = new org.apache.fop.apps.Driver();
After instantiating the Driver object, you call its methods to specify a Renderer to use and an OutputStream for the rendered result. You must supply the Renderer with a set of element mappings that specify how each element should be rendered to the output. You can do this by supplying either a preexisting ElementMappings object or by supplying the name of the class, in which case the Driver will instantiate the class. The advantage of using a class is that it enables you to specify the Renderer and ElementMapping(s) at runtime.

The org.apache.fop package contains a PDF Renderer implementation and some standard element mappings.

   driver.setRenderer      (“org.apache.fop.render.pdf.PDFRenderer”, version);   driver.addElementMapping      (“org.apache.fop.fo.StandardElementMapping”);   driver.addElementMapping      (“org.apache.fop.svg.SVGElementMapping”);   driver.addPropertyList      (“org.apache.fop.fo.StandardPropertyListMapping”);          driver.addPropertyList      (“org.apache.fop.svg.SVGPropertyListMapping”);
After initializing the Driver, call the buildFOTree() method. If you’re using DOM, you invoke the method using buildFOTree(Document). If you’re using the Simple API for XML (SAX), you invoke the method using the syntax buildFOTree(Parser, InputSource).

Figure 1. Generated Document: Here is a peek at the output PDF file from the sample code running in the free Adobe Acrobat Reader application.

You aren’t limited to opening the files directly from disk with the PDF reader. You can send the generated PDF file directly to most browsers, which use the Adobe reader as a helper file to open the PDF document. The generated documents are fully compatible with the PDF reader. Users can read, search, print and save the files. If you have the Adobe PDF reader installed on your computer, you can see an output example. If not, click the thumbnail image below to see a full-size image of the output.

The procedure shown in this article lets you generate PDF files from any type of XML document. You can add custom element mappings to improve your layout capabilities.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: