Glossary Term

XPath

A W3C query language for addressing parts of an XML document by path expressions. In EU e-invoicing, XPath is the glue: every Schematron rule, every XSLT mapping, and every "the element at this location is wrong" error message ultimately speaks XPath. ERP developers cannot debug EN 16931 validation without reading it.

Quick Facts

Versions
1.0 (1999), 2.0 (2007), 3.1 (2017)
Common trap
Namespace prefix binding (cbc:/cac:/ram:/rsm:)
Primary use
Schematron rules, XSLT transformations, error reporting
Standards body
W3C
Number of rules
~200 in EN 16931 baseline; hundreds more in each CIUS
Reference engine
Saxon (Java/.NET/C)
EN 16931 requirement
XPath 2.0 (via XSLT 2.0 Schematron)
Output of validators
Failing XPath + rule code (e.g. BR-CO-15)

Definition

What it is

XPath is the W3C language for navigating XML. A path expression like /Invoice/cac:AccountingSupplierParty/cac:Party/cbc:EndpointID selects a node (or a set of nodes) inside a document — in this case the seller's electronic address inside a UBL invoice. XPath is to XML what a file path is to a filesystem, but with the added ability to filter by attribute, predicate, and namespace.

Three versions matter in practice:

  • XPath 1.0 (1999) — the original, supported everywhere, but limited: no sequences, weak typing, no real string-handling beyond substring() and contains().

  • XPath 2.0 (2007) — the version mandated by the EN 16931 Schematron artefacts. Adds sequences, schema-aware types, regular expressions, and for/if/let expressions.

  • XPath 3.1 (2017) — adds maps, arrays, and JSON interop. Increasingly common in modern XSLT 3.0 toolchains but not required by EN 16931.
  • Why it matters in e-invoicing

    Every layer of an EN 16931 validation pipeline speaks XPath:

  • Schematron rules. The official EN 16931 Schematron artefacts (currently v1.3.16, maintained on GitHub by the Connecting Europe Facility) are roughly 200 XPath 2.0 assertions over UBL or CII. A rule like BR-CO-15 — "Invoice total amount with VAT (BT-112) = Invoice total amount without VAT (BT-109) + Invoice total VAT amount (BT-110)" — is expressed as an XPath expression evaluated against the invoice tree.

  • Error reporting. When validation fails, the report typically returns the failing XPath, the rule code, and a human description. Reading the XPath is how a developer locates the offending element — there is no field name to grep for.

  • XSLT transformations. Mapping a legacy ERP format to UBL or CII, or converting between UBL and CII, is done with XSLT, which uses XPath to address source nodes.

  • CIUS Schematrons. Country-specific extensions (XRechnung, Peppol BIS Billing 3.0, the Dutch SI-UBL, the Italian FatturaPA) add their own Schematron files, each with hundreds of additional XPath rules layered on top of the EN 16931 baseline.
  • An ERP vendor implementing EN 16931 will read XPath expressions every working day during the integration phase, and again every time the validation artefacts are updated (typically twice a year).

    XPath in a Schematron rule

    A typical EN 16931 Schematron rule looks like:


    test="(round(cbc:LineExtensionAmount * 100) =
    round(sum(../cac:InvoiceLine/cbc:LineExtensionAmount) * 100))">
    [BR-CO-13] Invoice total amount without VAT (BT-106)
    must equal the sum of Invoice line net amounts (BT-131).


    The context is an XPath that selects which node the rule runs against. The test is an XPath that must evaluate to true() — if it does not, the rule fires and the engine produces an error.

    Note the multiplication by 100 and the round(). Decimal arithmetic in XPath 1.0 is famously fragile; the EN 16931 rules normalise to integer cents to avoid floating-point drift between implementations. This single workaround is the source of more developer confusion than almost any other detail in the standard.

    Namespaces — the trap that catches everyone

    UBL invoices use two prefixes by convention: cbc: for urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2 (single-element values like amounts and identifiers) and cac: for urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2 (groups). CII uses ram: and rsm: for its own namespaces. XPath is namespace-aware, which means:

  • Invoice/AccountingSupplierParty/Party/EndpointID — wrong; matches nothing.

  • //*[local-name()='EndpointID'] — works but is sloppy and slow.

  • /cbc:Invoice/cac:AccountingSupplierParty/cac:Party/cbc:EndpointID — correct, provided the prefixes are bound to the right namespace URIs in the evaluation context.
  • Almost every "I wrote the XPath and it returns nothing" bug is a namespace binding issue, not a path issue.

    XPath toolchain choices

    ERP vendors typically reach for one of three execution engines:

  • Saxon (Saxonica) — the reference implementation for XPath 2.0 / 3.1 and XSLT 2.0 / 3.0. Used by the Connecting Europe Facility's official validator and by most serious commercial validators. Available as Java, .NET, and a C library; the HE (Home Edition) is open source.

  • libxml2 / libxslt — fast, C-based, but XPath 1.0 only. Disqualified from EN 16931 Schematron use without a wrapper that compiles the rules to XSLT 2.0 first.

  • Native engines in .NET, Java, Python (lxml), and Go. Most are XPath 1.0; check before committing.
  • A common architecture is to pre-compile the EN 16931 Schematron into XSLT once (Saxon does this with iso_svrl_for_xslt2.xsl) and then run the resulting XSLT against each invoice. This makes validation cheap per invoice — typically <10ms — and means production runtimes only need an XSLT 2.0 processor, not a full Schematron implementation.

    Relation to EN 16931

    EN 16931 itself is syntax-agnostic. The semantic standard (the BT- and BG- business terms) does not care whether you express an invoice in UBL or CII. But every conformance check that exists — the official Schematron, the country CIUS Schematrons, the Peppol BIS Schematrons — is written in XPath. The semantic standard travels through an XPath-shaped door.

    For an ERP vendor, this means XPath fluency is not optional. The team that owns the e-invoicing module needs at least one engineer who can read an XPath expression, locate the failing element in the document, and explain to product why the rule fired. Without that, every validation error becomes a ticket to an external consultancy.

    XML Examples

    UBL (Peppol, XRechnung)

    <!-- XPath selecting BT-49 (Buyer electronic address) in UBL: -->
    <!-- /Invoice/cac:AccountingCustomerParty/cac:Party/cbc:EndpointID -->
    
    <Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
             xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
             xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
      <cac:AccountingCustomerParty>
        <cac:Party>
          <cbc:EndpointID schemeID="0192">991825827</cbc:EndpointID>
        </cac:Party>
      </cac:AccountingCustomerParty>
    </Invoice>

    CII (ZUGFeRD, Factur-X)

    <!-- XPath selecting BT-49 in CII: -->
    <!-- /rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:URIUniversalCommunication/ram:URIID -->
    
    <rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
                              xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100">
      <rsm:SupplyChainTradeTransaction>
        <ram:ApplicableHeaderTradeAgreement>
          <ram:BuyerTradeParty>
            <ram:URIUniversalCommunication>
              <ram:URIID schemeID="0192">991825827</ram:URIID>
            </ram:URIUniversalCommunication>
          </ram:BuyerTradeParty>
        </ram:ApplicableHeaderTradeAgreement>
      </rsm:SupplyChainTradeTransaction>
    </rsm:CrossIndustryInvoice>

    Related Content