Glossary Term

XSLT

A W3C language for transforming XML documents into other XML, HTML, or text. In EU e-invoicing, XSLT is the engine that compiles Schematron rules for fast runtime validation, renders UBL or CII invoices into human-readable HTML or PDF (the KoSIT XRechnung visualization toolchain), and converts legacy ERP exports into EN 16931 syntaxes.

Quick Facts

Versions
1.0 (1999), 2.0 (2007), 3.0 (2017)
Primary uses
Schematron compilation, invoice viewers, format mapping
Output formats
XML, HTML, XSL-FO/PDF, text, JSON (3.0)
Standards body
W3C
Reference engine
Saxon HE/PE/EE (Java, .NET, C)
Schematron compiler
iso_svrl_for_xslt2.xsl
EN 16931 requirement
XSLT 2.0 (for compiled Schematron)
Viewer reference impl
KoSIT xrechnung-visualization

Definition

What it is

XSLT — XML Stylesheet Language Transformations — is a W3C standard for transforming XML documents. A stylesheet is itself an XML document containing templates that match nodes in the input (using XPath) and emit output. The output can be XML (e.g. UBL converted to CII), HTML (a human-readable invoice viewer), plain text (a CSV export), or arbitrary serialized formats including JSON in XSLT 3.0.

Three versions are in active use:

  • XSLT 1.0 (1999) — universal support; everything that parses XML can probably run XSLT 1.0. Limited: no sequences, no functions you write yourself in a portable way, weak typing.

  • XSLT 2.0 (2007) — the version that EN 16931 Schematron tooling depends on. Adds user-defined functions, grouping, regular expressions, schema-awareness, and the underlying XPath 2.0 type system.

  • XSLT 3.0 (2017) — adds streaming (process gigabyte XML without loading it in memory), packages, maps and arrays, and JSON serialization. Adopted in modern toolchains but not required by EN 16931 itself.
  • XSLT is declarative — you describe what the output should look like for each kind of input node, not the step-by-step procedure for producing it. The XSLT engine handles the traversal order, template matching, and output sequencing.

    Why XSLT shows up in EU e-invoicing

    There are three places an ERP vendor will encounter XSLT during EN 16931 work, and the right one to focus on depends on which side of the pipeline the vendor sits.

    1. Schematron compilation

    The official EN 16931 Schematron, every CIUS Schematron (XRechnung, Peppol BIS Billing 3.0, the Dutch SI-UBL profile, the French specs), and the country-specific extensions are all distributed as .sch files containing XPath 2.0 assertions. Running raw Schematron at validation time is expensive — every assertion has to be re-parsed and re-bound on each invoice.

    The standard solution is ISO Schematron's iso_svrl_for_xslt2.xsl, a meta-stylesheet that compiles a Schematron file into an XSLT 2.0 stylesheet. Validation then becomes: apply the compiled XSLT to the invoice, get back an SVRL (Schematron Validation Report Language) document listing the failed assertions. This compiles once at build time and runs in single-digit milliseconds per invoice.

    Every serious EN 16931 validator — the Connecting Europe Facility reference validator, KoSIT's validator, the Peppol Test Bed validator, every commercial validator I'm aware of — works this way. "Schematron support" almost always means "compiled Schematron, executed as XSLT."

    2. Viewer transformations (UBL/CII → HTML/PDF)

    Machine-readable XML is not human-readable. When an EN 16931 invoice arrives at an accounts-payable clerk's screen, somebody has to render it. The dominant approach in Germany — and increasingly across the EU — is to use XSLT to transform the invoice into HTML or XSL-FO (which then renders to PDF).

    KoSIT's xrechnung-visualization project is the de facto reference. It ships XSLT 2.0 stylesheets that convert any XRechnung-conformant UBL or CII invoice into an HTML view (with codelist labels resolved from UN/CEFACT recommendations) or a PDF via Apache FOP. The stylesheets are open source and many ERP vendors and government portals embed them directly rather than building their own viewers.

    France's PPF specification and several Peppol authorities reference KoSIT's viewer as the recommended rendering implementation. "Render an EN 16931 invoice as a PDF" is rarely a custom build; it is almost always a KoSIT XSLT stylesheet plus a FOP renderer.

    3. ERP-format-to-EN-16931 mapping

    Most ERP systems have an internal invoice representation that is not UBL and not CII. Converting from "the way our system thinks about invoices" to UBL or CII is a transformation problem, and XSLT is one of the standard tools for it — particularly when the source is already XML (a legacy EDIFACT-XML wrapper, an internal canonical-XML format, or a SAP IDoc-XML export).

    The alternative is procedural code in Java/.NET/Python with an XML builder. Both work; XSLT wins when the mapping rules are stable and the team owns a Saxon licence (or uses Saxon HE).

    XSLT engines and the EN 16931 toolchain

    For XSLT 2.0 and 3.0 (the versions EN 16931 needs), there is effectively one production-grade engine and a handful of niche alternatives.

  • Saxon (Saxonica) — the reference implementation for XSLT 2.0 / 3.0 and XPath 2.0 / 3.1. Three editions: HE (Home Edition, open source, free, covers everything EN 16931 needs), PE (Professional, schema-awareness), EE (Enterprise, schema-aware XSLT 3.0 streaming). Available as Java, .NET (SaxonCS), and a C/C++ binding. The Connecting Europe Facility validator, KoSIT's validator, Peppol's Test Bed validator, and most commercial validators run on Saxon HE.

  • libxslt — fast, C-based, XSLT 1.0 only. Disqualified from running EN 16931 Schematron-compiled XSLT directly because the compiled output requires XSLT 2.0 features. Still useful for the simpler internal transformation steps.

  • Native XSLT 1.0 engines in .NET (XslCompiledTransform), Java (javax.xml.transform.TransformerFactory default), Python (lxml), Go (encoding/xml has none — third-party only). All XSLT 1.0; none can execute the EN 16931 compiled Schematron.
  • The practical consequence: if your EN 16931 validation pipeline does not have Saxon (or an equivalent XSLT 2.0+ engine) in the dependency graph, it is not running real Schematron validation. It is running something else — a hand-translated subset of the rules, an XPath 1.0 approximation, or a regex parade. None of those will catch the same errors the official artefacts catch.

    XSLT vs. XPath vs. XSD vs. Schematron — the validation toolchain

    These four are often confused. In an EN 16931 pipeline they have distinct roles:

  • XSD validates structure and types — "this document has the right shape."

  • Schematron declares business rules — "BT-112 equals BT-109 plus BT-110."

  • XPath is the query language Schematron rules and XSLT stylesheets use to address elements.

  • XSLT is the engine that runs compiled Schematron and renders invoices for human viewing.
  • An invoice gets parsed (well-formed XML), validated against XSD (structure), validated against XSLT-compiled Schematron (business rules, written in XPath, expressed as a stylesheet), and rendered to HTML via a separate XSLT stylesheet. Four W3C standards layered into one validation-and-viewing pipeline. Every one of them is mandatory for a serious implementation.

    Relation to EN 16931

    XSLT is not itself referenced by EN 16931. The standard mandates UBL 2.1 or CII D16B as the XML syntax and references Schematron for the business rules — XSLT is the implementation technology that ties them together. But every realistic EN 16931 implementation depends on XSLT in at least one of the three places above, and most depend on it in all three. For an ERP vendor scoping an EN 16931 integration, "do we have an XSLT 2.0 toolchain?" is a foundational architecture question, not an implementation detail.

    XML Examples

    UBL (Peppol, XRechnung)

    <!-- XSLT 2.0 template that emits an HTML row for each UBL invoice line. -->
    <xsl:stylesheet version="2.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
      xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
      <xsl:template match="cac:InvoiceLine">
        <tr>
          <td><xsl:value-of select="cbc:ID"/></td>
          <td><xsl:value-of select="cac:Item/cbc:Name"/></td>
          <td><xsl:value-of select="cbc:InvoicedQuantity"/></td>
          <td><xsl:value-of select="cbc:LineExtensionAmount"/>
              <xsl:text> </xsl:text>
              <xsl:value-of select="cbc:LineExtensionAmount/@currencyID"/></td>
        </tr>
      </xsl:template>
    </xsl:stylesheet>

    CII (ZUGFeRD, Factur-X)

    <!-- XSLT 2.0 template that converts CII trade-line items into a flat report row. -->
    <xsl:stylesheet version="2.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100">
      <xsl:template match="ram:IncludedSupplyChainTradeLineItem">
        <line>
          <id><xsl:value-of select="ram:AssociatedDocumentLineDocument/ram:LineID"/></id>
          <description><xsl:value-of select="ram:SpecifiedTradeProduct/ram:Name"/></description>
          <quantity><xsl:value-of select="ram:SpecifiedLineTradeDelivery/ram:BilledQuantity"/></quantity>
          <net-amount><xsl:value-of select="ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeSettlementLineMonetarySummation/ram:LineTotalAmount"/></net-amount>
        </line>
      </xsl:template>
    </xsl:stylesheet>

    Related Content