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:
Download the sample XML file invitation.xml
Download the XSLT program invitation2fo.xslt
(Download/View)
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
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:

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">
<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 event
s to block
s 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"></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 inline
s. 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"></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"></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>
</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> </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"></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