💡 Pełny działający przykład dostępny na GitHub: metadata-diff-doc-versions-using-groupdocs-metadata-nodejs
Introduction
Porównywanie metadanych to funkcja GroupDocs.Metadata, która ujawnia ukryte zmiany między wersjami dokumentów, umożliwiając audytorom szybkie zweryfikowanie autentyczności. Gdy zespoły prawne muszą udowodnić, że umowa nie została podrobiona, niewidoczne właściwości — autor, edytor, znaczniki czasu rewizji — często mówią prawdziwą historię.
Natrafiłem na ten problem, przeglądając zestaw umów dostawców; każdy plik deklarował tę samą datę utworzenia, ale pola ukrytego autora różniły się, a ręczna weryfikacja zajęłaby godziny.
Why hidden metadata matters for legal teams
Specjaliści ds. prawa i zgodności polegają na niezmiennych dowodach. Nawet jeśli widoczny tekst pozostaje taki sam, zmiana w polu Creator lub LastPrinted może wskazywać na nieautoryzowane edycje. Wczesne wykrycie tych zmian zapobiega kosztownym sporom i spełnia wymogi ścieżek audytu regulacyjnego.
Our solution with GroupDocs.Metadata
GroupDocs.Metadata dla Node.js oferuje jedyne API, które wyciąga każdą obsługiwaną właściwość, porównuje dwie rewizje i generuje ustrukturyzowane raporty różnic. SDK obsługuje DOCX, PDF, XLSX i wiele innych formatów od razu, więc nie potrzebujesz własnych parserów dla każdego typu pliku.
Step 1 – Pulling all metadata from a document
The helper below opens a file, walks the full property tree, and returns a plain JavaScript map of property name → value. It uses the AnySpecification to capture both built‑in and custom fields.
/** Extract all metadata from a file */
function extractAllMetadata(documentPath) {
const result = {};
const metadata = new groupdocs.Metadata(documentPath);
try {
const properties = metadata.findProperties(new groupdocs.AnySpecification());
for (let i = 0; i < properties.getCount(); i++) {
const p = properties.get_Item(i);
const name = p.getName();
const value = valueToString(p);
result[name] = value;
}
} finally {
metadata.close();
}
return result;
}
Uwaga dotycząca wydajności: wyodrębnianie metadanych z pliku DOCX o wielkości 5 MB zajmuje mniej niż 200 ms na typowym procesorze 2 GHz [Docs][DOCS_URL].
Step 2 – Spotting differences between two revisions
With both versions represented as plain objects, the diff routine builds three buckets—added, removed, and changed—and supplies a convenient totalChanges getter.
/** Compare two metadata maps */
function compareMetadataSets(pathV1, pathV2) {
const v1 = extractAllMetadata(pathV1);
const v2 = extractAllMetadata(pathV2);
const added = {};
const removed = {};
const changed = {};
for (const k of Object.keys(v2)) {
if (!(k in v1)) added[k] = v2[k];
else if (v1[k] !== v2[k]) changed[k] = { from: v1[k], to: v2[k] };
}
for (const k of Object.keys(v1)) {
if (!(k in v2)) removed[k] = v1[k];
}
return {
added,
removed,
changed,
get totalChanges() {
return Object.keys(this.added).length + Object.keys(this.removed).length + Object.keys(this.changed).length;
},
};
}
Step 3 – Ownership and revision insights (optional)
Detecting ownership changes
Legal auditors often focus on who created or edited a document. This helper isolates those fields and flags any variation.
/** Ownership change detection */
function detectOwnershipChanges(pathV1, pathV2) {
const v1 = readOwnership(pathV1);
const v2 = readOwnership(pathV2);
const all = new Set([...Object.keys(v1), ...Object.keys(v2)]);
const changes = {};
for (const k of all) {
const oldV = v1[k] !== undefined ? v1[k] : '<missing>';
const newV = v2[k] !== undefined ? v2[k] : '<missing>';
if (oldV !== newV) changes[k] = { from: oldV, to: newV };
}
return changes;
}
Detecting revision‑history changes
Revision number, total editing time, and last‑printed timestamps expose hidden activity.
/** Revision history change detection */
function detectRevisionHistory(pathV1, pathV2) {
const v1 = readRevision(pathV1);
const v2 = readRevision(pathV2);
const all = new Set([...Object.keys(v1), ...Object.keys(v2)]);
const changes = {};
for (const k of all) {
const oldV = v1[k] !== undefined ? v1[k] : '<missing>';
const newV = v2[k] !== undefined ? v2[k] : '<missing>';
if (old