E-Rechnung XML selbst erstellen: Anleitung für technisch Versierte

Wer möchte, kann E-Rechnungen direkt als XML-Datei erstellen. Wir zeigen, wie eine valide XML-Rechnung aufgebaut ist und welche Tools dabei helfen.

02.12.2026

Wer ein eigenes ERP, eine eigene Plattform oder ein Spezialsystem baut, stößt früher oder später auf die Frage: „Wie generiere ich das XML selbst?" Die Antwort ist erstaunlich machbar, sobald man die zwei Syntaxen, die Namespaces und die wichtigsten Pflichtfelder verstanden hat. Bibliotheken sparen viel Arbeit, sind aber kein Muss – ein gut strukturierter XML-Generator reicht für die meisten Fälle.

Dieser Beitrag zeigt den Aufbau einer XRechnung in beiden Syntaxen, listet die Pflichtfelder, erklärt Validierung und nennt Bibliotheken für die populärsten Sprachen.

UBL oder CII?

Die Norm EN 16931 erlaubt zwei XML-Syntaxen:

SyntaxVollformWo verbreitet
UBL 2.1Universal Business LanguagePeppol, internationale B2B-Welt
CIIUN/CEFACT Cross Industry InvoiceZUGFeRD/Factur-X, Bundesbehörden in Deutschland

XRechnung kann beide Syntaxen, ZUGFeRD nur CII. Wer für die Bundesverwaltung produziert, ist mit CII flexibel. Wer Peppol bedient, sollte UBL können. Mehr in XML-Format.

Grundgerüst UBL

Eine minimale UBL-Rechnung sieht so aus:

<?xml version="1.0" encoding="UTF-8"?>
<Invoice
  xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
  xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
  xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">

  <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_3.0</cbc:CustomizationID>
  <cbc:ID>2027-0001</cbc:ID>
  <cbc:IssueDate>2027-01-15</cbc:IssueDate>
  <cbc:DueDate>2027-02-14</cbc:DueDate>
  <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
  <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
  <cbc:BuyerReference>04011000-12345-67</cbc:BuyerReference>

  <cac:AccountingSupplierParty>...</cac:AccountingSupplierParty>
  <cac:AccountingCustomerParty>...</cac:AccountingCustomerParty>
  <cac:PaymentMeans>...</cac:PaymentMeans>
  <cac:TaxTotal>...</cac:TaxTotal>
  <cac:LegalMonetaryTotal>...</cac:LegalMonetaryTotal>
  <cac:InvoiceLine>...</cac:InvoiceLine>
</Invoice>

Drei Namespaces sind Standard: der Invoice-Namespace, cbc für Basiskomponenten, cac für Aggregate. Der CustomizationID-Wert teilt dem Validator mit, dass es eine XRechnung ist.

Grundgerüst CII

Die CII-Variante ist verbose-r und nutzt vier Namespaces:

<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice
  xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
  xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
  xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
  xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100">

  <rsm:ExchangedDocumentContext>
    <ram:GuidelineSpecifiedDocumentContextParameter>
      <ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_3.0</ram:ID>
    </ram:GuidelineSpecifiedDocumentContextParameter>
  </rsm:ExchangedDocumentContext>

  <rsm:ExchangedDocument>
    <ram:ID>2027-0001</ram:ID>
    <ram:TypeCode>380</ram:TypeCode>
    <ram:IssueDateTime>
      <udt:DateTimeString format="102">20270115</udt:DateTimeString>
    </ram:IssueDateTime>
  </rsm:ExchangedDocument>

  <rsm:SupplyChainTradeTransaction>...</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

Achtung: In CII ist das Datumsformat YYYYMMDD mit format="102", in UBL YYYY-MM-DD. Verwechslung ist Klassiker Nr. 1.

Pflichtfelder, ohne die nichts geht

Das ist die Kurzliste – siehe auch Pflichtfelder:

FeldUBL-ElementCII-Element
Rechnungsnummercbc:IDram:ExchangedDocument/ram:ID
Rechnungsdatumcbc:IssueDateram:IssueDateTime
Rechnungstypcbc:InvoiceTypeCoderam:TypeCode
Währungcbc:DocumentCurrencyCoderam:InvoiceCurrencyCode
Käuferreferenzcbc:BuyerReferenceram:BuyerReference
Verkäufercac:AccountingSupplierPartyram:SellerTradeParty
Käufercac:AccountingCustomerPartyram:BuyerTradeParty
Steueraufschlüsselungcac:TaxTotal/cac:TaxSubtotalram:ApplicableTradeTax
Summencac:LegalMonetaryTotalram:SpecifiedTradeSettlementHeaderMonetarySummation
Positioncac:InvoiceLineram:IncludedSupplyChainTradeLineItem

Eine Position in UBL

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <cbc:InvoicedQuantity unitCode="HUR">8</cbc:InvoicedQuantity>
  <cbc:LineExtensionAmount currencyID="EUR">800.00</cbc:LineExtensionAmount>
  <cac:Item>
    <cbc:Name>Beratung Migration</cbc:Name>
    <cac:ClassifiedTaxCategory>
      <cbc:ID>S</cbc:ID>
      <cbc:Percent>19</cbc:Percent>
      <cac:TaxScheme>
        <cbc:ID>VAT</cbc:ID>
      </cac:TaxScheme>
    </cac:ClassifiedTaxCategory>
  </cac:Item>
  <cac:Price>
    <cbc:PriceAmount currencyID="EUR">100.00</cbc:PriceAmount>
  </cac:Price>
</cac:InvoiceLine>

HUR ist die Maßeinheit „Stunde" nach UN/ECE Rec. 20. Mehr zur Maßeinheit in BT-130.

Validierung in der eigenen Pipeline

Ihr Generator ist erst dann fertig, wenn jede Ausgabe automatisch durch zwei Schritte geht:

  1. XSD-Validierung mit dem offiziellen Schema (für UBL: UBL-Invoice-2.1.xsd, für CII: CrossIndustryInvoice_100pD22B.xsd).
  2. Schematron-Validierung mit den EN-16931- und XRechnung-Regeln (KoSIT-Validator-Konfiguration).

Beides lässt sich in Java mit javax.xml.validation und ph-schematron umsetzen, in Python mit lxml, in .NET mit System.Xml.Schema. In CI integrieren – sonst zerlegt das nächste Refactoring den Output.

Mehr in Integrationstest.

Bibliotheken pro Sprache

Wer nicht alles von Hand baut, nimmt eine Bibliothek:

SpracheBibliothekAnmerkung
Javamustangprojectde facto Standard, ZUGFeRD + XRechnung
Javaph-ubl, ph-ciiHelper-Bibliotheken zu UBL/CII
.NETs2industries.ZUGFeRDaktiv gepflegt
PHPhorstoeko/zugferdgut dokumentiert
PythondrafthorseCII-Generator
JavaScript / TS@e-rechnung/*wachsendes Ökosystem

Vorteil von Bibliotheken: Codeschlüssel, Maßeinheiten, BR-Logik sind eingebaut. Nachteil: Sie sind an deren Datenmodell gebunden.

Häufige Fehler beim Eigenbau

  • Falsche Reihenfolge: UBL/CII haben strikte Reihenfolgen. Das Schema schlägt sofort an.
  • Beträge mit Komma: Nur Punkt als Dezimaltrennzeichen.
  • Rundung inkonsistent: Positions-, Steuer- und Gesamtsummen müssen exakt zusammenpassen (BR-CO-10 ff.).
  • Default-Namespace verloren: Wer manuell konkateniert, vergisst Namespace-Präfixe.
  • Falscher InvoiceTypeCode: 380 (Rechnung), 381 (Gutschrift), 384 (Korrektur). Mehr in Gutschrift.
  • CustomizationID veraltet: bei jedem XRechnung-Versions-Update prüfen.

Versionsmanagement

Die Schemata und Schematron-Regeln entwickeln sich weiter. Empfehlung:

  • Aktuelle Version (XRechnung 3.x) als Default.
  • Verwendete Version pro Empfänger speichern (manche akzeptieren noch 2.x).
  • Validator-Bibliothek nicht dauerhaft auf eine Version pinnen, sondern jährlich aktualisieren.

Häufige Fragen

Lohnt sich der Eigenbau?

Wenn Sie eine Standard-Buchhaltungslösung haben: nein. Wenn Sie eine eigene Plattform betreiben (z. B. Marktplatz, Telco, Energieversorger) oder sehr viele Rechnungen erzeugen, fast immer ja.

Welche Syntax soll ich nehmen?

Wenn Sie hauptsächlich an Behörden und Mittelstand in Deutschland liefern: CII. Wenn Sie international über Peppol versenden: UBL. Im Idealfall können Sie beides.

Reicht XSD-Validierung aus?

Nein. XSD prüft nur die Struktur. Die EN-16931-Regeln werden über Schematron geprüft. Beides ist nötig.

Muss ich PDF/A-3 selbst bauen können?

Nur, wenn Sie ZUGFeRD-Hybriddateien erzeugen wollen. Reine XRechnung ist XML-only. Für PDF/A-3 nutzt fast jeder eine Bibliothek (iText, PDFBox, FPDI), kein Eigenbau.

Wo finde ich offizielle Beispieldateien?

Auf der Seite des KoSIT und im Mustang-Repository. Beide bieten getestete Referenz-Rechnungen, gegen die Sie Ihren Generator regredieren lassen können.