CommunityCodierung & Entwicklunggithub.com

wintersdragon-c/office-docx-skills

Agent-Fähigkeit zum Bearbeiten von .docx-Dateien mit Microsoft Word-Änderungsnachverfolgung (Track Changes).

Was ist office-docx-skills?

Diese Fähigkeit ermöglicht es KI-Agenten, .docx-Dateien programmatisch so zu bearbeiten, dass alle Änderungen als überarbeitete Versionen in Microsoft Word erscheinen (Änderungsnachverfolgung). Löschungen werden rot durchgestrichen, Einfügungen rot unterstrichen, mit Autor- und Datumsmetadaten im Randbereich. Im Gegensatz zu `python-docx`, das keine Änderungsnachverfolgung unterstützt, arbeitet diese Fähigkeit direkt mit der OOXML-Struktur (`w:ins` / `w:del`-Elemente) über `lxml`. Sie ist ideal für Szenarien, in denen Autoren Änderungen einzeln annehmen oder ablehnen müssen, z. B. bei Manuskript-Review-Prozessen. Wichtige Einschränkungen: Sie bearbeitet nur den Haupttext (nicht Kopf-/Fußzeilen oder Fußnoten), erfordert die eindeutige Verwaltung von Revisions-IDs und warnt vor häufigen Fehlern wie dem Überschreiben vorheriger Änderungen oder dem Einfügen von Referenztext an falscher Stelle.

Funktioniert mit✓Claude Code✓Codex CLI~Cursor
npx skills add wintersdragon-c/office-docx-skills

Installed? Explore more Codierung & Entwicklung skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Bearbeiten von .docx mit Word-Änderungsnachverfolgung (Revisionsmodus)

Übersicht

Bearbeiten Sie .docx-Dateien programmatisch, sodass Änderungen als überarbeitete Versionen in Microsoft Word erscheinen – Löschungen als rote Durchstreichungen, Einfügungen als rote Unterstreichungen, mit Autor-/Datumsmetadaten im Seitenrand. Dies nutzt direkte XML-Manipulation der OOXML-Elemente w:ins / w:del über lxml, NICHT die High-Level-API von python-docx (die keine Unterstützung für Änderungsnachverfolgung bietet).

Abhängigkeiten

pip install python-docx lxml
  • python-docx >= 1.2.0 – nur für die anfängliche Inspektion (Absatzstile, Laufschriftformatierung). NICHT für die eigentlichen Schreibvorgänge mit Änderungsnachverfolgung verwendet.
  • lxml >= 5.0 – das eigentliche Arbeitstier; parst und modifiziert word/document.xml innerhalb des .docx-Zip-Archivs.

Beide sind reine Python-Installationen ohne Systemabhängigkeiten.

Wann verwenden

  • Der Benutzer möchte eine .docx-Datei bearbeiten und die Änderungen in Word SEHEN (Änderungsnachverfolgung)
  • Der Benutzer muss ein überarbeitetes Manuskript senden, bei dem Gutachter einzelne Änderungen annehmen/ablehnen können
  • Jedes Szenario, in dem direkte Textersetzung in .docx nicht ausreicht, weil der Änderungsverlauf wichtig ist

Wann NICHT verwenden

  • Der Benutzer möchte lediglich den endgültigen Text ersetzen (keine Revisionsmarkierungen erforderlich) – dann direkt python-docx verwenden
  • Die Datei ist .doc (altes Binärformat) – nicht unterstützt
  • Der Benutzer möchte Kopf-/Fußzeilen/Fußnoten mit Änderungsnachverfolgung bearbeiten – diese Technik deckt nur Textkörperabsätze ab

Funktioniert mit

Diese Fähigkeit kann allein oder zusammen mit anderen Fähigkeiten in office-docx-skills verwendet werden.

  • Verwenden Sie sie mit word-default-formatting, wenn der überarbeitete Text auch dem Standard-Word-Formatierungsprofil des Pakets folgen soll.
  • Verwenden Sie sie mit word-formula-writing, wenn formelbezogene Bearbeitungen als Word-native bearbeitbare Gleichungen und sichtbare Revisionsmarkierungen dargestellt werden sollen.
  • Wenn sowohl Formatierung als auch Formeln wichtig sind, verwenden Sie alle drei Fähigkeiten zusammen.

OOXML-Struktur der Änderungsnachverfolgung

Eine .docx-Datei ist ein Zip-Archiv, das word/document.xml enthält. Änderungen in der Nachverfolgung verwenden zwei Wrapperelemente um w:r-Elemente (Laufschrift) innerhalb von w:p (Absatz):

<!-- Löschung: umschließt ursprüngliche Laufschriften, Text-Tag wird zu w:delText -->
<w:del w:id="102" w:author="Claude" w:date="2026-04-17T10:00:00Z">
  <w:r>
    <w:rPr><!-- ursprüngliche Formatierung bleibt erhalten --></w:rPr>
    <w:delText xml:space="preserve">alter Text hier</w:delText>
  </w:r>
</w:del>

<!-- Einfügung: umschließt neue Laufschrift mit kopierter Formatierung -->
<w:ins w:id="103" w:author="Claude" w:date="2026-04-17T10:00:00Z">
  <w:r>
    <w:rPr><!-- von der ursprünglichen Laufschrift kopiert --></w:rPr>
    <w:t xml:space="preserve">neuer Text hier</w:t>
  </w:r>
</w:ins>

Wichtige Regeln:

  • w:del und w:ins sind direkte Kinder von w:p, Geschwister von w:pPr
  • Jedes benötigt eine eindeutige w:id (ganze Zahl, darf nicht mit vorhandenen IDs im Dokument kollidieren)
  • w:author und w:date füllen die Randannotation in Word
  • Innerhalb von w:del MÜSSEN Textelemente w:delText sein (nicht w:t)
  • Innerhalb von w:ins sind Textelemente normale w:t
  • Laufschrifteigenschaften (w:rPr) müssen von den ursprünglichen Laufschriften kopiert werden, um Schriftart/-größe/Fettschrift zu erhalten

Kernimplementierung

Die wiederverwendbare Implementierung befindet sich in tracked_change_editor.py neben dieser Fähigkeit. Kopieren Sie diesen Helfer in Ihr Arbeitsverzeichnis, wenn Sie Code möchten, den Sie direkt importieren können.

from tracked_change_editor import TrackedChangeEditor

editor = TrackedChangeEditor('input.docx', author='Ihr Name')

for i, p in enumerate(editor.body_paras):
    if 'Zieltext' in editor._get_para_text(p):
        editor.replace_paragraph_text(i, 'Ersatztext')
        break

editor.save('output.docx')

tracked_change_editor.py übernimmt die wichtigen Abläufe:

  • scannt vorhandene Revisions-IDs, bevor neue w:ins / w:del-Knoten erstellt werden
  • bewahrt die Absatzformatierung durch Klonen der Standard-w:rPr des Absatzes
  • schreibt über eine sichere temporäre Datei, bevor zur endgültigen .docx-Datei gewechselt wird

Verwendungsablauf

editor = TrackedChangeEditor('input.docx', author='Ihr Name')

# Zielabsatz anhand des Textinhalts finden
for i, p in enumerate(editor.body_paras):
    if 'Zieltext' in editor._get_para_text(p):
        editor.replace_paragraph_text(i, 'Ersatztext')
        break

editor.save('output.docx')  # Immer zuerst in einer NEUEN Datei speichern

Kritische Fallstricke – VOR DEM BEARBEITEN LESEN

0. ALLE Bearbeitungen in EINEM Skript oder Verkettung ab der letzten gespeicherten Datei

Wenn Sie 7 Bearbeitungen vornehmen müssen, führen Sie sie ALLE in einem einzigen Skriptdurchlauf gegen eine einzige TrackedChangeEditor-Instanz aus und speichern Sie dann einmal. Tun Sie NICHT:

  • Skript A ausführen → in _revised.docx speichern
  • Skript B gegen die ORIGINALDATEI ausführen → in _revised.docx speichern (überschreibt die Arbeit von Skript A)

Wenn Sie auf mehrere Skriptdurchläufe aufteilen müssen, MUSS jeder nachfolgende Durchlauf von der vorherigen Ausgabe laden:

# Runde 1
editor = TrackedChangeEditor('original.docx')
# ... Bearbeitungen ...
editor.save('revised.docx')

# Runde 2 – von revised laden, NICHT vom Original
editor2 = TrackedChangeEditor('revised.docx')
# ... weitere Bearbeitungen ...
editor2.save('revised.docx')

Warum das wichtig ist: Das Laden von der Originaldatei verwirft alle Änderungsnachverfolgungen aus vorherigen Runden. Dies ist der mit Abstand häufigste Fehler – er verwirft stillschweigend Arbeit ohne Fehlermeldung.

0b. Einfügen neuer Absätze: DEN ABSCHNITT finden, nicht nur den Text

Wenn Sie einen neuen Absatz einfügen (z. B. einen Literaturverweiseintrag), durchsuchen Sie NIEMALS das gesamte Dokument nach einer Textübereinstimmung. Textzitate im Fließtext enthalten dieselben Autorennamen wie Literaturverweiseinträge. Eine naive Suche wie if 'Acharya' in text findet zuerst einen Fließtextabsatz und fügt den Verweis in der Mitte von Abschnitt 2 ein.

Richtiger Ansatz – zuerst die Abschnittsgrenze finden:

# Finden, wo der Literaturverweisabschnitt beginnt
refs_start_idx = None
for i, p in enumerate(editor.body_paras):
    t = editor._get_para_text(p)
    if t.strip() == 'Literaturverzeichnis':
        refs_start_idx = i
        break

# Nur INNERHALB des Literaturverzeichnisses suchen
for i in range(refs_start_idx + 1, len(editor.body_paras)):
    t = editor._get_para_text(editor.body_paras[i])
    if t.startswith('Acharya') and 'Johnson' in t:
        # Nach diesem Absatz einfügen
        break

Warum das wichtig ist: Autorennamen erscheinen sowohl in Textzitaten als auch in Literaturverweiseinträgen. Ohne abschnittsbewusste Suche landen neue Verweisabsätze im Fließtext – eine Verfälschung, die schwer zu erkennen ist, bis der Benutzer Word öffnet.

0c. Absätze in wissenschaftlichen Arbeiten umschreiben: ALLE Zitate bewahren

Beim Ersetzen des Textes eines Absatzes MÜSSEN Sie jedes (Autor Jahr)-Zitat aus dem Original bewahren. Wissenschaftliche Arbeiten haben ein Literaturverzeichnis, das mit den Textzitaten übereinstimmen muss – das Weglassen eines Zitats verwaist den Verweiseintrag oder schwächt das Argument.

Richtiger Ansatz – vor dem Umschreiben extrahieren:

import re
alter_text = editor._get_para_text(editor.body_paras[idx])
alte_zitate = re.findall(r'\([^)]*\d{4}[a-z]?\)', alter_text)
# Neuen Text schreiben und sicherstellen, dass jedes Element in alte_zitate vorkommt
# Nach dem Schreiben überprüfen:
for z in alte_zitate:
    assert z in neuer_text, f'ZITAT VERLOREN: {z}'

Warum das wichtig ist: Eine umgeschriebene Einleitung, die (Malmendier und Nagel 2011; Choi, Gao und Jiang 2020) weglässt, zerstört stillschweigend die Zitatintegrität der Arbeit. Das Literaturverzeichnis enthält diese Einträge noch, aber nichts im Text verweist auf sie. Gutachter und Lektoren werden dies beanstanden.

1. Absätze mit vorhandenen Änderungsnachverfolgungen

Wenn ein Absatz bereits w:ins/w:del aus vorherigen Bearbeitungen enthält, erfasst _collect_direct_runs nur direkte w:r-Kinder – Laufschriften innerhalb vorhandener w:ins/w:del-Wrapper werden übersprungen. Dies vermeidet Verschachtelung von Revisionen, bedeutet aber, dass der Ersatz nur den „akzeptierten“ Textteil abdeckt. Bei Absätzen mit umfangreichen vorherigen Revisionen akzeptieren Sie zuerst alle Änderungen in Word und bearbeiten dann erneut.

2. Immer in einer neuen Datei speichern

Überschreiben Sie niemals das Original. Speichern Sie als _revised.docx, lassen Sie den Benutzer in Word überprüfen und ersetzen Sie dann manuell.

3. Inhaltsverzeichnis wird nicht automatisch aktualisiert

python-docx / lxml kann Words Inhaltsverzeichnis nicht aktualisieren. Nach der Bearbeitung muss der Benutzer in Word öffnen → Rechtsklick auf das Inhaltsverzeichnis → Feld aktualisieren.

4. Eindeutigkeit der Revisions-ID

Die Methode _find_max_id() scannt alle vorhandenen w:ins, w:del, w:rPrChange, w:pPrChange, w:sectPrChange-Elemente. Neue IDs werden ab dem Maximum inkrementiert. Wenn IDs kollidieren, kann Word den Revisionsverlauf beschädigen.

5. Formatierung bewahren

_get_default_rpr klont das w:rPr aus der ersten Laufschrift im Absatz. Dies funktioniert für Absätze mit einheitlicher Formatierung. Bei Absätzen mit gemischter Formatierung (z. B. fett „Schlüsselwörter:" gefolgt von normalem Text) führen Sie einen chirurgischen, laufschriftweisen Ersatz durch, anstatt den gesamten Absatz zu ersetzen.

6. Wiedergabetreue

Das Speichern über lxml erzeugt geringfügige kosmetische XML-Unterschiede (Anführungszeichenstil " vs. ', Zeilenenden \r\n vs. \n). Inhalt und Formatierung bleiben erhalten. Die Dateigröße kann aufgrund der Zip-Komprimierungsstufe abweichen – dies ist harmlos.

Überprüfungscheckliste

Nach dem Speichern in Word öffnen und bestätigen:

  • Gelöschter Text wird rot durchgestrichen angezeigt
  • Eingefügter Text wird rot unterstrichen angezeigt
  • Autorname erscheint in den Randanmerkungen
  • Umgebende Absätze behalten die ursprüngliche Formatierung
  • Keine doppelten oder verschachtelten Revisionsmarkierungen
  • Die Anzahl der Einfügungen für Ihren gewählten Autor entspricht den Erwartungen – führen Sie ein Überprüfungsskript aus, um w:ins mit Ihrem Autornamen zu zählen und die ersten 100 Zeichen jeder Einfügung auszugeben. Wenn die Anzahl geringer als erwartet ist, wurden vorherige Bearbeitungen verloren (siehe Fallstrick 0).
  • Keine Literaturverweiseinträge im Fließtext – scannen Sie Absätze vor der Überschrift „Literaturverzeichnis“ auf Absätze, die wie ein vollständiger bibliografischer Eintrag aussehen (Autor, Jahr, Zeitschrift, Band, Seiten). Wenn gefunden, wurde ein Verweis an der falschen Stelle eingefügt (siehe Fallstrick 0b).
# Überprüfungsausschnitt nach dem Speichern
ziel_autor = 'Codex'
with zipfile.ZipFile('output.docx') as z:
    xml = z.read('word/document.xml')
root = etree.fromstring(xml)
autor_ins = [e for e in root.findall('.//w:ins', nsmap)
              if e.get(qn('w:author')) == ziel_autor]
print(f'Einfügungen von {ziel_autor}: {len(autor_ins)}')
for i, ins in enumerate(autor_ins):
    texte = ''.join(t.text for t in ins.findall('.//w:t', nsmap) if t.text)
    print(f'  [{i+1}] {texte[:100]}')

Verwandte Skills