XSL-FO and PDF generation pipelines
XSL-FO is a page description language driven by XSLT. It still produces the best paginated output, at the cost of a second transform and a heavier toolchain.
The two-stage pipeline
The usual shape is: source XML plus a stylesheet produce a formatting-object document, and a formatting-object processor turns that into PDF. The XSLT stage has no knowledge of pagination; the FO processor decides where pages break.
# Stage 1: XML to XSL-FO
xsltproc --output book.fo to-fo.xsl book.xml
# Stage 2: XSL-FO to PDF with Apache FOP
fop -fo book.fo -pdf book.pdf
# One command, two stages, for a build script
fop -xml book.xml -xsl to-fo.xsl -pdf book.pdf<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="A4" page-height="297mm" page-width="210mm"
margin="20mm">
<fo:region-body margin-bottom="15mm"/>
<fo:region-after extent="10mm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4">
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="center" font-size="8pt">
Page <fo:page-number/> of <fo:page-number-citation ref-id="end"/>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="16pt" font-weight="bold" space-after="6mm">
<xsl:value-of select="//title"/>
</fo:block>
<fo:block font-size="10pt" text-align="justify">
<xsl:value-of select="//summary"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>| Engine | Licence | Strengths | Weaknesses |
|---|---|---|---|
| Apache FOP | Apache 2.0 | Free, predictable, good for tables and long documents | No hyphenation by default, limited font handling |
| Antenna House | Commercial | Excellent typography and CJK support | Cost, per-server licensing |
| RenderX XEP | Commercial | Fast, mature, good SVG support | Cost |
| Prince XML | Commercial | Takes HTML plus CSS instead of FO | Different input model |
💡
If you already control the markup, CSS paged media with a headless browser or Prince gets you a paginated PDF from HTML in one stage and is easier for a web developer to maintain. Choose XSL-FO when you need strict control over page geometry, running headers and multi-column flows.
FAQ
Do I have to write XSL-FO by hand?
No — the second stage is generated by XSLT, so you write templates that emit fo: elements. DocBook and DITA toolchains ship stylesheets that already do this.
Why is my font missing in the PDF?
FO engines do not use system fonts by default. FOP needs an explicit font configuration file mapping the family name to the font file, and the PDF must embed it for the glyphs to be present.
Related
Output methods and real use cases Calling XSLT from Java, .NET and Python
Last refreshed 2026-09-18.