← Alle Beiträge

GAEB-Dateien in Python lesen mit pyGAEB

Ein praxisnaher Leitfaden zum Parsen von GAEB-DA-XML-Dateien in Python mit der Open-Source-Bibliothek pyGAEB — vom Einzeiler bis zum Iterieren von Positionen, Validierung und Zurückschreiben eines Angebots.

GAEB DA XML ist der Standard für den Austausch von Leistungsverzeichnissen am Bau in Deutschland — und es von Hand zu parsen, ist eine Qual. Mehrere Schema-Versionen (2.0 bis 3.3), ein Dutzend Austauschphasen und XML, das nur zu gern eine XXE-Nutzlast oder eine „Billion Laughs“-Bombe versteckt. pyGAEB ist eine quelloffene (MIT) Python-Bibliothek, die all das in ein sauberes, typisiertes Modell überführt. So nutzt man sie in der Praxis.

Installation

# Kern-Parser + Writer + Export, ohne LLM-Abhängigkeiten
pip install pyGAEB

# Optional: LLM-gestützte Positionsklassifikation (100+ Provider über LiteLLM)
pip install pyGAEB[llm]

Jede Datei mit einem Aufruf parsen

Version und Phase muss man nicht im Voraus kennen — pyGAEB erkennt beides automatisch:

from pygaeb import GAEBParser

doc = GAEBParser.parse("tender.X83")   # DA XML 3.x
doc = GAEBParser.parse("old.D83")      # DA XML 2.x — derselbe Aufruf

print(doc.source_version)              # SourceVersion.DA_XML_33
print(doc.exchange_phase)              # ExchangePhase.X83
print(doc.grand_total)                 # Decimal("1234567.89")

Man beachte das Decimal — Beträge und Mengen sind nie Floats. Das zählt in dem Moment, in dem man ein paar tausend Positionen summiert.

Über die Positionen iterieren

iter_items() funktioniert über jede Dokumentart hinweg — Vergabe, Handel, Kostenermittlung und Mengenermittlung — sodass man generischen Code schreiben kann:

for item in doc.iter_items():
    print(item.oz)            # "01.02.0030"  — Ordnungszahl
    print(item.short_text)    # "Mauerwerk der Innenwand…"
    print(item.qty)           # Decimal("1170.000")
    print(item.unit)          # "m2"
    print(item.unit_price)    # Decimal("45.50")
    print(item.total_price)   # Decimal("53235.00")

Prüfen, was man geparst hat

Standardmäßig ist pyGAEB tolerant — es parst weiter und sammelt Probleme, damit man selbst entscheidet, was damit geschieht. Man kann auch früh abbrechen oder eigene Regeln registrieren:

from pygaeb import GAEBParser, ValidationMode

# Tolerant (Standard): Warnungen sammeln, weitermachen
doc = GAEBParser.parse("tender.X83")
for issue in doc.validation_results:
    print(issue.severity, issue.message)

# Strikt: beim ersten ERROR eine Ausnahme werfen
doc = GAEBParser.parse("tender.X83", validation=ValidationMode.STRICT)

Bepreisen und das Angebot zurückschreiben

Die häufigste reale Aufgabe: Man erhält eine D83/X83-Aufforderung, trägt Einheitspreise ein und gibt eine D84/X84 mit identischer Struktur zurück. Dieser Rundlauf ist eine erstklassige Operation:

from pygaeb import GAEBParser, GAEBWriter, ExchangePhase
from decimal import Decimal

doc = GAEBParser.parse("tender.X83")
item = doc.award.boq.get_item("01.02.0030")
item.unit_price = Decimal("48.00")

GAEBWriter.write(doc, "bid.X84", phase=ExchangePhase.X84)

Weil der Writer vom ursprünglichen Dokument ausgeht, behält das zurückgegebene Angebot exakt die Positionen und Kennungen, die die Software des Auftraggebers erwartet — kein struktureller Drift.

Zwischen Versionen konvertieren

Eine 2.x-Datei erhalten, aber die nachgelagerten Werkzeuge sprechen nur 3.3? Oder für einen Partner auf einem älteren System zurückstufen?

from pygaeb import GAEBConverter, SourceVersion

report = GAEBConverter.convert("old.D83", "modern.X83")
report = GAEBConverter.convert(
    "tender.X83", "compat.X83",
    target_version=SourceVersion.DA_XML_32,
)
print(report.items_converted, report.has_data_loss)

Das Flag has_data_loss ist ehrlich darüber, was eine Rückstufung gekostet hat — besser zu protokollieren, als es später zu entdecken.

Export für Menschen

Für schnelle Analysen oder die Übergabe an Nicht-Entwickler:

from pygaeb.convert import to_json, to_csv

to_json(doc, "boq.json")   # vollständiger, verschachtelter LV-Baum
to_csv(doc, "items.csv")   # flache Positionstabelle mit Klassifikationsspalten

Wo das hineinpasst

pyGAEB ist die Parse- und Schreib-Grundlage — die Schicht, die dafür sorgt, dass Software (und Kalkulatoren) nicht mehr wissen müssen, in welchem Format eine Ausschreibung ankam. Darauf ist die DatumOS-Plattform gebaut: dieselbe Engine, plus Klassifikation, Bepreisung und einen Prüf-Workflow obendrauf.

Sie ist MIT-lizenziert und auf GitHub — Issues, PRs und Beispieldateien für Randfälle sind alle willkommen. Wer mit GAEB in Python ringt, beginnt am besten mit GAEBParser.parse() und arbeitet sich von dort vor.

Kein Code im Spiel? pyGAEB bringt jetzt auch einen Model-Context-Protocol-Server mit — so lässt sich eine Ausschreibungsdatei in natürlicher Sprache von einem KI-Assistenten befragen, ganz ohne Python.

Kommentare

Kommentare werden vor der Veröffentlichung geprüft.

Kommentare werden geladen…

    Wird nur verwendet, falls wir Ihnen direkt antworten müssen.

    Ihr Name und Ihr Kommentar werden nach der Prüfung veröffentlicht. Datenschutzerklärung.