Java : Reporting in Java using XSL-FO

This page last changed on Feb 22, 2006 by Kees de Kooter

Not really satisfied with the available reporting solution for Java I decided to brew my own solution. It consists of the following layers:

  1. Domain objects (populated using Hibernate)
  2. A Velocity template for generating the xml
  3. An XSL template for generating the XSL-FO
  4. The Apache FOP renderer for generating the PDF

The domain objects are java beans with getter methods for all properties. Velocity can interpret the standard ${} markup . All variable placeholders are replaced with bean property values. The variables can contain members of members. This is the Velocity template:

<?xml version="1.0" encoding="UTF-8"?>
   <!-- Template for rendering timesheet xml report -->
   #foreach($activity in ${timeSheet.activities})

The java code triggering Velocity looks like this (exception handling omitted):

VelocityContext velocityContext = new VelocityContext();
Template template = Velocity
StringWriter stringWriter = new StringWriter();
velocityContext.put("timeSheet", dataSource);
velocityContext.put("dateFormatter", new Dates());
template.merge(velocityContext, stringWriter);

Here is a snippet of the XSL file for transforming this xml report to the XSL-FO:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" 
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <xsl:decimal-format decimal-separator="," grouping-separator="." name="nl"/>
   <xsl:template match="/">
            <fo:simple-page-master margin="1.5cm" page-width="21cm" page-height="29.7cm" master-name="first">
         <fo:page-sequence master-reference="first">
            <fo:flow flow-name="xsl-region-body" font-family="Helvetica" font-size="10pt">
                  <fo:external-graphic src=""/>
               <fo:block font-weight="bold" font-size="11pt" padding-before="1cm" padding-after="0.2cm">
                  <xsl:value-of select="/report/customer"/>
               <fo:block font-weight="bold" font-size="11pt" padding-before="0.2cm" padding-after="0.2cm">
                  <xsl:value-of select="/report/title"/>
               <fo:block padding-before="0.6cm" padding-after="0.2cm">
                  <xsl:text>Medewerker: </xsl:text><xsl:value-of select="/report/employee"/>
               <xsl:apply-templates select="/report/activities"/>

Next the the xml is transformed to XSL-FO and rendered by FOP. The resulting byte array can either be piped to a file or sent to the browser.

private byte[] renderTimeSheet(Integer id) {
    String xml = timeSheetDao.findByIdAsXml(id);
    // Transform to fo and subsequently pdf
    Driver driver = new Driver();
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
        // Setup JAXP using identity transformer
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer(new StreamSource(
        // Setup input stream
        Source source = new StreamSource(new StringReader(xml));
        // Resulting SAX events (the generated FO) must be piped through to
        // FOP
        Result result = new SAXResult(driver.getContentHandler());
        // Start XSLT transformation and FOP processing
        transformer.transform(source, result);
    } catch (Exception e) {
    return outputStream.toByteArray();

And all of this coded by hand, no graphical tools used whatsoever. The toughest job was coding the FO. There is a very extensive W3C specification available (, but no comprehensive 'cookbook' manual, nor GUI tools. So every tiny little layout aspect that I wanted to render took a lot of research time.

Another issue is the performance of FOP. It is quite slow. There is a version coming up however, promising to be much faster: