Migrating from Apache FOP and XSL-FO / A report designer or markup toolchain
Migrating off Apache FOP, from XSL-FO to CSS
A formatter taking XSL-FO, an XML vocabulary for paged layout, usually produced from your data by an XSLT transform, where the transform is the template and both halves change.
What ports and what does not
The source XML and the data behind it. The XSLT does not, or rather it changes target: it was transforming your XML into XSL-FO, and it can transform it into HTML instead, which means the transform's structure survives and its output templates are rewritten. That is a real advantage over the other tooling migrations, because the branching and the iteration logic stay put. XSL-FO itself is closer to CSS in intent than anything else in this cluster, since both describe paged layout declaratively, so the concepts translate even though the syntax does not.
What the call becomes
The FopFactory, the transformer and the FO to PDF pipeline become a POST to /v1/pdf with html. fo:simple-page-master, which described the page geometry and its regions, becomes the @page rule with margin boxes: region-before is the top margin box, region-after is the bottom one. fo:page-sequence becomes a named page. The fo:table constructs map onto HTML tables closely, including the header repetition.
Side by side
The old shape and the new one, with the parts that have no counterpart called out in comments rather than quietly omitted.
<!-- Before: XSLT producing XSL-FO -->
<fo:simple-page-master master-name="A4" page-width="210mm" page-height="297mm"
margin-top="20mm" margin-bottom="25mm">
<fo:region-body margin-top="15mm" margin-bottom="15mm"/>
<fo:region-before extent="15mm"/>
<fo:region-after extent="15mm"/>
</fo:simple-page-master>
<!-- After: the same XSLT, producing HTML and CSS -->
<style>
@page {
size: 210mm 297mm;
margin: 35mm 20mm 40mm; /* body margins folded in */
@top-center { content: "Invoice"; } /* was region-before */
@bottom-center { content: counter(page); } /* was region-after */
}
</style>
<!-- The concept map:
fo:simple-page-master -> @page
fo:region-body -> the page margin box interior
fo:region-before/after -> @top-* and @bottom-* margin boxes
fo:page-sequence -> a named page
fo:block -> a block element
fo:table-header -> thead, repeating for the same reason
keep-together -> break-inside: avoid
break-before="page" -> break-before: page
The vocabulary changes; the model does not. -->The CSS delta, in both directions
What the old engine accepted that a current one does not, and what it refused that a current one wants. The second direction is the one people forget, and it is where the value of the migration is.
- The concepts translate unusually well, because XSL-FO and paged CSS are both declarative descriptions of the same thing. keep-together, keep-with-next and the break attributes all have direct counterparts.
- Page masters become @page rules and named pages, and regions become margin boxes, which is the cleanest structural mapping in this cluster.
- The absolute-positioned regions and the more exotic FO constructs have no counterpart and need rethinking rather than translating.
- Everything modern in CSS is new, and the XSLT can produce it as easily as it produced FO.
What changes without anything erroring
The dangerous list. Each of these produces a different document and no diagnostic, so none of them are caught by a test that only checks the render succeeded.
- Everything visual, because the output vocabulary is being rewritten.
- Page count.
- Anything relying on FO's more precise control over region geometry, which CSS margin boxes express differently.
- Fonts, from FOP's font configuration file to @font-face.
What to diff before cutting over
Diff extracted text first, because the XSLT is being changed and a transform error drops content silently. Then compare the page geometry by measuring, since the region and margin box models fold the same measurements together differently and it is easy to double-count a margin.
The one thing that always breaks
The region and body margin arithmetic. In XSL-FO the page master has margins and the body region has its own margins inside them, and both apply. In CSS there is one page margin, so the two numbers have to be added. Transcribing only the outer one produces a text block that is correct at the sides and too tall, and it overlaps the header on the first long document.
Frequently asked
Do I have to rewrite my templates to leave Apache FOP and XSL-FO?
Effectively yes, and it is better to plan for that than to discover it. The old tool did not have HTML templates to port, so the document has to be expressed as markup for the first time. The value in the old code is the data layer underneath the drawing, and that part survives untouched.
Can I run both for a while?
Yes, and it is the safest way to do it. Put both behind one internal function that takes your data and returns bytes, switch on an environment variable, and run the new path on real traffic while the old one still serves. You get a diff on real documents rather than on fixtures, and you keep a way back that does not involve a deploy.
What about the documents already generated?
Nothing here changes them. They are files that already exist. What is worth deciding before the cutover is whether a regenerated document has to match the original byte for byte or merely say the same thing, because for anything with a legal or audit character the answer is usually to keep the original file rather than to be able to reproduce it.
Other migrations
The nearest neighbours first, then others that started from the same kind of tool, because the model matters more than the language.
Migrating off LaTeX, and what you give up in typesetting
A typesetting system with its own language and a compilation step, where the migration is honest about losing typographic quality in exchange for everything else.
Migrating off JasperReports, and what happens to the bands
A reporting engine whose layouts are XML files built in a visual designer, organised into bands that repeat by rule, where nothing about the layout is portable and the band model has no equivalent.
Migrating off Prince, and the paged CSS features you lose
A commercial formatter with the most complete paged CSS implementation available, which makes this the one migration in the cluster where you should expect to give something up.
Migrating off Crystal Reports, and rebuilding the formula fields
A reporting product whose layouts live in binary report files edited in a designer, with sections, formula fields and its own formula language, none of which are portable.
Migrating off SSRS, from RDL and tablix to markup
A reporting service whose layouts are RDL files built around a tablix, with the report server providing scheduling, subscriptions and delivery alongside the rendering.
Every migration, grouped by what you are coming from
The full list, sorted by the model the old tool used rather than by its name.
What this API actually does
One page per option and endpoint that exists, which is what the mappings above point at.
Render one of your existing documents through the playground before changing any code. That comparison is the whole of the risk assessment for this migration.