บทนำ

เมื่อทีมกฎหมายหรือผู้วิเคราะห์ด้านนิติวิทยาศาสตร์ต้องพิสูจน์ว่าเอกสารไม่ได้ถูกดัดแปลง การมองเห็นเนื้อหาที่ปรากฏไม่เพียงพอ คุณสมบัติที่ซ่อนอยู่—เช่น ผู้เขียน, วันที่สร้าง, หรือหมายเลขรุ่น—สามารถเปิดเผยว่าใครได้สัมผัสไฟล์และเมื่อใด การตรวจจับการเปลี่ยนแปลงเล็ก ๆ เหล่านี้ในหลายเวอร์ชันของเอกสารเป็นจุดเจ็บปวดที่มักต้องตรวจสอบคุณสมบัติแต่ละอย่างด้วยตนเอง ซึ่งใช้เวลานานและเสี่ยงต่อข้อผิดพลาด

GroupDocs.Metadata for 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)

การติดตั้ง

เพิ่ม dependency ผ่าน Maven:

<dependency>
    <groupId>com.groupdocs</groupId>
    <artifactId>groupdocs-metadata</artifactId>
    <version>24.7</version>
</dependency>

วิธีที่ 1 – การเปรียบเทียบเมตาดาต้าครบถ้วน

วิธีนี้สกัด ทุก คุณสมบัติเมตาดาต้าจากทั้งสองเวอร์ชันและรายงานรายการที่เพิ่ม, ลบ, และเปลี่ยนแปลง

// 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()))))