Úvod
Když právní týmy nebo forenzní analytici potřebují prokázat, že dokument nebyl pozměněn, pouhý pohled na viditelný obsah nestačí. Skryté vlastnosti – například autor, datum vytvoření nebo číslo revize – mohou odhalit, kdo soubor upravil a kdy. Detekce těchto jemných změn napříč verzemi dokumentu je častý problém, který často vyžaduje ruční kontrolu každé vlastnosti, což je časově náročné a náchylné k chybám.
GroupDocs.Metadata pro Java poskytuje programatický způsob, jak získat všechna metadata a vypočítat strukturovaný rozdíl mezi dvěma verzemi. V tomto tutoriálu porovnáme tři praktické přístupy: úplný rozdíl metadat, zaměření na změny vlastnictví a analýzu historie revizí. Každá metoda je demonstrována stručným, připraveným k zkopírování kódem a také ukážeme, jak exportovat výsledky do CSV nebo JSON pro auditní zprávy.
Setkal jsem se s tím při revizi smlouvy, kterou během několika měsíců upravovalo více stran; viditelný text vypadal identicky, ale pole vlastnictví se tiše změnila.
Jak zjistit, které metadata se změnila mezi dvěma verzemi dokumentu?
GroupDocs.Metadata načte každý soubor, extrahuje všechna přístupná vlastnosti do mapy a poté iteruje přes klíče, aby klasifikoval přidané, odebrané a upravené položky. Knihovna zvládá vestavěné i vlastní značky, takže získáte kompletní obrázek bez psaní formátově specifických parserů. Výsledkem je objekt MetadataDiff, který můžete dotazovat nebo serializovat pro souladové zprávy.
Požadavky
- Java 8 nebo novější
- GroupDocs.Metadata pro Java 24.7 ([dočasná licence][TEMP_LICENSE_URL])
- Dva soubory dokumentů, které chcete porovnat (např.
contract_v1.pdfacontract_v2.pdf)
Instalace
Přidejte závislost přes Maven:
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-metadata</artifactId>
<version>24.7</version>
</dependency>
Metoda 1 – Úplný rozdíl metadat
Tato metoda extrahuje všechna metadata z obou verzí a hlásí přidané, odebrané i změněné položky.
// CompareMetadataSets.run – returns a MetadataDiff object
Map<String, String> v1 = ExtractAllMetadata.run(pathV1);
Map<String, String> v2 = ExtractAllMetadata.run(pathV2);
MetadataDiff diff = new MetadataDiff();
// Detect added and changed properties
for (Map.Entry<String, String> e : v2.entrySet()) {
String key = e.getKey();
String val = e.getValue();
if (!v1.containsKey(key)) {
diff.added.put(key, val); // New property in v2
} else if (!v1.get(key).equals(val)) {
diff.changed.put(key, new String[]{v1.get(key), val}); // Value changed
}
}
// Detect removed properties
for (Map.Entry<String, String> e : v1.entrySet()) {
if (!v2.containsKey(e.getKey())) {
diff.removed.put(e.getKey(), e.getValue());
}
}
return diff;
Klíčové body:
- Komplexní: Zachytí všechny značky, včetně vlastních.
- Jednoduchá logika map: Není potřeba externí knihovna pro rozdíly.
- Objekt výsledku: Mapy
added,removedachangedjsou připraveny k dalšímu zpracování.
💡 Tip: Použijte, když potřebujete úplný auditní záznam pro regulatorní soulad.
Metoda 2 – Detekce změn vlastnictví
Právní spory často závisí na tom, kdo dokument vytvořil nebo upravil. Tato metoda se zaměřuje na osobní značky jako Creator, Editor, Manager a Company.
// DetectOwnershipChanges.run – returns a map of changed ownership fields
Map<String, String> v1 = readOwnership(pathV1);
Map<String, String> v2 = readOwnership(pathV2);
Set<String> allKeys = new HashSet<>(v1.keySet());
allKeys.addAll(v2.keySet());
Map<String, String[]> changes = new LinkedHashMap<>();
for (String key : allKeys) {
String oldVal = v1.getOrDefault(key, "<missing>");
String newVal = v2.getOrDefault(key, "<missing>");
if (!oldVal.equals(newVal)) {
changes.put(key, new String[]{oldVal, newVal});
}
}
return changes;
readOwnership načte pouze relevantní značky:
Map<String, String> result = new LinkedHashMap<>();
try (Metadata metadata = new Metadata(path)) {
if (metadata.getFileFormat() == FileFormat.Unknown) return result;
for (MetadataProperty p : metadata.findProperties(
new ContainsTagSpecification(Tags.getPerson().getCreator())
.or(new ContainsTagSpecification(Tags.getPerson().getEditor()))
.or(new ContainsTagSpecification(Tags.getPerson().getManager()))
.or(new ContainsTagSpecification(Tags.getCorporate().getCompany())))) {
String value = "";
if (p.getValue() != null && p.getValue().getRawValue() != null) {
value = String.valueOf(p.getValue().getRawValue());
}
result.put(p.getName(), value);
}
}
return result;
Klíčové body:
- Cílené: Zkoumá jen vlastnosti související s identitou.
- Přehledný výstup: Vrací mapu, kde každý záznam ukazuje hodnoty
[old, new]. - Připravené pro soulad: Ideální pro e‑discovery nebo spory o vlastnictví smluv.
💡 Tip: Kombinujte s úplným rozdílem, pokud potřebujete jak šířku, tak hloubku.
Metoda 3 – Detekce změn v historii revizí
Čísla revizí, časové razítka úprav a data tisku jsou pro koncové uživatele neviditelné, ale jsou klíčová pro forenzní časové osy. Tato metoda izoluje časově související značky.
Map<String, String> v1 = readRevision(pathV1);
Map<String, String> v2 = readRevision(pathV2);
Set<String> allKeys = new HashSet<>(v1.keySet());
allKeys.addAll(v2.keySet());
Map<String, String[]> changes = new LinkedHashMap<>();
for (String key : allKeys) {
String oldVal = v1.getOrDefault(key, "<missing>");
String newVal = v2.getOrDefault(key, "<missing>");
if (!oldVal.equals(newVal)) {
changes.put(key, new String[]{oldVal, newVal});
}
}
return changes;
readRevision extrahuje časová razítka Modified, Created a Printed:
Map<String, String> result = new LinkedHashMap<>();
try (Metadata metadata = new Metadata(path)) {
if (metadata.getFileFormat() == FileFormat.Unknown) return