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>
EngineLicenceStrengthsWeaknesses
Apache FOPApache 2.0Free, predictable, good for tables and long documentsNo hyphenation by default, limited font handling
Antenna HouseCommercialExcellent typography and CJK supportCost, per-server licensing
RenderX XEPCommercialFast, mature, good SVG supportCost
Prince XMLCommercialTakes HTML plus CSS instead of FODifferent 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.

Output methods and real use cases Calling XSLT from Java, .NET and Python

Last refreshed 2026-09-18.