Вступ
Коли юридичні команди або судові аналітики мають довести, що документ не був підроблений, простий перегляд видимого вмісту недостатній. Приховані властивості — такі як автор, дата створення або номер ревізії — можуть розкрити, хто і коли торкався файлу. Виявлення цих тонких змін між версіями документів є поширеною проблемою, яка часто вимагає ручної перевірки кожної властивості, що є трудомістким і схильним до помилок процесом.
GroupDocs.Metadata для Java надає програмний спосіб отримати всі поля метаданих і обчислити структурний diff між двома версіями. У цьому посібнику ми порівняємо три практичні підходи: повний diff метаданих, виявлення змін власності та аналіз історії ревізій. Кожен метод продемонстровано коротким, готовим до копіювання кодом, а також показано, як експортувати результати у CSV або JSON для аудиторської звітності.
Я зіткнувся з цим, переглядаючи контракт, який редагували кілька сторін протягом місяців; видимий текст був ідентичним, але поля власності змінилися без повідомлення.
Як визначити, які поля метаданих змінилися між двома версіями документу?
GroupDocs.Metadata завантажує кожен файл, витягує всі доступні властивості у карту і потім ітерує ключі, класифікуючи додані, видалені та змінені елементи. Бібліотека обробляє вбудовані та користувацькі теги, тому ви отримуєте повну картину без написання парсерів, специфічних для формату. Результатом є об’єкт MetadataDiff, який можна запитувати або серіалізувати для звітів про відповідність.
Передумови
- Java 8 або новіша
- GroupDocs.Metadata for Java 24.7 ([temporary license][TEMP_LICENSE_URL])
- Два документі, які потрібно порівняти (наприклад,
contract_v1.pdfіcontract_v2.pdf)
Встановлення
Додайте залежність через Maven:
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-metadata</artifactId>
<version>24.7</version>
</dependency>
Метод 1 – Повний diff метаданих
Цей метод витягує усі властивості метаданих з обох версій і повідомляє про додані, видалені та змінені записи.
// 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;
Ключові моменти:
- Всеохоплююче: Захоплює всі теги, включаючи користувацькі.
- Проста логіка мап: Не потрібна зовнішня бібліотека diff.
- Об’єкт результату: Карти
added,removedіchangedготові до подальшої обробки.
💡 Порада: Використовуйте цей метод, коли потрібен повний аудит для регуляторної відповідності.
Метод 2 – Виявлення змін власності
Юридичні спори часто зводяться до того, хто створив або відредагував документ. Цей метод зосереджується на тегах, пов’язаних з особами, таких як Creator, Editor, Manager і 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 витягує лише релевантні теги:
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;
Ключові моменти:
- Цілеспрямовано: Перевіряються лише властивості, що стосуються ідентифікації.
- Чіткий вихід: Повертає мапу, де кожен запис показує значення
[old, new]. - Готово до відповідності: Ідеально підходить для e‑discovery або спорів про власність контракту.
💡 Порада: Поєднайте цей метод з повним diff, якщо потрібна і ширина, і глибина аналізу.
Метод 3 – Виявлення змін історії ревізій
Номери ревізій, часові мітки редагування та дати друку невидимі для кінцевих користувачів, але критично важливі для судово‑технічних часових ліній. Цей метод виділяє теги, пов’язані з часом.
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 витягує мітки Modified, Created і Printed:
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.getTime().getModified())
.or(new ContainsTagSpecification(Tags.getTime().getCreated()))
.or(new ContainsTagSpecification(Tags.getTime().getPrinted()))