💡 Voll funktionsfähiges Beispiel auf GitHub verfügbar:
office-metadata-pii-cleanup-nodejs

Einführung

Ein Upload‑Endpunkt akzeptiert ein DOCX von einem Mitarbeitenden und speichert es zu einem Kundenticket. Der Text ist in Ordnung. Die Eigenschaften nicht: Die Datei enthält den Namen der Person, die sie erstellt hat, den Kollegen, der sie zuletzt gespeichert hat, den Abteilungsleiter aus der Unternehmensvorlage und, weil sie von SharePoint stammt, den Genehmiger, der sie freigegeben hat.

Ein Metadaten‑Sanitizer ist ein kleines Skript, das diese Eigenschaften löscht, bevor die Datei gespeichert wird, und anschließend seine eigene Arbeit überprüft. Dieses Tutorial erstellt ein solches Skript in Node.js mit GroupDocs.Metadata in vier Schritten: Eigenschaften nach Tag auswählen, nach Namen auswählen, alles löschen, wenn selektive Auswahl nicht mehr hilft, und das Ergebnis verifizieren. Jeder Schritt besteht aus wenigen Zeilen, und das fertige Skript hat weniger als hundert Zeilen.

Warum Metadaten‑Sanitisierung wichtig ist

Die Daten sammeln sich, ohne dass jemand sie auswählt. Word schreibt bei jedem Speichern Author und LastSavedBy aus dem Betriebssystem‑Konto, führt einen Versionszähler, protokolliert TotalEditingTime und speichert LastPrinted. Dokumenten‑Server fügen Workflow‑Pfade, Genehmiger‑Kennungen und Content‑Type‑URIs beim Einchecken hinzu. Keines dieser Elemente erscheint beim Lesen oder Drucken des Dokuments, sodass ein Korrekturlesen sie nie erfasst.

Der Vorteil, dies in Node.js statt von Hand zu erledigen, liegt darin, dass ein Skript Zahlen zurückgibt: Jeder Aufruf zum Entfernen meldet, wie viele Eigenschaften gelöscht wurden, und diese Zahl kann in ein Log geschrieben, in einem Test geprüft oder dem Datensatz, zu dem das Dokument gehört, angehängt werden.

Ein zweiter Grund, weniger offensichtlich, bis ein Batch‑Job läuft: Manuelle Bereinigung ist eine Entscheidung, die pro Datei von der jeweiligen Person getroffen wird, sodass zwei Personen, die dasselbe Dokument säubern, unterschiedliche Ergebnisse erzielen können. Ein Skript fixiert die Regel an einem Ort: dieselben vier Tags, dieselben Teilzeichenketten‑Listen, identisch angewendet, egal ob die Warteschlange drei Dateien oder dreitausend enthält.

Voraussetzungen

Das Paket ist Node.js über Java, daher benötigt die Maschine eine Java‑Runtime neben Node.

Installation

npm install @groupdocs/groupdocs.metadata

Das Beispielprojekt bindet Version 26.7 ein und fügt einen overrides‑Eintrag hinzu, der nan auf ^2.22.0 setzt, wodurch das native Binding auf aktuellen Node‑Versionen gebaut werden kann. Ohne Lizenzdatei läuft die Bibliothek im Evaluierungsmodus, was ausreicht, um jeden Schritt hier nachzuvollziehen.

Schritt 1 – Eigenschaften nach ihrer Bedeutung auswählen

Eigenschaftsnamen unterscheiden sich zwischen Formaten und Paketen, daher greift die erste Regel stattdessen auf Tags zurück. ContainsTagSpecification nimmt ein Tag und trifft auf jede Eigenschaft zu, die dieses trägt; .or() kombiniert Spezifikationen zu einer.

const T = groupdocs.Tags;
const spec = new groupdocs.ContainsTagSpecification(T.getPerson().getCreator())
  .or(new groupdocs.ContainsTagSpecification(T.getPerson().getEditor()))
  .or(new groupdocs.ContainsTagSpecification(T.getPerson().getManager()))
  .or(new groupdocs.ContainsTagSpecification(T.getCorporate().getCompany()));
const affected = metadata.removeProperties(spec);
metadata.save(outputPath);

Wichtige Punkte:

  • Vier Tags decken die Identitätsgruppe ab: Ersteller, Bearbeiter, Manager und das Unternehmensfeld.
  • Titel, Betreff und Schlüsselwörter bleiben unverändert, sodass ein Index, der darauf basiert, weiter funktioniert.
  • removeProperties gibt die Anzahl der betroffenen Eigenschaften zurück, nicht nur einen booleschen Wert.

Packen Sie das Ganze in try/finally mit metadata.close() im finally. Die Bindung hält die Datei bis dahin offen, und eine Schleife ohne Schließen läuft an Handles vorbei.

Schritt 2 – Eigenschaften nach Namen auswählen

Kommentar‑Threads, Versionszähler und Server‑Felder besitzen kein Tag. Für diese greift WithNameSpecification(needle, false), das jede Eigenschaft trifft, deren Name die Teilzeichenkette enthält; ein vierzeiliger Builder verkettet jeweils eine Teilzeichenkette:

let spec = null;
for (const needle of needles) {
  const s = new groupdocs.WithNameSpecification(needle, false /* fullMatch */);
  spec = spec ? spec.or(s) : s;
}
return spec;

Drei Durchläufe verwenden diesen Builder mit unterschiedlichen Listen. Kommentare zuerst:

const affected = metadata.removeProperties(
  nameContainsSpec(['Comment', 'Reviewer', 'Reviewed']));
metadata.save(outputPath);

Die Bearbeitungs‑Zeitlinie ist die Gruppe, die häufig vergessen wird, und sie beschreibt, wie das Dokument entstanden ist:

const affected = metadata.removeProperties(nameContainsSpec([
  'Revision', 'TrackedChange', 'LastPrinted', 'TotalEditingTime', 'EditTime',
]));
metadata.save(outputPath);

Der SharePoint‑Durchlauf ist derselbe Aufruf mit Server, Workflow, Approver, ContentType und Template. Das Teilzeichenketten‑Matching ist bewusst: Es erfasst CommentsCount neben Comment, ohne für jedes Format eine exakte Namensliste zu pflegen.

Schritt 3 – Alles löschen, wenn selektive Auswahl nicht mehr hilft

Für die Kopie, die das Unternehmen verlässt, ersetzt ein Aufruf die vier vorherigen Durchläufe:

const affected = metadata.sanitize();
metadata.save(outputPath);

sanitize() löscht jedes Metadaten‑Paket, das die Bibliothek erkennt, inklusive benutzerdefinierter OOXML‑Teile, und die zurückgegebene Anzahl übersteigt meist die Summe der gezielten Durchläufe. Es entfernt zudem Titel und Betreff, weshalb es am Rand und nicht in einer Prüfschleife eingesetzt werden sollte.

Schritt 4 – Überprüfen, weil ein stilles Versäumnis wie Erfolg aussieht

Der Scan verwendet dieselben Spezifikationen über findProperties, das nur liest. Das Ergebnis ist eine Java‑Collection, die per Index durchlaufen wird:

const props = metadata.findProperties(tagSpec.or(nameSpec));
for (let i = 0; i < props.getCount(); i++) {
  const p = props.get_Item(i);
  const val = p.getValue && p.getValue();
  const value = val ? String(val.getRawValue ? val.getRawValue() : val) : '';
  if (!value || value === '0' || value === '0.0') continue;
  leaks.push(`${p.getName()}=${value}`);
}

Der Filter für leere und Null‑Werte hat seinen Grund. Ich habe ihn hinzugefügt, nachdem ein Durchlauf wegen eines Versionszählers, der auf 0 zurückgesetzt war, fehlgeschlagen war – der Scan meldete diese Eigenschaft korrekt als noch vorhanden.

Vollständiges funktionierendes Beispiel

Das Repository verknüpft die sechs Funktionen in index.js, wendet die Lizenz an, führt jeden Durchlauf gegen resources/pii-sample.docx aus, prüft, dass jede Ausgabedatei existiert, und schließt mit der Assertion, dass die Leak‑Liste leer ist. Eine fehlgeschlagene Assertion beendet das Programm mit einem Nicht‑Null‑Code, sodass das Ganze als Check in CI funktioniert und nicht nur als Demo zum Lesen.

Ein Detail, das Sie in Ihre eigene Version übernehmen sollten: Jeder Durchlauf liest dieselbe Quelldatei und schreibt eine separate Ausgabe, anstatt eine bereits bereinigte Datei weiterzuverarbeiten. So bleiben die betroffenen Zähler unabhängig, und eine Log‑Zeile für den Kommentar‑Durchlauf gibt wieder, was die Kommentar‑Regel gefunden hat, und nicht, was nach dem Identitäts‑Durchlauf noch übrig war.

Wann sollte ich einen gezielten Durchlauf anstelle von sanitize() ausführen?

Immer, wenn das Dokument noch in Gebrauch ist. Dateien, die zwischen Gutachtern zirkulieren, benötigen Titel, Betreff und Schlüsselwörter für Suche und Klassifizierung, und sanitize() entfernt alle drei zusammen mit den personenbezogenen Daten. Führen Sie die Identitäts‑ und Kommentar‑Durchläufe während der Zusammenarbeit aus, behalten Sie die beschreibenden Felder bei und speichern Sie das vollständige Löschen für die Kopie, die das Unternehmen tatsächlich verlässt.

Anwendungen in der Praxis

Upload‑Handler

Eine Express‑Route säubert einen Anhang, bevor er gespeichert wird, protokolliert die betroffenen Zähler im Ticket und verwirft den Upload, wenn die Leak‑Liste nicht leer ist.

Nächtlicher Export‑Job

Ein Worker durchläuft einen Export‑Ordner, wendet die Identitäts‑ und Server‑Durchläufe an und lässt den Job fehlschlagen, anstatt nur eine Warnung zu loggen, wenn ein Dokument noch Rest‑PII meldet.

Pre‑Publikations‑Gate

Ein Build‑Schritt säubert Dokumentations‑Anhänge vor dem Release, verwendet sanitize(), weil in diesen Dateien keine Metadaten erhalten bleiben müssen.

Best Practices und Tipps

  • Schreiben Sie immer in einen neuen Pfad, damit das Original für Streitbeilegungen erhalten bleibt.
  • Schließen Sie das Metadaten‑Objekt in einem finally‑Block, besonders in Schleifen.
  • Kombinieren Sie Spezifikationen mit .or() in Batch‑Jobs; ein Öffnen und ein Speichern schlägt vier.
  • Loggen Sie die betroffene Anzahl pro Durchlauf, inklusive Nullen, damit ein nicht erkanntes Format sichtbar wird.

Fehlerbehebung bei häufigen Problemen

Die betroffene Anzahl ist Null bei einem Dokument, von dem Sie wissen, dass es „schmutzig“ ist
Stellen Sie sicher, dass das Eingabeformat erkannt wird, bevor Sie schließen, dass die Datei sauber war; eine nicht lesbare Datei und eine saubere Datei ergeben beide Null.

Der Leak‑Check meldet Eigenschaften, die Sie gerade entfernt haben
Richten Sie ihn auf den gespeicherten Ausgabepfad, nicht auf den Eingabepfad. Der Scan liest die Datei, die ihm übergeben wird.

Kommentar‑Ballons sind in Word noch sichtbar
Der Kommentartext befindet sich im Dokumentenkörper, nicht in einem Metadaten‑Paket. GroupDocs.Metadata löscht die kommentarbezogenen Eigenschaften; das Entfernen der Ballons selbst erfordert eine Inhalts‑Bearbeitungs‑Bibliothek wie Aspose.Words.

Fazit

Vier Schritte, sechs Funktionen, ein Skript, das berichtet, was es getan hat. Tag‑Spezifikationen behandeln die Identitätsgruppe über Formate hinweg, Namens‑Spezifikationen decken die Familien ab, die Tags nicht klassifizieren, sanitize() übernimmt die Grenze, und der Leak‑Scan verwandelt das Ganze in einen Check. Klonen Sie das Repository, führen Sie es gegen ein Dokument aus, das einen echten Review‑Durchlauf hinter sich hat, und schauen Sie sich die Zähler an, bevor Sie entscheiden, welche Durchläufe Ihre Pipeline benötigt.

Zusätzliche Ressourcen