💡 Contoh kerja penuh tersedia di GitHub:
document-version-metadata-diff-python
Yang Akan Anda Bangun
Dalam panduan ini Anda akan membandingkan setiap properti metadata antara dua versi dokumen dan mencetak secara tepat apa yang ditambahkan, dihapus, atau diubah. Perbandingan versi metadata adalah perbandingan tingkat properti dari dua revisi satu file, dan ia menangkap sinyal yang tidak pernah dilihat perbandingan teks: Pembuat baru, NomorRevisi yang naik, sesi penyuntingan yang tercatat setelah tinjauan ditutup. Pada akhir tutorial Anda akan memiliki solusi yang berfungsi plus dua detektor terfokus dan dua format ekspor, semuanya diambil dari repositori yang dapat dijalankan dengan pasangan revisi contoh.
Tingkat keahlian: pengembang Python menengah
Apa yang Anda butuhkan: Python 3, pip, dan dua revisi satu dokumen
Run pertama saya dengan skrip ini menandai perubahan nilai Perusahaan yang tidak ada yang ingat melakukannya; satu baris itu membayar biaya penyiapan. Semua di bawah ini siap disalin‑tempel dan totalnya jauh di bawah seratus baris.
Pipeline sengaja sederhana: dua pembukaan file, tiga komprehensi dict, satu loop cetak. Kesederhanaan adalah intinya. Perselisihan versi diputuskan berdasarkan apakah metode dapat dijelaskan dan diulang, dan skrip sekecil ini dapat dibaca seluruhnya oleh siapa pun yang menantang temuan.
1. Instalasi
pip install groupdocs-metadata-net==26.5
Repositori pendamping mengunci versi ini dan menyertakan document-v1.docx serta document-v2.docx sehingga kode di bawah ini dapat dijalankan apa adanya. Kunci versi yang Anda gunakan saat audit; reproduktibilitas adalah bagian dari bukti.
2. Kode Inti
Baca kedua pohon properti, lalu klasifikasikan delta dengan logika set. Inilah seluruh diff:
# Flatten a file's complete property tree into a dict
def read_props(path):
props = {}
with Metadata(path) as metadata:
for p in metadata.find_properties(lambda p: p.name is not None):
props[p.name] = (str(p.interpreted_value) if p.interpreted_value is not None
else (str(p.value) if p.value is not None else ""))
return props
v1 = read_props("resources/document-v1.docx")
v2 = read_props("resources/document-v2.docx")
# Classify every key; changed entries keep both values
added = {k: v for k, v in v2.items() if k not in v1}
removed = {k: v for k, v in v1.items() if k not in v2}
changed = {k: (v1[k], v2[k]) for k in v1 if k in v2 and v1[k] != v2[k]}
print(f"added={len(added)} removed={len(removed)} changed={len(changed)}")
for k, (old_v, new_v) in changed.items():
print(f" {k}: {old_v} -> {new_v}")
Itulah minimum yang Anda butuhkan. Harapkan hitungan kecil pada pasangan revisi yang sah; delta berpuluh biasanya berarti file melewati perubahan templat atau migrasi penyimpanan di tengah jalan. Bagian selanjutnya menjelaskan panggilan kunci dan menunjukkan kustomisasi yang biasanya ditambahkan tim pertama kali.
3. Cara Kerja
Metadata: manajer konteks yang membuka file dan melepaskannya saat keluar; satu instance per revisi.find_properties: menelusuri bidang bawaan, properti khusus, dan XMP dalam satu pass, mengembalikan semua yang diterima predikat.interpreted_value: bentuk yang dapat dibaca manusia dari sebuah properti; memprioritaskannya berarti tanggal dan enumerasi dibandingkan sebagai string yang dapat Anda cetak dalam laporan.- Nama yang memenuhi syarat sebagai kunci: bidang bawaan dan khusus tidak dapat bertabrakan dalam dict, sehingga logika set tetap aman.
Tidak ada yang di sini mem-parsing struktur DOCX. Dokumentasi produk mencantumkan lebih dari 170 format di balik panggilan yang sama, jadi skrip identik dapat membandingkan pasangan PDF atau XLSX.
Satu lagi sifat desain yang patut disebutkan: batas API berakhir pada dua pemanggilan read_props. Semua setelahnya adalah Python standar‑library, sehingga unit test, ambang batas, dan aturan peringatan tidak pernah menyentuh lapisan dokumen. Tim yang membungkus ini dalam layanan biasanya menyimpan dict yang diekstrak per revisi dan membiarkan setiap pemeriksaan hilir menggunakannya kembali, menjaga IO file pada satu pembukaan per versi tidak peduli berapa banyak pertanyaan yang diajukan.
4. Kustomisasi Umum
Deteksi perubahan kepemilikan saja
Ketika pertanyaannya adalah “siapa yang menyentuh file ini”, saring saat membaca dengan predikat tag alih‑alih menyaring diff lengkap setelahnya:
# Identity fields only, whatever the format calls them
def read_ownership(path):
result = {}
with Metadata(path) as metadata:
props = metadata.find_properties(lambda p:
Tags.person.creator in list(p.tags)
or Tags.person.editor in list(p.tags)
or Tags.person.manager in list(p.tags)
or Tags.corporate.company in list(p.tags))
for prop in props:
result[prop.name] = (str(prop.interpreted_value)
if prop.interpreted_value is not None
else (str(prop.value) if prop.value is not None else ""))
return result
Jalankan loop delta yang sama atas dua dict ini, gunakan <missing> sebagai nilai default sehingga bidang yang menghilang tetap muncul. Nama predikat tidak menyebutkan bidang apa pun, itulah yang memungkinkan satu detektor melayani semua format yang dibaca perpustakaan.
Lacak linimasa penyuntingan
Ganti predikat dengan Tags.time plus aturan nama penghitung dan detektor melaporkan pergerakan RevisionNumber, TotalEditingTime, dan LastPrinted:
props = metadata.find_properties(lambda p:
Tags.time.modified in list(p.tags)
or Tags.time.created in list(p.tags)
or Tags.time.printed in list(p.tags)
or (p.name is not None and ("Revision" in p.name
or "EditTime" in p.name or "EditingTime" in p.name)))
Ekspor laporan audit
Temuan yang hanya muncul di konsol akan mati di sana. Empat kolom mencakup spreadsheet dan kasus SIEM:
with open("output/diff.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(["change_type", "property", "old_value", "new_value"])
for k, v in added.items():
writer.writerow(["added", k, "", v])
for k, v in removed.items():
writer.writerow(["removed", k, v, ""])
for k, (old_v, new_v) in changed.items():
writer.writerow(["changed", k, old_v, new_v])
Repositori juga menyertakan pengekspor JSON dengan skema tiga‑peta stabil untuk dasbor dan API manajemen kasus.
Di Mana Ini Dijalankan dalam Praktik
Tiga penerapan terus muncul. Pipeline intake membandingkan setiap dokumen yang masuk dengan salinan yang sudah tercatat dan mengarantina pasangan dengan perubahan kepemilikan. Pekerjaan kepatuhan menjalankan diff secara terjadwal dan mengarsipkan CSV per pasangan, membangun linimasa properti yang tidak perlu direkonstruksi nanti. Dan alat sengketa menjalankan kedua detektor atas permintaan, karena ketika klaim muncul pertanyaan pembuka selalu siapa yang menyentuh file dan kapan, bukan apa yang berubah di paragraf empat.
Pola keempat, membandingkan file dengan snapshot terakhir yang diketahui baik, menggunakan kode yang sama dengan dict yang disimpan di satu sisi. Dalam semua kasus, file ekspor adalah deliverable; output konsol hanyalah kebisingan progres. Pola kode keluar mengikuti main.py repositori, sehingga penjadwal dan CI memperlakukan assert gagal sebagai run gagal tanpa wiring tambahan. Tidak ada yang memerlukan kode di luar apa yang ditunjukkan halaman ini.
Apa yang dihitung sebagai perubahan yang layak ditandai?
Apa pun yang diklasifikasikan diff ditambah konteks yang Anda tambahkan. Properti yang ditambahkan dan dihapus selalu patut diperiksa karena berarti struktur berubah, bukan hanya nilai. Untuk entri yang diubah, kebanyakan tim memberi peringatan pada grup identitas dan revisi terlebih dahulu dan memperlakukan sisanya sebagai informasi. Detektor ada agar pass pertama hanya memerlukan satu pemanggilan fungsi.
5. Referensi Cepat: Panggilan Kunci
| Panggilan | Apa Fungsinya |
|---|---|
Metadata(path) |
Membuka file; manajer konteks menangani pelepasan |
find_properties(predicate) |
Mengembalikan setiap properti yang diterima predikat, melintasi semua lapisan |
p.interpreted_value |
Nilai yang dapat dibaca manusia; jatuh kembali ke p.value |
Tags.person.* / Tags.corporate.company |
Klasifikasi identitas, independen format |
Tags.time.* |
Klasifikasi timestamp untuk detektor revisi |
Lihat referensi API lengkap untuk seluruh permukaan pencarian dan tagging. Kosakata tag lebih besar daripada baris ini; grup asal, konten, dan legal mengikuti tes keanggotaan yang sama.
6. Masalah Umum & Solusi
Diff terlalu besar dan terasa seperti kebisingan
→ Kemungkinan dua jalur bukan revisi satu dokumen. Perbaiki: validasi asal sebelum melakukan diff; file yang tidak terkait menghasilkan delta yang tidak berarti.
Bidang penulis yang dikenal tidak muncul di detektor kepemilikan
→ Beberapa produsen menyimpan identitas di bidang khusus yang tidak ditandai. Perbaiki: jalankan diff lengkap sekali, temukan nama bidang sebenarnya, dan perluas predikat dengan aturan nama.
Konsol menampilkan peringatan mode evaluasi
→ Tidak ada file lisensi yang ditemukan. Perbaiki: arahkan LICENSE_PATH di main.py ke file .lic Anda, atau tetap gunakan mode evaluasi untuk pengembangan; logikanya tetap sama.
Tanggal tercetak sebagai angka serial mentah
→ p.value mentah masuk ke pembaca di suatu tempat. Perbaiki: pertahankan pola interpreted_value‑first dari read_props; itulah alasan laporan tetap dapat dibaca.
Apa Selanjutnya?
Anda sudah memiliki diff metadata yang berfungsi. Berikut langkah selanjutnya:
- Batch it: loop skrip atas pasangan dokumen dan simpan CSV per pasangan; biaya per pasangan hanya dua pembukaan file, dan CSV dapat digabungkan bersih untuk tampilan perpustakaan secara keseluruhan.
- Schedule it:
main.pyrepositori melakukan assert setiap langkah dan mengembalikan kode keluar yang tepat, yang dapat langsung masuk ke CI atau penjadwal. - Walk the tutorial version: panduan kasus penggunaan membangun pipeline yang sama dalam tiga tutorial bergradasi.
- See the whole project: document-version-metadata-diff-python dengan pasangan revisi yang disediakan.