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. |
| 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. 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. 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. |
| DevX is a division of Internet.com. © Copyright 2010 Internet.com. All Rights Reserved. Legal Notices |