💡 Esempio completo funzionante disponibile su GitHub:
office-metadata-pii-cleanup-nodejs
Introduzione
Un endpoint di upload accetta un DOCX da un membro del personale e lo memorizza in un ticket cliente. Il testo va bene. Le proprietà no: il file contiene il nome della persona che lo ha redatto, il collega che lo ha salvato per ultimo, il responsabile del dipartimento dal modello aziendale e, poiché proviene da SharePoint, l’approvatore che lo ha firmato.
Un sanitizzatore di metadati è un piccolo script che elimina quelle proprietà prima che il file venga memorizzato e poi verifica il proprio lavoro. Questo tutorial ne costruisce uno in Node.js con GroupDocs.Metadata, in quattro passaggi: selezionare le proprietà per tag, selezionarle per nome, cancellare tutto quando la selettività non aiuta più e verificare ciò che resta. Ogni passaggio è costituito da poche righe, e lo script completo è inferiore a cento righe.
Perché la sanitizzazione dei metadati è importante
I dati si accumulano senza che nessuno li scelga. Word scrive Author e LastSavedBy dall’account del sistema operativo ad ogni salvataggio, mantiene un contatore di revisioni, traccia TotalEditingTime e registra LastPrinted. I server di documenti aggiungono percorsi di workflow, identificatori di approvatori e URI di tipo contenuto al check‑in. Nessuna di queste informazioni appare quando il documento viene letto o stampato, quindi una revisione non le individua mai.
Il vantaggio di farlo in Node.js anziché manualmente è che uno script restituisce numeri: ogni chiamata di rimozione segnala quante proprietà ha eliminato, e quel conteggio può essere scritto in un log, verificato in un test o allegato al record a cui appartiene il documento.
C’è un secondo motivo, meno ovvio finché non si esegue un lavoro batch. La pulizia manuale è una decisione presa una volta per file da chiunque lo gestisca, quindi due persone che sanificano lo stesso tipo di documento producono risultati diversi. Uno script fissa la regola in un unico punto: gli stessi quattro tag, le stesse liste di sottostringhe, applicate identicamente sia che la coda contenga tre file sia tre mila.
Prerequisiti
Il pacchetto è Node.js tramite Java, quindi la macchina necessita di un runtime Java accanto a Node.
Installazione
npm install @groupdocs/groupdocs.metadata
Il progetto di esempio fissa la versione 26.7 e aggiunge una voce overrides che imposta nan a ^2.22.0, il che mantiene la compilazione del binding nativo sulle versioni attuali di Node. Senza un file di licenza la libreria funziona in modalità di valutazione, sufficiente per seguire tutti i passaggi qui descritti.
Passo 1 – Selezionare le proprietà per ciò che significano
I nomi delle proprietà differiscono tra formati e pacchetti, quindi la prima regola corrisponde ai tag. ContainsTagSpecification prende un tag e corrisponde a qualsiasi proprietà che lo contiene; .or() unisce le specifiche in una sola.
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);
Punti chiave:
- Quattro tag coprono il gruppo di identità: creatore, editore, manager e il campo aziendale.
- Titolo, Soggetto e Parole‑chiave rimangono intatti, così un indice di record che li utilizza continua a funzionare.
removePropertiesrestituisce il conteggio delle proprietà interessate anziché un valore booleano.
Avvolgi il tutto in try/finally con metadata.close() nel blocco finally. Il binding mantiene il file aperto fino a quel momento, e un ciclo senza di esso esaurisce le handle.
Passo 2 – Selezionare le proprietà per nome
I thread di commenti, i contatori di revisione e i campi del server non hanno tag. Per questi, WithNameSpecification(needle, false) corrisponde a qualsiasi proprietà il cui nome contiene la stringa needle, e un costruttore a quattro righe concatena una specifica per ogni sottostringa:
let spec = null;
for (const needle of needles) {
const s = new groupdocs.WithNameSpecification(needle, false /* fullMatch */);
spec = spec ? spec.or(s) : s;
}
return spec;
Tre passaggi riutilizzano quel costruttore con liste diverse. I commenti vanno per primi:
const affected = metadata.removeProperties(
nameContainsSpec(['Comment', 'Reviewer', 'Reviewed']));
metadata.save(outputPath);
La linea temporale di editing è il gruppo che tende a essere dimenticato, ed è quello che descrive come il documento è stato prodotto:
const affected = metadata.removeProperties(nameContainsSpec([
'Revision', 'TrackedChange', 'LastPrinted', 'TotalEditingTime', 'EditTime',
]));
metadata.save(outputPath);
Il passaggio SharePoint è la stessa chiamata con Server, Workflow, Approver, ContentType e Template. La corrispondenza per sottostringa è deliberata: cattura CommentsCount insieme a Comment senza dover mantenere una lista di nomi esatti per ogni formato.
Passo 3 – Cancellare tutto quando la selettività non aiuta più
Per la copia che lascia l’organizzazione, una chiamata sostituisce i quattro passaggi:
const affected = metadata.sanitize();
metadata.save(outputPath);
sanitize() elimina ogni pacchetto di metadati che la libreria rileva, inclusi i componenti OOXML personalizzati, e il suo conteggio supera solitamente la somma dei passaggi mirati. Rimuove anche Titolo e Soggetto, motivo per cui va eseguito al confine anziché in un ciclo di revisione.
Passo 4 – Verificare, perché una mancata rilevazione silenziosa sembra un successo
La scansione riutilizza le stesse specifiche tramite findProperties, che legge senza scrivere. Il risultato è una collezione Java, quindi viene percorsa per indice:
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}`);
}
Il filtro “vuoto e zero” guadagna il suo posto. L’ho aggiunto dopo che un’esecuzione è fallita su un contatore di revisione che era stato azzerato a 0, che la scansione segnalava fedelmente come proprietà residua.
Esempio completo funzionante
Il repository collega le sei funzioni in index.js, che applica la licenza, esegue ogni passaggio su resources/pii-sample.docx, verifica che ogni file di output esista e termina verificando che la lista delle perdite sia vuota. Un’asserzione fallita termina con un codice diverso da zero, così l’intero processo funge da controllo in CI anziché da demo da leggere.
Un dettaglio vale la pena copiare nella tua versione: ogni passaggio legge lo stesso file sorgente e scrive un output separato, anziché concatenare un file pulito al successivo. Questo mantiene i conteggi delle proprietà interessate indipendenti, così una riga di log per il passaggio dei commenti riporta ciò che la regola dei commenti ha trovato, non ciò che rimaneva dopo il passaggio di identità.
Quando dovrei eseguire un passaggio mirato invece di sanitize()?
Ogni volta che il documento è ancora in uso. I file che circolano tra revisori si basano su Titolo, Soggetto e Parole‑chiave per la ricerca e la classificazione, e sanitize() rimuove tutti e tre insieme ai dati personali. Esegui i passaggi di identità e commenti durante la collaborazione, mantieni intatti i campi descrittivi e riserva la cancellazione completa per la copia che effettivamente lascia l’organizzazione.
Applicazioni nel mondo reale
Gestore di upload
Una route Express sanifica un allegato prima di scriverlo nello storage, registra i conteggi delle proprietà interessate sul ticket e rifiuta l’upload quando la lista delle perdite non è vuota.
Job di esportazione notturna
Un worker attraversa una cartella di esportazione, applica i passaggi di identità e server, e fallisce il job invece di registrare un avviso quando un documento segnala ancora PII residua.
Porta di pre‑pubblicazione
Un passaggio di build sanifica gli allegati della documentazione prima del rilascio, usando sanitize() perché nulla in quei file necessita di conservare i propri metadati.
Buone pratiche e consigli
- Scrivi sempre su un percorso nuovo così l’originale rimane disponibile per eventuali contestazioni.
- Chiudi l’oggetto metadata in un blocco
finally, soprattutto nei cicli. - Unisci le specifiche con
.or()nei job batch; un’apertura e un salvataggio battono quattro. - Registra il conteggio delle proprietà interessate per ogni passaggio, inclusi gli zero, così un formato non riconosciuto è visibile.
Risoluzione dei problemi comuni
Il conteggio delle proprietà interessate è zero su un documento che sai essere “sporco”
Verifica che il formato di input sia riconosciuto prima di concludere che il file fosse pulito; un file non leggibile e un file pulito producono entrambi zero.
Il controllo delle perdite segnala proprietà che hai appena rimosso
Puntalo sul percorso di output salvato, non su quello di input. La scansione legge il file che le viene fornito.
I balloon dei commenti sono ancora visibili in Word
Il testo del commento vive nel corpo del documento, non in un pacchetto di metadati. GroupDocs.Metadata elimina le proprietà correlate ai commenti; la rimozione dei balloon stessi richiede una libreria di editing del contenuto come Aspose.Words.
Conclusione
Quattro passaggi, sei funzioni, uno script che riporta ciò che ha fatto. Le specifiche di tag gestiscono il gruppo di identità tra i formati, le specifiche di nome coprono le famiglie che i tag non classificano, sanitize() gestisce il confine e la scansione delle perdite trasforma il tutto in un controllo. Clona il repository, eseguilo su un documento che ha attraversato una vera fase di revisione e osserva i conteggi prima di decidere quali passaggi servono al tuo pipeline.