💡 Tam çalışan örnek GitHub’da mevcuttur:
document-version-metadata-diff-python
Oluşturacağınız Şey
Bu rehberde bir belgenin iki sürümü arasındaki tüm metadata özelliklerini karşılaştırıp, eklenen, kaldırılan veya değiştirilenleri tam olarak yazdıracaksınız. Bir metadata sürüm farkı, aynı dosyanın iki revizyonunun özellik‑seviyesi karşılaştırmasıdır ve bir metin karşılaştırmasının asla göremediği sinyalleri yakalar: yeni bir Creator, yükseltilmiş RevisionNumber, inceleme kapandıktan sonra kaydedilen bir düzenleme oturumu. Sonunda çalışır bir çözüm, iki odaklı dedektör ve iki dışa aktarma formatı elde edeceksiniz; hepsi örnek bir revizyon çiftiyle doldurulmuş bir çalıştırılabilir depodan alınmıştır.
Yetenek seviyesi: orta seviye Python geliştiricisi
Gereksinimler: Python 3, pip ve bir belgenin iki revizyonu
Bu betiğin ilk çalıştırması, ekipte kimsenin hatırlamadığı bir Company değeri değişikliğini işaretledi; o bir satır kurulumun bedelini ödedi. Aşağıdaki tüm içerik kopyala‑yapıştır hazır ve yüz satırın çok altında.
İş akışı kasıtlı olarak sıkıcı: iki dosya açma, üç sözlük kavraması, bir yazdırma döngüsü. Sıkıcı olması amaç. Sürüm anlaşmazlıkları, yöntemin açıklanabilir ve tekrarlanabilir olup olmadığına göre çözülür ve bu kadar küçük bir betik, bulguyu sorgulayan herkes tarafından tamamen okunabilir.
1. Kurulum
pip install groupdocs-metadata-net==26.5
İlgili depo bu sürümü sabitler ve document-v1.docx ile document-v2.docx dosyalarını içerir; böylece aşağıdaki kod olduğu gibi çalışır. Denetiminizle aynı sürümü sabitleyin; yeniden üretilebilirlik kanıtın bir parçasıdır.
2. Temel Kod
Her iki özellik ağacını okuyun, ardından set mantığıyla farkı sınıflandırın. İşte tüm fark:
# 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}")
Bu, ihtiyacınız olan en az şeydir. Gerçek revizyon çiftlerinde sayılar düşük olur; ondalık sayıda fark, dosyanın bir şablon değişikliğinden veya bir depolama geçişinden geçtiği anlamına gelir. Sonraki bölümler temel çağrıları açıklar ve ekiplerin ilk eklediği özelleştirmeleri gösterir.
3. Nasıl Çalışır
Metadata: dosyayı açan ve çıkışta serbest bırakan bağlam yöneticisi; her revizyon için bir örnek.find_properties: yerleşik alanları, özel özellikleri ve XMP’yi tek bir geçişte dolaşır, koşulu sağlayan her şeyi döndürür.interpreted_value: bir özelliğin insan‑okunur biçimi; bunu tercih etmek, tarih ve enum değerlerinin raporda yazdırılabilir string olarak karşılaştırılmasını sağlar.- Anahtar olarak nitelikli adlar: yerleşik ve özel alanlar sözlükte çakışamaz, böylece set mantığı güvenli kalır.
Burada DOCX yapıları ayrıştırılmaz. Ürün belgeleri aynı çağrıyla 170+ formatı listeler; aynı betik PDF veya XLSX çiftleri için de çalışır.
Tasarımın bir diğer özelliği de şudur: API sınırı iki read_props çağrısında biter. Sonrasındaki her şey standart‑kütüphane Python’udur; bu yüzden birim testleri, eşik değerleri ve uyarı kuralları belge katmanına dokunmaz. Bu betiği bir hizmet içinde saran ekipler genellikle çıkarılan sözlükleri revizyon başına önbelleğe alır ve her alt kontrolün bunları yeniden kullanmasını sağlar; böylece kaç soru sorulursa sorulsun dosya IO’su sadece sürüm başına bir kez olur.
4. Yaygın Özelleştirmeler
Sadece sahiplik değişikliklerini algıla
Soru “bu dosyaya kim dokundu?” olduğunda, tam farkı sonradan filtrelemek yerine okuma sırasında etiket koşullarıyla filtrele:
# 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
Bu sözlükler üzerinde aynı delta döngüsünü çalıştır, eksik alanları göstermek için <missing> varsayılanını kullan. Koşul hiçbir alanı isimlendirmez; bu da bir dedektörün kütüphanenin okuduğu her formatta çalışmasını sağlar.
Düzenleme zaman çizelgesini izle
Koşulu Tags.time ve sayaç adı kurallarıyla değiştir; dedektör RevisionNumber, TotalEditingTime ve LastPrinted hareketlerini raporlar:
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)))
Denetim raporu dışa aktar
Konsolda kalan bulgular orada ölür. Dört sütun, elektronik tablo ve SIEM vakası için yeterlidir:
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])
Depo ayrıca panolar ve vaka‑yönetim API’leri için sabit üç‑harita şemasıyla bir JSON dışa aktarıcı içerir.
5. Hızlı Referans: Temel Çağrılar
| Çağrı | Ne İşe Yarar |
|---|---|
Metadata(path) |
Dosyayı açar; bağlam yöneticisi serbest bırakmayı yönetir |
find_properties(predicate) |
Koşulu sağlayan her özelliği, tüm katmanlarda döndürür |
p.interpreted_value |
İnsan‑okunur değer; yoksa p.value kullanılır |
Tags.person.* / Tags.corporate.company |
Kimlik sınıflandırması, format bağımsız |
Tags.time.* |
Revizyon dedektörü için zaman damgası sınıflandırması |
Tam arama ve etiketleme yüzeyine bakmak için tam API referansına göz atın. Etiket sözlüğü bu satırlardan daha geniştir; kaynak, içerik ve yasal etiket grupları aynı üyelik testini kullanır.
6. Yaygın Sorunlar ve Çözümler
Fark çok büyük ve gürültü gibi görünüyor
→ İki yol muhtemelen aynı belgenin revizyonları değil. Çözüm: fark almadan önce kaynağı doğrulayın; alakasız dosyalar anlamsız farklar üretir.
Bilinen bir yazar alanı sahiplik dedektöründe hiç görünmüyor
→ Bazı üreticiler kimliği etiketlenmemiş özel alanlarda saklar. Çözüm: tam farkı bir kez çalıştır, gerçek alan adını bul ve koşula bir ad kuralı ekle.
Konsolda değerlendirme‑modu uyarısı gösteriliyor
→ Lisans dosyası bulunamadı. Çözüm: main.py içinde LICENSE_PATH değişkenini .lic dosyanıza yönlendirin veya geliştirme için değerlendirme modunu tutun; mantık aynı kalır.
Tarihler ham seri numarası olarak yazdırılıyor
→ p.value bir yerde okuyucuya kaçmış. Çözüm: read_props içinde interpreted_value‑ilk desenini koruyun; bu, raporların okunabilir kalmasının nedenidir.
Sonraki Adım?
Çalışır bir metadata farkınız var. Bundan sonra yapabilecekleriniz:
- Toplu hâle getirin: betiği belge çiftleri üzerinde döngüye alın ve her çift için CSV kaydedin; çift başına maliyet iki dosya açma ve CSV’ler kütüphane‑geneli bir görünüm için sorunsuz birleştirilebilir.
- Zamanlayın: deponun
main.pydosyası her adımı doğrular ve uygun bir çıkış kodu döndürür; bu doğrudan CI ya da zamanlayıcıya bağlanabilir. - Eğitim sürümünü izleyin: kullanım senaryosu rehberi aynı akışı üç dereceli öğreticide oluşturur.
- Tüm projeyi görün: document-version-metadata-diff-python içinde örnek revizyon çifti bulunur.