CSSMedia - XML to PDF with CSS

CSSMedia logo

CSSMedia is a TypeScript / Node.js engine that reads an XML file and a CSS stylesheet and generates a PDF that follows what the CSS specifications say must be done with that stylesheet. You can run it from the command line or call it from your own code as a library.

Styling comes from CSS alone. The engine makes no assumptions about element names or attribute semantics, so any well-formed XML can be styled, not just a specific vocabulary like DITA or DocBook. PDF is the only output.

The source code is available on GitHub under the Business Source License 1.1. CSSMedia already generates PDF files and is under active development. Support for CSS features is not complete yet, and more is being added.

Quick example

Install the package from the root of the repository (Node.js 24 or newer is required):

npm install -g file:cssmedia-x.x.x.tgz

Then format an XML file with a CSS stylesheet and write the PDF:

cssmedia -x document.xml -c document.css -p document.pdf

Why CSSMedia

An XML document describes content, not pages. To publish it as a PDF you have to say how it looks on paper: page size and margins, fonts, headers and footers, page numbers, line breaking for each language.

The traditional way to do that is a two-step pipeline: an XSLT stylesheet transforms the XML into XSL-FO, and an FO processor renders the result. Both steps need specialized knowledge, and the stylesheets are usually written for one XML vocabulary, so each new vocabulary needs new stylesheets.

CSSMedia replaces that pipeline with a single CSS stylesheet applied directly to the XML. This is what changes:

  • The design is written in CSS. A CSS rule says how an element looks. There are no templates, modes or XPath expressions to write, and no intermediate XSL-FO document to produce and debug. If you know XSL-FO, you can reuse that knowledge: many XSL-FO properties, such as font-family, text-align and padding, are also CSS properties.
  • The XML is styled directly. The source document is not converted to another format first, so the structure of the output follows the structure of the document.
  • One engine for any XML vocabulary. The engine does not assume anything about element names or attributes. Each vocabulary needs only its own stylesheet.
  • One stylesheet for many languages. The same stylesheet can format a document in several languages and scripts, as the xml_gap sample shows. It is a DocBook article in four languages, included in the samples folder of the repository.
  • Behavior defined by specifications. Features are implemented from the CSS specifications, so what a property does is documented by the specification that defines it.

Features

Core capabilities for turning XML into PDF with CSS:

Languages and text

  • Multiple languages and scripts: documents can be in any language, including right-to-left scripts such as Arabic and CJK languages such as Japanese. The xml_gap samples show the same article in English, Arabic, Japanese and Russian, all styled by one stylesheet.
  • Hyphenation by language: with hyphens: auto, words are hyphenated using the patterns of the language declared in the document by using xml:lang. CSSMedia includes 75 hyphenation pattern sets, which cover many languages and some of their variants, such as en-us and en-gb. The swordfish_hyphens.pdf sample is generated with hyphenation turned on.

Styling

  • CSS-only styling: the XML is styled by CSS alone. Selector matching, specificity, cascade, inheritance and value resolution are CSSMedia's own code; css-tree is used only to parse CSS syntax.

Fonts and images

  • Fonts: OpenType, TrueType, collections, WOFF and WOFF 2.0 files, loaded from @font-face rules or a fonts folder, plus the 14 standard PDF fonts.
  • Images: readers for PNG, JPEG, JPEG 2000 and WebP, written in CSSMedia's own code.
  • SVG and MathML: SVG and MathML found in a document are handled as images.

Usage

Run cssmedia and the program prints this help text:

Usage: cssmedia -x <file> -c <file> -p <file> [-f <fontsFolder>] [-g <catalog>]

  -x, --xml <file>       XML file to format
  -c, --css <file>       CSS stylesheet to apply
  -p, --pdf <file>       PDF file to write
  -f, --fonts <folder>   (optional) alternative fonts folder
  -g, --catalog <file>   (optional) OASIS catalog to use when parsing XML

Use -g to pass a custom OASIS catalog, so that the XML file is read with its associated grammars:

cssmedia -x document.xml -c document.css -p document.pdf -g catalog.xml

Warnings are printed to stderr. When processing fails, the program prints the error and exits with code 1; wrong arguments exit with code 2.

Fonts

Fonts come from the @font-face rules of the stylesheet, then from the folder given with -f. CSSMedia does not search the fonts installed on the computer. The 14 standard PDF fonts are always available under the family names Times, Helvetica, Courier, Symbol and ZapfDingbats. A declared family or a family in the -f folder with the same name takes precedence.

CSSMedia loads OpenType and TrueType (.otf, .ttf), OpenType collections (.otc, .ttc), WOFF 1.0 (.woff) and WOFF 2.0 (.woff2) fonts. The User Manual describes the @font-face descriptors, the format() and tech() values that are supported, and the sources that are skipped.

Using CSSMedia as a library

PdfGenerator.generate() writes the PDF. The constructor takes the optional font folder and the optional XML catalog, and the warnings of the last run are in warnings:

const generator: PdfGenerator = new PdfGenerator("/path/to/fonts");
generator.generate("document.xml", "document.css", "document.pdf");
generator.warnings.forEach((warning: string): void => console.error(warning));

Documentation & Samples

  • Read the CSSMedia User Guide (PDF) to learn how to run CSSMedia and how to write stylesheets for it. The manual is written in DITA XML and its PDF is generated with CSSMedia itself, so it is also an example of what CSSMedia produces.
  • Explore the samples, which include the XML files, the stylesheets and the fonts they use:
    • xml_gap: a DocBook article in English, Arabic, Japanese and Russian, all formatted with one stylesheet.
    • Swordfish: the User Guide of Swordfish, a real product, originally written in DITA and merged into one XML file in two ways, each with its own stylesheet.

To try CSSMedia on the English sample, run these commands from the samples folder:

cd samples
cssmedia -x xml_gap/xml_gap.xml -c xml_gap.css -p xml_gap/xml_gap.pdf

The command prints a warning about the DocBook DTD and generates xml_gap/xml_gap.pdf.