DOCX-Erstellung, -Bearbeitung und -Analyse
Eine .docx-Datei ist ein ZIP-Archiv von XML-Dateien. Wähle den Ansatz je nach Aufgabe:
| Aufgabe | Ansatz |
|---|---|
| Erstellen eines neuen Dokuments | Ein docx-Skript (npm) schreiben – siehe Fallstricke unten |
| Bearbeiten eines vorhandenen Dokuments | unzip → word/document.xml bearbeiten → zip (docx-js kann keine vorhandenen Dateien öffnen) |
| Lesen von Inhalten | pandoc -t markdown file.docx |
Skriptpfade unten beziehen sich auf das Verzeichnis dieses Skills.
Erstellen mit docx-js – Fallstricke
docx ist vorinstalliert – nicht npm install ausführen; das Skript schreiben und direkt require('docx') verwenden. Nur wenn dieser require fehlschlägt: npm install docx. Das Modell kennt die API; hier sind die Stolpersteine:
- Seitengröße standardmäßig A4. Für US Letter
page: { size: { width: 12240, height: 15840 } }setzen (DXA; 1440 = 1″). - Querformat: Porträtmaße und
orientation: PageOrientation.LANDSCAPEübergeben – docx-js tauscht width/height intern aus. - Tabellen benötigen doppelte Breiten:
columnWidthsan der Tabelle UNDwidthan jeder Zelle setzen, beide inWidthType.DXA(PERCENTAGE bricht in Google Docs). Spaltenbreiten müssen der Tabellenbreite entsprechen. - Tabellenschattierung:
ShadingType.CLEARverwenden, niemalsSOLID(ergibt schwarz). - Listen: Niemals
•wörtlich einfügen; einenumbering-Konfiguration mitLevelFormat.BULLETverwenden. ImageRunbenötigttype:("png","jpg", …).PageBreakmuss innerhalb einesParagraphsein.- Nie
\nverwenden – separateParagraph-Elemente nutzen. - Inhaltsverzeichnis: Überschriften müssen die integrierten
HeadingLevel.*verwenden; benutzerdefinierte Überschriftenformate benötigenoutlineLevel, sonst erscheinen sie nicht. - Keine Tabelle als horizontale Linie verwenden – stattdessen einen Absatzrand unten nutzen.
- Punktführer / rechtsbündig in derselben Zeile:
PositionalTab(alignment: PositionalTabAlignment.RIGHT,leader: PositionalTabLeader.DOT) innerhalb einesTextRunverwenden, nicht wörtliche.oder Leerzeichen-Auffüllung.
Ausgabe überprüfen
Nach dem Schreiben einer .docx-Datei diese rendern und ansehen:
python scripts/office/soffice.py --headless --convert-to pdf output.docx
pdftoppm -jpeg -r 100 output.pdf page
ls page-*.jpg # dann die Bilder lesen
pdftoppm füllt Seitenzahlen auf die Breite der Seitenanzahl mit Nullen auf (page-01.jpg…page-12.jpg).
Vorhandene Dokumente bearbeiten
Legacy .doc-Dateien müssen zuerst konvertiert werden: python scripts/office/soffice.py --headless --convert-to docx file.doc.
unzip -q doc.docx -d unpacked/
find unpacked -type l -delete # Symlink-Einträge entfernen – docx von externen Parteien ist nicht vertrauenswürdig
python scripts/merge_runs.py unpacked/ # fragmentierte Runs zusammenführen, damit Text auffindbar ist
# unpacked/word/document.xml direkt bearbeiten – NICHT neu formatieren oder pretty-print
(cd unpacked && rm -f ../out.docx && zip -Xr ../out.docx .)
python scripts/office/validate.py out.docx --original doc.docx # XSD-Prüfungen; --auto-repair behebt häufige Probleme
# Änderungsverfolgung? --author "<der Name, unter dem geändert wurde>" hinzufügen, um zu prüfen, ob jede Bearbeitung nachverfolgt ist
Word verteilt Text über viele <w:r>-Runs (Revisions-IDs, Rechtschreibprüfungsmarkierungen), sodass ein im Dokument sichtbarer Ausdruck im XML oft nicht als zusammenhängende Zeichenkette existiert. merge_runs.py führt benachbarte, identisch formatierte Runs in word/document.xml zusammen, ohne Inhalt oder Darstellung zu ändern; es akzeptiert auch eine .docx-Datei direkt (python scripts/merge_runs.py doc.docx -o merged.docx).
Änderungsverfolgung: Beim Redlining mit --author "<der Name, unter dem geändert wurde>" validieren (benötigt --original) – es meldet jeden geänderten Text ohne umgebendes <w:ins>/<w:del>, was leicht versehentlich passiert und in der akzeptierten Ansicht unsichtbar ist. Runs in <w:ins>/<w:del> mit w:id-, w:author- und w:date-Attributen einschließen. Innerhalb von <w:del> heißt das Textelement <w:delText>, nicht <w:t>. Ein gelöschtes Absatzzeichen (<w:pPr><w:rPr><w:del w:id=".." w:author=".." w:date=".."/></w:rPr></w:pPr>) bedeutet „diesen Absatz mit dem nächsten zusammenführen“ – einen Absatz komplett zu löschen, bedeutet dies plus ein <w:del> um jeden Run. Das <w:del/> muss vor den anderen Kindern von rPr stehen; ihre Reihenfolge ist schemavorgegeben.
Um eine bereinigte Kopie mit allen akzeptierten Änderungen zu erstellen: python scripts/accept_changes.py in.docx out.docx.
Das Akzeptieren eines gelöschten Absatzzeichens sollte diesen Absatz mit dem darunterliegenden verbinden, sodass ein Absatz, dessen Runs alle gelöscht sind, verschwindet. Word tut dies; accept_changes.py und pandoc --track-changes=accept tun das nicht immer. Beide versagen auf die gleiche Weise – sie entfernen den gelöschten Text, lassen aber den leeren Absatz zurück, der als verlorener leerer Aufzählungspunkt erscheint, wenn er automatisch nummeriert war:
pandoc --track-changes=acceptverbindet die Absätze nie.accept_changes.py(LibreOffice) verbindet sie korrekt, außer wenn dem gelöschten Absatz ein leerer Abstandsabsatz folgt.
Ein leerer Aufzählungspunkt in einer der beiden Ansichten ist ein Artefakt dieser Ansicht, kein Fehler im Dokument. Absatzlöschungen im XML prüfen.
Kommentare
Kommentare erfordern sechs verknüpfte Dateien. Das Hilfsskript verwenden – Verzeichnismodus, wenn auch document.xml bearbeitet wird (spart einen Unzip/Rezip-Zyklus), .docx-Direktmodus sonst:
# Gegen ein bereits entpacktes Verzeichnis (bevorzugt, wenn auch Marker gesetzt werden)
python scripts/comment.py unpacked/ "Gebühren- und Kostendeckelung zu niedrig"
python scripts/comment.py unpacked/ "Einverstanden" --parent 0
# Gegen eine .docx-Datei direkt
python scripts/comment.py vertrag.docx "Dieser Deckel zu niedrig" -o annotiert.docx
Das Skript schreibt comments.xml, commentsExtended.xml, commentsIds.xml, commentsExtensible.xml, die Beziehungen und die Content-Type-Überschreibungen. Kommentar-IDs werden automatisch vergeben. Anschließend wird das <w:commentRangeStart>/<w:commentRangeEnd>/<w:commentReference>-Fragment ausgegeben, das in word/document.xml eingefügt werden muss, um den Kommentar an bestimmten Text zu binden – bis diese Marker platziert sind, existiert der Kommentar, ist aber nicht sichtbar.
Abhängigkeiten
docx (npm, vorinstalliert – nur installieren, wenn require('docx') fehlschlägt) · pandoc · LibreOffice (soffice) · pdftoppm (Poppler)