💡 Pełny działający przykład dostępny na GitHubie:
metadata-diff-doc-versions-using-groupdocs-metadata-nodejs

Wprowadzenie

Porównanie 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ę.

Zauważyłem 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.

Dlaczego ukryte metadane mają znaczenie dla zespołów prawnych

Profesjonaliści z zakresu prawa i zgodności opierają się 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 regulacyjne dotyczące ścieżek audytu.

Nasze rozwiązanie z GroupDocs.Metadata

GroupDocs.Metadata dla Node.js udostępnia jedną API, która wyciąga wszystkie obsługiwane właściwości, 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.

Krok 1 – Pobieranie wszystkich metadanych z dokumentu

Poniższy pomocnik otwiera plik, przechodzi po całym drzewie właściwości i zwraca zwykłą mapę JavaScript nazwa właściwości → wartość. Używa AnySpecification, aby przechwycić zarówno wbudowane, jak i niestandardowe pola.

/** 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.

Krok 2 – Wykrywanie różnic między dwoma wersjami

Gdy obie wersje są reprezentowane jako proste obiekty, procedura diff tworzy trzy koszyki — added, removed i changed — oraz udostępnia wygodny getter totalChanges.

/** 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;
    },
  };
}

Krok 3 – Wgląd w własność i historię wersji (opcjonalnie)

Wykrywanie zmian własności

Audytorzy prawni często koncentrują się na tym, kto utworzył lub edytował dokument. Ten pomocnik izoluje te pola i sygnalizuje każdą odmianę.

/** 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;
}

Wykrywanie zmian w historii wersji

Numer rewizji, całkowity czas edycji i znaczniki czasu ostatniego wydruku ujawniają ukrytą aktywność.

/** 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 (oldV !== newV) changes[k] = { from: oldV, to: newV };
  }
  return changes;
}

Krok 4 – Eksportowanie raportów audytu

Eksport CSV

Format CSV jest idealny do importu do Excela lub systemów SIEM. Pola są escapowane, aby obsłużyć przecinki i znaki nowej linii.

/** Export diff to CSV */
function exportDiffToCsv(diff, outputPath) {
  const rows = ['change_type,property,old_value,new_value'];
  for (const [k, v] of Object.entries(diff.added)) rows.push(`added,${esc(k)},,${esc(v)}`);
  for (const [k, v] of Object.entries(diff.removed)) rows.push(`removed,${esc(k)},${esc(v)},`);
  for (const [k, o] of Object.entries(diff.changed)) rows.push(`changed,${esc(k)},${esc(o.from)},${esc(o.to)}`);
  fs.writeFileSync(outputPath, rows.join('\n') + '\n', 'utf-8');
}

Eksport JSON

JSON zachowuje strukturę hierarchiczną, co ułatwia dalsze przetwarzanie programistyczne.

/** Export diff to JSON */
function exportDiffToJson(diff, outputPath) {
  const payload = { added: diff.added, removed: diff.removed, changed: diff.changed };
  fs.writeFileSync(outputPath, JSON.stringify(payload, null, 2), 'utf-8');
}

Pełny skrypt sterujący

Skrypt łączy wszystkie elementy, wypisuje krótkie podsumowanie i zapisuje raporty w formatach CSV oraz JSON.

const path = require('path');
const fs = require('fs');
const groupdocs = require('@groupdocs/groupdocs.metadata');

function esc(txt) { return /[",\n]/.test(txt) ? `"${txt.replace(/"/g, '""')}"` : txt; }

const diff = compareMetadataSets('resources/document-v1.docx', 'resources/document-v2.docx');
console.log(`Total metadata changes: ${diff.totalChanges}`);

exportDiffToCsv(diff, path.resolve('metadata-diff.csv'));
exportDiffToJson(diff, path.resolve('metadata-diff.json'));

Uruchomienie node index.js tworzy pliki metadata-diff.csv i metadata-diff.json w katalogu głównym projektu.

Jak porównać metadane między dwiema wersjami dokumentu?

Porównujesz metadane, ładując każdą rewizję przy pomocy klasy Metadata, wyciągając płaską mapę nazwa‑wartość za pomocą extractAllMetadata i przekazując dwie mapy do compareMetadataSets. Funkcja zwraca trzy kolekcje — added, removed i changed — oraz licznik totalChanges. Działa to dla każdego formatu obsługiwanego przez GroupDocs.Metadata (DOCX, PDF, XLSX, PPTX itp.) i kończy się w znacznie mniej niż sekundę dla typowych plików biurowych, co czyni je odpowiednimi do przetwarzania wsadowego lub integracji CI.

Wpływ na biznes

Metryka Proces ręczny Zautomatyzowane z GroupDocs.Metadata
Czas na dokument ~45 min (ręczna weryfikacja) <30 s (diff metadanych)
Wskaźnik błędów ~3 % pominiętych zmian 0 % – każda właściwość jest sprawdzona
Przepustowość 20 dok./dzień na recenzenta 1 000 + dok./dzień na skromnym VM
Ścieżka audytu Notatki ręczne Strukturalne logi CSV/JSON
Koszt $X / godzinę × N recenzentów Stała licencja, nieograniczone uruchomienia

Automatyzacja skraca czas przeglądu o ponad 99 %, eliminuje błędy ludzkie i dostarcza maszynowo czytelną ścieżkę audytu, którą można bezpośrednio zintegrować z pulpitami zgodności.

Rozpoczęcie pracy w Twoim środowisku

  1. Wypróbuj za darmo – uzyskaj tymczasową 30‑dniową licencję tutaj.
  2. Zainstaluj SDKnpm install @groupdocs/groupdocs.metadata.
  3. Uruchom przykład – sklonuj repozytorium z GitHub i wykonaj node index.js.
  4. Poznaj więcej – zapoznaj się z pełną dokumentacją API, aby korzystać z zaawansowanych filtrów i obsługi własnych właściwości.

Zasoby