Linkwerk Logo

invitation2fo.xslt - Transforming XML to XSL-FO/PDF

Up · XHTML · PDF · WordML

If you've already read the description about how to transform invitation.xml to XHTML you won't be suprised about the generation of PDF. Although we can't generate PDF directly from XML, but have to use XSL-FO as an intermediate format, the process is very similar. Thanks to the fact that formatting XSL-FO to PDF is an automated process we can think of XML to PDF as XML to XSL-FO — we just need another software for the XSL-FO-to-PDF conversion.

Again you can follow my example on your own; the steps are a little bit different:

  1. Download the sample XML file invitation.xml

  2. Download the XSLT program invitation2fo.xslt (Download/View)

  3. The canonical way to continue is

    The latter step requires an XSL-FO formatter. A popular XSL-FO formatter is fop. Fop has a nice feature: Fop combines the above two steps in one. Therefore you can simply

  4. Transform and format the invitation.xml to PDF with fop:

    fop.sh -xml ../invitation.xml -xsl invitation2fo.xslt -pdf invitation.pdf

You should get a PDF file as the result of the transformation (invitation.pdf). In case you do not have a PDF viewer, here's my screenshot:

invitation.pdf

Let's take a look at the XSLT program.

The template for the root element invitation generates the XSL-FO structure, just as the XHTML version did. A fo:layout-master-set element defines a very simple page layout, size and margins. At <fo:page-sequence master-reference="one"> begins the body of the FO document. It contains the same generated text as the XHTML stylesheet and applies the templates for the other input elements. It's exactly what we've seen for XHTML, with the only difference of XSL-FO instead of XHTML markup.

<xsl:template match="invitation">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="one" page-height="15cm" page-width="21cm" margin-left="2cm" margin-right="2cm">
<fo:region-body margin-top="1cm" margin-bottom="1cm"></fo:region-body>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="one">
<fo:flow flow-name="xsl-region-body" font-size="14pt" line-height="18pt">
<xsl:apply-templates select="event"></xsl:apply-templates>
<fo:block text-align="justify" padding="2em" margin-left="0cm" margin-right="0cm" border-left="solid red 2em" border-right="solid red 2em">
I'd like to invite you to come to
<xslt:apply-templates xmlns:xslt="http://www.w3.org/1999/XSL/Transform" select="location"></xslt:apply-templates>
. The event takes place on
<xslt:apply-templates xmlns:xslt="http://www.w3.org/1999/XSL/Transform" select="date"></xslt:apply-templates>
at
<xslt:apply-templates xmlns:xslt="http://www.w3.org/1999/XSL/Transform" select="time"></xslt:apply-templates>
.
</fo:block>
<xslt:apply-templates xmlns:xslt="http://www.w3.org/1999/XSL/Transform" select="description|dresscode"></xslt:apply-templates>
<fo:block text-align="justify" background-color="#cccccc" color="#000000" padding="10pt" font-size="8pt" space-before.optimum="30pt">
Generated from XML with invitation2html.xslt. Copyright © Stefan Mintert, Linkwerk.com.
<fo:inline font-style="italic">
http://www.linkwerk.com/pub/xml/invitation/
</fo:inline>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>

Because we don't have specific elements for headings etc. in XSL-FO, the following template transforms events to blocks with some styling (centered, bold faced, colored, etc.):

<xsl:template match="event">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" text-align="center" font-size="24pt" font-weight="bold" background-color="#66AA66" color="white" padding="10pt" line-height="28pt">
<xsl:apply-templates></xsl:apply-templates>
</fo:block>
</xsl:template>

Inline elements are handled in a similar way. But since they are inline, they're not transformed to blocks, but to inlines. location, date and time are printed with bold face; emph is emphasised with italics:

<xslt:template xmlns:xslt="http://www.w3.org/1999/XSL/Transform" match="location | date | time">
<fo:inline xmlns:fo="http://www.w3.org/1999/XSL/Format" font-weight="bold">
<xslt:apply-templates></xslt:apply-templates>
</fo:inline>
</xslt:template>
<xslt:template xmlns:xslt="http://www.w3.org/1999/XSL/Transform" match="emph">
<fo:inline xmlns:fo="http://www.w3.org/1999/XSL/Format" font-style="italic">
<xslt:apply-templates></xslt:apply-templates>
</fo:inline>
</xslt:template>

description and dresscode become blocks with a certain styling and some generated text, which you've already seen in the XHTML version:

<xslt:template xmlns:xslt="http://www.w3.org/1999/XSL/Transform" match="description">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" text-align="left" padding-left="2em" padding-right="2em" padding-top="1em" margin-left="0cm" margin-right="0cm" border-left="solid white 2em" border-right="solid white 2em">
<fo:inline font-weight="bold">
What's up?
</fo:inline>
<xslt:apply-templates></xslt:apply-templates>
</fo:block>
</xslt:template>
<xslt:template xmlns:xslt="http://www.w3.org/1999/XSL/Transform" match="dresscode">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" text-align="left" padding-left="2em" padding-right="2em" padding-top="1em" margin-left="0cm" margin-right="0cm" border-left="solid white 2em" border-right="solid white 2em">
<fo:inline font-weight="bold">
What to wear?
</fo:inline>
<xslt:apply-templates></xslt:apply-templates>
</fo:block>
</xslt:template>

Last, but not least, the transformation of para: a left aligned block.

<xslt:template xmlns:xslt="http://www.w3.org/1999/XSL/Transform" match="para">
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" text-align="left">
<xslt:apply-templates></xslt:apply-templates>
</fo:block>
</xslt:template>

Apart from the more complex markup of XSL-FO compared to XHTML, I'm sure you agree that the production of PDF from XML is not harder than producing a web page — thanks to the universality of XML and XSLT.

© 2005, Stefan Mintert, All rights reserved