XML to PDF? Oh, FOP It.
Pages: 1, 2
XSL + XML
By playing with the simple example, you would have noticed that it's very hard to produce the FO document by hand. It is cumbersome to change and by directly modifying the FO file, we are losing the benefit of content independence. So normally, you would instead use an XSLT stylesheet to transform your XML data into an XSL-FO file. You don't need to do this transformation explicitly or external to FOP. You can specify the stylesheet and the XML file to FOP and FOP can do the transformation by itself. Let's see an example of how to do this.
We'll abstract our data from the previous example into an XML file. So our XML data file looks like this:
<?xml version="1.0" encoding="UTF-8"?> <data> <name> Krusty the Clown </name> <description> This memo explains why Krusty the Clown is our best customer. We need to take good care of him from now onwards and make sure that there are always enough bananas for his pet monkey. </description> </data>
Save this file in the root FOP directory.
We now need to produce a stylesheet that will be used to transform this data file into an FO file. To look at the end result, download the final XSL file (also in the FOP.zip example file).
<?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">
As expected, the XSL document starts with the XML declaration, followed by the namespace declarations.
If you have worked with XSLT before, you will notice that now all we are trying to do is to match the tags that we expect in our XML file and replace/use them to transform into another XML file (our FO file). So the line above looks for and matches the
root tag and replaces it with the content that follows it. This content, as outlined below, is basically just the definition of our simple layout master set from our FO file described above.
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master master-name="simple" page-height="29.7cm" page-width="21cm" margin-top="1cm" margin-bottom="2cm" margin-left="2.5cm" margin-right="2.5cm"> <fo:region-body margin-top="3cm"/> <fo:region-before extent="3cm"/> <fo:region-after extent="1.5cm"/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="simple"> <fo:flow flow-name="xsl-region-body"> <xsl:apply-templates select="data"/> </fo:flow> </fo:page-sequence> </fo:root>
Replacing the data tags with the actual formatting information forms the next part of our XSL file.
<xsl:template match="data"> <fo:block> <xsl:apply-templates select="name"/> <xsl:apply-templates select="description"/> </fo:block> </xsl:template> <xsl:template match="name"> <fo:block font-size="18pt" font-family="sans-serif" line-height="24pt" space-after.optimum="15pt" background-color="blue" color="white" text-align="center" padding-top="3pt"> <xsl:value-of select="."/> </fo:block> </xsl:template> <xsl:template match="description"> <fo:block font-size="12pt" font-family="sans-serif" line-height="15pt" space-after.optimum="3pt" text-align="justify"> <xsl:value-of select="."/> </fo:block> </xsl:template> </xsl:stylesheet>
As you can see, the template matches are replaced by the corresponding formatting information, in terms of FO tags. The stylesheet is complete with the closing stylesheet tag. Save this file as krusty.xsl in the root FOP directory.
To run this and see how our efforts compare with the original, type in the following command in the root FOP directory:
fop -xml krusty.xml -xsl krusty.xsl -pdf krusty.pdf
Thus, you are specifying the input XSL and XML files along with the output PDF. When you open this PDF, you will see that the result is exactly the same as when we ran FOP with the FO file.
The advantage of the second approach should be clear. Our input XML data can be different in different circumstances. Today we are preparing the report for Krusty the Clown, tomorrow it might be Bart the Kid. Our data file will change, but not the stylesheet.
Conversion to AWT
There really is nothing great to do when deciding to output to different formats. FOP takes care of it internally. So to output to Java's Abstract Window Toolkit (AWT), all you need to do is:
fop -xml krusty.xml -xsl krusty.xsl -awt
That is, specify the output as AWT rather than PDF. FOP creates an AWT viewer for you, as shown in Figure 2.
Figure 2. AWT Viewer.
Whether as part of a Web or a desktop application, the steps to embed FOP into your own application are simple.
Driver driver = new Driver();
Set the type of rendering you want to do.
Set a logger to log to.
Set an input source.
Set an output stream to render to.
Finally, you are set to produce the output.
The above process is valid if you are specifying an input source as an FO file. If you specify XSL and XML files instead, you would change steps 4 and 6 as follows:
4. Set an Input Handler as an
InputHandler inputHandler = new XSLTInputHandler(xmlfile, xslfile);
6. Grab the parser out of this handler and render.
That's all there is to embedding FOP into an application. There is a complete example in the docs\examples\embedding directory that deals with embedding FOP in a servlet.
The FOP site is a good place for getting all of the documentation about FOP; however, this information is not always up to date.
The XSL specification maintained at W3C is a good place for getting information about all of your formatting objects.
O'Reilly's XML.com is good for general XML and XSL information.
Finally, a good introduction to FOP is available in this excerpt from the XML Bible.
Additional XML Resources
- What is XSL-FO?
- Printing from XML: An Introduction to XSL-FO
- Using XSL Formatting Objects
- Using XSL Formatting Objects, Part 2
- O'Reilly's XSL-FO - Making XML Look Good in Print
- A web service implementation of FOP
FOP is an open source tool for processing formatting objects. It renders these objects onto different media as per our requests. You can run FOP standalone, and as part of your application.
Vikram Goyal is the author of Pro Java ME MMAPI.
Return to ONJava.com.