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.
You start the process by creating a TransformerFactory instance.
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;
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.
TransformerFactory tfactory = TransformerFactory.newInstance();
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:
You use the Transformer.Transform() method to transform the input XML document into the output .fo file.
Transformer transformer= tfactory.newTransformer (new StreamSource(getServletContext(). getResource(xslPath). toString()));
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.
transformer.transform(new StreamSource (getServletContext().getResource(xmlPath). toString()),new StreamResult(new FileOutputStream(filepath )));
The Transformer saves the output of the transformation (the .fo file) to the file represented by the filepath variable. That completes the first step.
String xslName = request.getParameter(“xsl”); String xmlName = request.getParameter(“xml”); String xslPath = xslName +”.xsl”; String xmlPath = xmlName +”.xml”;
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:
First get the FOP version with the getVersion() method.
import org.apache.fop.messaging.MessageHandler; import org.apache.fop.apps.*;
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.
String version = org.apache.fop.apps.Version.getVersion();
Before calling the createXMLReader() method set the System property.
XMLReaderFactory.createXMLReader() // org.xml.sax.helpers.XMLReaderFactory // relies on a System Property.
Next, instantiate a Driver object.
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.
org.apache.fop.apps.Driver driver = new org.apache.fop.apps.Driver();
The org.apache.fop package contains a PDF Renderer implementation and some standard element mappings.
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).
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”);
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.