xmlstarlet ist das Unix-CLI-Schweizermesser für XML — es kombiniert XPath-Abfrage, Massen-Edit, XSLT-Transformation, Schema-Validierung und Pretty-Print in einem einzigen Werkzeug. Wer regelmässig grössere Mengen XML-Dateien (TEI-Editionen, EAD-Findmittel, METS-Manifeste, OAI-PMH-Records) auf der Shell prozessiert, kommt an xmlstarlet kaum vorbei.
Das Programm lebt seit ~2002 als plattformunabhängige C-Anwendung um libxml2 und libxslt herum; es liefert verlässliche XPath 1.0- und XSLT-1.0-Unterstützung mit grosszügigen Optionen für Namespaces, Encoding und Output-Formatierung.
Installation
# macOS
brew install xmlstarlet
# Debian/Ubuntu
apt install xmlstarlet
# Aufruf entweder als `xmlstarlet` oder kürzer `xml`
xml --version
Auf den meisten Systemen ist sowohl xmlstarlet als auch das kürzere xml als Alias installiert.
Die Sub-Kommandos
| Kommando | Aufgabe |
|---|---|
sel | Select — XPath-Abfrage, Resultate ausgeben |
ed | Edit — Knoten einfügen, ändern, löschen, umbenennen |
val | Validate — gegen DTD, XSD oder RelaxNG |
tr | Transform — XSLT 1.0 ausführen |
fo | Format — Pretty-Print, Encoding-Konversion |
c14n | Canonicalize — XML-Kanonisierung (XMLDsig-tauglich) |
esc / unesc | XML-Entitäten escapen / unescapen |
elem | XML-Element-Generator |
pyx | Konversion zu/von PYX (Lex-/Linien-orientiertes Hilfsformat) |
ls | Verzeichnis als XML auflisten |
In der Praxis sind sel, ed, val und tr die meistgenutzten.
sel — XPath-Abfragen
Werte oder Knoten aus einem XML-Dokument extrahieren.
# Alle persName-Texte ausgeben (ohne Namespace)
xmlstarlet sel -t -m '//persName' -v 'text()' -n datei.xml
# Mit TEI-Namespace
xmlstarlet sel -N t='http://www.tei-c.org/ns/1.0' \
-t -m '//t:persName' -v 'text()' -n datei.tei.xml
# Attribut-Werte sammeln
xmlstarlet sel -t -v '//persName/@ref' -n datei.xml | sort -u
# Mehrere Spalten als TSV ausgeben
xmlstarlet sel -t \
-m '//tei:person' \
-v '@xml:id' -o $'\t' \
-v 'tei:persName' -o $'\t' \
-v 'tei:birth/@when' \
-n \
-N tei='http://www.tei-c.org/ns/1.0' \
datei.xml
# Anzahl Elemente
xmlstarlet sel -t -v 'count(//letter)' datei.xml
# Bedingte Selektion (Personen ohne ref)
xmlstarlet sel -N t='http://www.tei-c.org/ns/1.0' \
-t -m '//t:persName[not(@ref)]' \
-v 'concat(., " (in ", ancestor::t:div[1]/@xml:id, ")")' -n \
datei.tei.xml
Die wichtigsten -t (Template)-Bausteine:
| Option | Bedeutung |
|---|---|
-m '<xpath>' | Match — pro Treffer ausführen |
-v '<xpath>' | Value — Wert ausgeben |
-c '<xpath>' | Copy — kompletten Knoten ausgeben |
-o 'text' | Output — wörtlichen Text ausgeben |
-n | Newline |
-i 'cond' | If — bedingt |
-N prefix=URI | Namespace binden |
ed — Editieren in-place oder pipe
Knoten ändern, einfügen, löschen — ohne XSLT-Stylesheet, direkt auf der Shell.
# Attribut auf alle persName setzen, in-place
xmlstarlet ed --inplace \
-u '//persName[not(@cert)]/@cert' -v 'high' \
datei.xml
# Wenn das Attribut noch nicht existiert: erst inserten
xmlstarlet ed --inplace \
-i '//persName[not(@cert)]' -t attr -n 'cert' -v 'high' \
datei.xml
# Alle TODO-Kommentare löschen
xmlstarlet ed --inplace \
-d '//note[@type="todo"]' \
datei.xml
# Element umbenennen
xmlstarlet ed --inplace \
-r '//placename' -v 'placeName' \
datei.xml
# Knoten am Ende einfügen
xmlstarlet ed --inplace \
-s '//body' -t elem -n 'div' -v 'Anhang' \
datei.xml
# Mehrere Operationen verkettet
xmlstarlet ed \
-d '//note[@type="todo"]' \
-u '//persName[not(@cert)]/@cert' -v 'high' \
datei.xml > datei-bereinigt.xml
-d (delete), -u (update), -i (insert), -a (append), -s (subnode), -r (rename), -m (move). Die Kombination mit XPath erlaubt sehr präzise Massen-Eingriffe — was in einem Editor 200 manuelle Klicks wären, ist hier ein Einzeiler.
val — Schema-Validierung
# Gegen XSD validieren
xmlstarlet val --xsd schema.xsd datei.xml
# Gegen DTD (DOCTYPE-Eintrag in der Datei oder explizit)
xmlstarlet val --dtd model.dtd datei.xml
# Gegen RelaxNG (relevant für TEI)
xmlstarlet val --relaxng tei_all.rng datei.xml
# Mehrere Dateien batch
xmlstarlet val --relaxng tei_all.rng *.xml
# → Output: "datei.xml - valid" oder Fehlermeldung mit Zeilennummer
Für TEI-Validierung gegen das Customization-Schema ist xmlstarlet val --relaxng <schema>.rng der schnellste Weg im CI/CD-Setup. Saubere Exit-Codes (0 = valid, >0 = invalid) machen es shell-script-tauglich.
tr — XSLT-Transformation
# Stylesheet anwenden
xmlstarlet tr stylesheet.xsl datei.xml > output.html
# Mit Parametern
xmlstarlet tr stylesheet.xsl -s lang=de datei.xml
# In Pipeline (XSLT-Output direkt weiterverarbeiten)
xmlstarlet tr to-csv.xsl edition.xml | xsv stats
xmlstarlet nutzt libxslt; das ist XSLT 1.0 mit EXSLT-Erweiterungen. Für XSLT 2.0/3.0 braucht es Saxon — dort steigt man typisch aus xmlstarlet tr aus.
fo — Pretty-Print und Encoding
# Pretty-Print
xmlstarlet fo datei.xml > formatted.xml
# Pretty-Print mit Tab-Einrückung statt Leerzeichen
xmlstarlet fo --indent-tab datei.xml
# Encoding ändern
xmlstarlet fo -e UTF-8 latin1.xml > utf8.xml
# Kompakt (eine Zeile)
xmlstarlet fo --omit-decl --indent-spaces 0 datei.xml
# Mit XML-Deklaration weglassen (für Snippet-Generation)
xmlstarlet fo --omit-decl datei.xml
fo ist auch der schnellste Weg, eine kaputt formatierte XML-Datei lesbar zu machen — gerade nach OAI-PMH-Output oder Tools, die alles in eine Zeile schreiben.
c14n — Kanonisierung
# XML-Canonical-Form (für digitale Signaturen, Diff-Vergleiche)
xmlstarlet c14n datei.xml
# Mit Kommentaren
xmlstarlet c14n --with-comments datei.xml
Relevant, wenn man zwei XML-Dateien semantisch vergleichen will, ohne durch Whitespace-Unterschiede oder Attribut-Reihenfolge gestört zu werden.
Pipeline-Patterns
xmlstarlet glänzt in der Kombination mit anderen Unix-Tools:
# Alle persName aus allen TEI-Dateien, deduplizieren, zählen
xmlstarlet sel -N t='http://www.tei-c.org/ns/1.0' \
-t -v '//t:persName' -n *.xml \
| sort | uniq -c | sort -rn | head -20
# Validieren und nur invalide Dateien melden
for f in *.xml; do
xmlstarlet val --relaxng tei.rng "$f" 2>&1 \
| grep -v ' - valid$'
done
# Massen-Update der GND-IDs aus einer Konkordanz-Tabelle
while IFS=$'\t' read -r oldid newid; do
xmlstarlet ed --inplace \
-u "//persName[@ref='gnd:$oldid']/@ref" \
-v "gnd:$newid" \
*.xml
done < konkordanz.tsv
# Aus TEI eine CSV mit Personenliste generieren
xmlstarlet sel -N t='http://www.tei-c.org/ns/1.0' \
-t -m '//t:listPerson/t:person' \
-v '@xml:id' -o ',' \
-v 't:persName' -o ',' \
-v 't:birth/@when' -o ',' \
-v 't:death/@when' \
-n datei.tei.xml > personen.csv
# OAI-PMH-Records pro Set ausgeben
xmlstarlet sel -N o='http://www.openarchives.org/OAI/2.0/' \
-t -m '//o:record' -c '.' -n harvest.xml \
| xmlstarlet fo --omit-decl
Namespaces — der Klassiker
Jede TEI-, EAD-, METS-, MODS-Datei kommt mit Default-Namespace. Wer //persName schreibt, matcht nichts. Lösungen:
# 1. Präfix binden (sauber)
xmlstarlet sel -N t='http://www.tei-c.org/ns/1.0' \
-t -v '//t:persName' datei.xml
# 2. local-name() (pragmatisch, aber ohne Namespace-Prüfung)
xmlstarlet sel -t -v '//*[local-name()="persName"]' datei.xml
# 3. Wildcard-Namespace (xmlstarlet-spezifisch, *:name)
xmlstarlet sel -t -v '//*:persName' datei.xml
Die saubere Variante ist immer die mit gebundenem Präfix.
Häufige Fallen
- Namespace vergessen — der häufigste Fehler. Test:
xmlstarlet sel -t -v '//*' datei.xml | headzeigt, ob überhaupt Knoten gematcht werden. -uohne existierendes Attribut —-uupdatet nur, schafft kein neues Attribut. Erst mit-i ... -t attreinfügen.- In-Place-Edit ohne Backup —
--inplaceschreibt direkt in die Datei. Vor Massen-Operationen Sicherheitskopie oder Git-Status prüfen. - macOS vs. GNU xmlstarlet — kleinere Unterschiede beim
-i-Flag-Verhalten und beim Encoding-Default. Im Zweifel denxmlstarlet-Manpage des eigenen Systems lesen. - Single-Quote-Hölle — Komplexe XPath-Ausdrücke mit Apostrophen in der Shell quoting-empfindlich.
$'...'-Strings (Bash) oder Heredoc-Stylesheets sind entlastend. - Output-Encoding — bei mehrzeiligen Strings im XML defaultmässig UTF-8. Bei alten Latin-1-Dateien explizit
-e UTF-8beimfo. - Riesige Dateien — xmlstarlet liest die ganze Datei in den Speicher (libxml2 DOM). Für mehrere GB grosse XML lieber SAX-Parser in Python (
xml.sax) oder xmllint —stream. - XSLT 2.0+ Funktionen —
xmlstarlet trist 1.0. Nutzungs-Versuche mitxs:date()o. ä. scheitern stillschweigend. Für 2.0+ Saxon nutzen.
Verhältnis zu anderen Werkzeugen
- XPath — die Sprache, die xmlstarlet ausführt; das eine ergänzt das andere.
xmllint(libxml2) — kann auch validieren und XPath; weniger Komfort beim Editieren.xq(yq) — JSON/YAML/XML mit jq-ähnlicher Syntax; gut für gemischte JSON/XML-Pipelines.xmlsh— älteres XML-Shell-Projekt, weniger verbreitet.- Saxon (
saxon-he,saxon-ee) — für XPath/XSLT 2.0/3.x; in CI/CD oft parallel zu xmlstarlet. pup/htmlq— analoges Tool für HTML mit CSS-Selektoren.- Pandoc — für Format-Transformation Text-orientiert; ergänzt xmlstarlet, ersetzt es nicht.
- OpenRefine — für tabellarische Daten; xmlstarlet ergänzt für XML.
- Regex — komplementär; Regex für Text, xmlstarlet für strukturierte XML-Bäume. Häufig in derselben Pipeline.