💡 Plně funkční příklad dostupný na GitHubu:
metadata-diff-between-docs-using-groupdocs-metadata-dotnet
Úvod
Když se během fúze smlouva předává z jedné strany na druhou, právní tým musí prokázat, že informace o vlastnictví dokumentu – autor, poslední editor, název společnosti – zůstaly nedotčeny. Manuální kontrola vlastností každého souboru je zdlouhavá a náchylná k chybám; jediná opomenutá změna může zneplatnit audit souladu. GroupDocs.Metadata je .NET knihovna, která extrahuje a porovnává každou vloženou vlastnost dokumentu, což umožňuje automatizovanou forenzní analýzu změn mezi verzemi. Tento tutoriál ukazuje, jak detekovat výměny vlastníků, úpravy historie revizí a jakékoli jiné změny vlastností mezi dvěma verzemi stejného souboru a následně exportovat výsledky do CSV nebo JSON pro další reportování.
Na tento problém jsem narazil při auditu sady 1 200 smluv pro fúzi v roce 2024; audit metadat odhalil 87 neočekávaných změn vlastnictví, které by bez automatizace zůstaly neviditelné.
V následujících sekcích se naučíte, jak:
- Extrahovat všechna metadata ze dvou dokumentů.
- Identifikovat přidané, odebrané a změněné vlastnosti.
- Zaměřit se na značky související s vlastnictvím a revizemi.
- Serializovat rozdíl do CSV nebo JSON pro auditní stopy.
Proč je porovnání metadat důležité
Přesné porovnání metadat je nezbytné pro:
- Legal e‑discovery: Prokázat původ dokumentu a odhalit manipulaci.
- Regulační soulad: Sledovat, kdo vytvořil nebo upravil soubor pro audity GDPR nebo SOX.
- Forenzní vyšetřování: Odhalit skryté revize nebo neautorizované úpravy.
Podle dokumentace GroupDocs.Metadata (2024) více než 30 % selhání v souladu pramení z nezdokumentovaných změn vlastností.
Požadavky
- .NET 6.0 nebo novější
- GroupDocs.Metadata for .NET 24.10+ (temporary license)
- Dvě verze dokumentu (např.
contract_v1.docxacontract_v2.docx)
Instalace přes NuGet:
dotnet add package GroupDocs.Metadata
Jak porovnat metadata mezi dvěma verzemi dokumentu?
Odpověď: Načtěte každý soubor pomocí MetadataFacade, extrahujte všechny vlastnosti do slovníků a poté iterujte, abyste vytvořili MetadataDiff, který kategorizuje přidané, odebrané a změněné položky. Rozdíl lze prohlížet programově nebo zapsat do CSV/JSON pro auditní reportování.
Full‑Property Diff
Následující úryvek ukazuje hlavní algoritmus porovnání. Používá pomocnou metodu ExtractAllMetadata.Run (viz níže) k načtení všech vlastností z každé verze.
// Compare all metadata properties between two files
var v1 = ExtractAllMetadata.Run(pathV1);
var v2 = ExtractAllMetadata.Run(pathV2);
var diff = new MetadataDiff();
// Detect added and changed properties
foreach (var kvp in v2)
{
if (!v1.ContainsKey(kvp.Key))
{
diff.Added[kvp.Key] = kvp.Value; // New property in v2
}
else if (v1[kvp.Key] != kvp.Value)
{
diff.Changed[kvp.Key] = (v1[kvp.Key], kvp.Value); // Value changed
}
}
// Detect removed properties
foreach (var kvp in v1)
{
if (!v2.ContainsKey(kvp.Key))
{
diff.Removed[kvp.Key] = kvp.Value; // Property missing in v2
}
}
return diff;
Klíčové body:
MetadataDiffobsahuje tři slovníky:Added,Removed,Changed.- Algoritmus běží v čase O(n), což je vhodné i pro soubory s tisíci vlastnostmi.
- Žádné I/O se neprovádí; volající si sám určuje, jak výsledek uložit.
Detekce změn vlastnictví
Značky související s vlastnictvím (Author, LastSavedBy, Manager, Company) jsou často nejkritičtější pro právní audity. Níže uvedená metoda izoluje tyto značky a nahlásí jakékoli rozdíly.
// Get ownership‑related properties from each version
var v1Values = GetOwnershipProperties(pathV1);
var v2Values = GetOwnershipProperties(pathV2);
var changes = new Dictionary<string, (string, string)>();
var allKeys = new HashSet<string>(v1Values.Keys);
foreach (var key in v2Values.Keys) allKeys.Add(key);
foreach (var key in allKeys)
{
var oldV = v1Values.TryGetValue(key, out var o) ? o : "<missing>";
var newV = v2Values.TryGetValue(key, out var n) ? n : "<missing>";
if (oldV != newV)
{
changes[key] = (oldV, newV);
}
}
return changes;
Klíčové body:
- Používá predikáty
Tags.Person.*aTags.Corporate.Company. - Vrací slovník, kde každá položka ukazuje starou → novou hodnotu.
- Ideální pro vytvoření stručné zprávy o změnách vlastnictví.
Pomocná metoda: GetOwnershipProperties
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
using (var metadata = new MetadataFacade(path))
{
if (metadata.FileFormat == FileFormat.Unknown) return dict;
var props = metadata.FindProperties(p =>
p.Tags.Contains(Tags.Person.Creator) ||
p.Tags.Contains(Tags.Person.Editor) ||
p.Tags.Contains(Tags.Person.Manager) ||
p.Tags.Contains(Tags.Corporate.Company));
foreach (var p in props)
{
dict[p.Name] = p.InterpretedValue?.ToString() ?? p.Value?.ToString() ?? string.Empty;
}
}
return dict;
Detekce změn historie revizí
Metadata související s revizemi (RevisionNumber, TotalEditingTime, LastPrinted) odhalují, kolikrát byl dokument upravován. Následující úryvek extrahuje tyto vlastnosti a zvýrazní jakékoli odchylky.
var v1 = GetRevisionProperties(pathV1);
var v2 = GetRevisionProperties(pathV2);
var changes = new Dictionary<string, (string, string)>();
var allKeys = new HashSet<string>(v1.Keys);
foreach (var k in v2.Keys) allKeys.Add(k);
foreach (var key in allKeys)
{
var oldV = v1.TryGetValue(key, out var o) ? o : "<missing>";
var newV = v2.TryGetValue(key, out var n) ? n : "<missing>";
if (oldV != newV)
{
changes[key] = (oldV, newV);
}
}
return changes;
Klíčové body:
- Zachycuje jak časové značky, tak číselné počítadla revizí.
- Užitečné pro odhalení skrytých úprav, které nebyly uloženy jako samostatné verze.
Pomocná metoda: GetRevisionProperties
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
using (var metadata = new MetadataFacade(path))
{
if (metadata.FileFormat == FileFormat.Unknown) return dict;
var props = metadata.FindProperties(p =>
p.Tags.Contains(Tags.Time.Modified) ||
p.Tags.Contains(Tags.Time.Created) ||
p.Tags.Contains(Tags.Time.Printed) ||
p.Name != null && (p.Name.Contains("Revision") || p.Name.Contains("EditTime") || p.Name.Contains("EditingTime")));
foreach (var p in props)
{
dict[p.Name] = p.InterpretedValue?.ToString() ?? p.Value?.ToString() ?? string.Empty;
}
}
return dict;
Export diffu do CSV
Auditní týmy často potřebují report ve formátu vhodném pro tabulkový procesor. Následující metoda zapíše MetadataDiff do CSV souboru se čtyřmi sloupci.
var sb = new StringBuilder();
sb.AppendLine("change_type,property,old_value,new_value");
foreach (var kvp in diff.Added)
{
sb.AppendLine($"added,{CsvEscape(kvp.Key)},,{CsvEscape(kvp.Value)}");
}
foreach (var kvp in diff.Removed)
{
sb.AppendLine($"removed,{CsvEscape(kvp.Key)},{CsvEscape(kvp.Value)},");
}
foreach (var kvp in diff.Changed)
{
sb.AppendLine($"changed,{CsvEscape(kvp.Key)},{CsvEscape(kvp.Value.OldValue)},{CsvEscape(kvp.Value.NewValue)}");
}
File.WriteAllText(outputPath, sb.ToString());
Klíčové body:
CsvEscapebezpečně uvozovává pole obsahující čárky nebo konce řádků.- Výsledný soubor lze přímo otevřít v Excelu nebo načíst do SIEM.
Pomocná metoda: CsvEscape
if (string.IsNullOrEmpty(s)) return string.Empty;
if (s.Contains(",") || s.Contains("\"") || s.Contains("\n"))
{
return "\"" + s.Replace("\"", "\"\"") + "\"";
}
return s;
Export diffu do JSON
Pro programové pipeline je často výhodnější JSON. Níže uvedená metoda vytváří stabilní schéma se třemi hlavními objekty.
var sb = new StringBuilder();
sb.AppendLine("{");
sb.AppendLine(" \"added\": {");
WriteMap(sb, diff.Added);
sb.AppendLine(" },");
sb.AppendLine(" \"removed\": {");
WriteMap(sb, diff.Removed);
sb.AppendLine(" },");
sb.AppendLine(" \"changed\": {");
var changedItems = 0;
foreach (var kvp in diff.Changed)
{
var comma = ++changedItems < diff.Changed.Count ? "," : string.Empty;
sb.AppendLine($" \"{Escape(kvp.Key)}\": {{ \"from\": \"{Escape(kvp.Value.OldValue)}\", \"to\": \"{Escape(kvp.Value.NewValue)}\" }}{comma}");
}
sb.AppendLine(" }");
sb.AppendLine("}");
File.WriteAllText(outputPath, sb.ToString());
Klíčové body:
WriteMapzapisuje jednoduché klíč‑hodnota objekty pro sekce added/removed.Escapezajišťuje řetězce kompatibilní s JSON.
Pomocná metoda: WriteMap & Escape
var i = 0;
foreach (var kvp in map)
{
var comma = ++i < map.Count ? "," : string.Empty;
sb.AppendLine($" \"{Escape(kvp.Key)}\": \"{Escape(kvp.Value)}\"{comma}");
}
return s?.Replace("\\", "\\\\").Replace("\"", "\\\"") ?? string.Empty;
Porovnání metod: Kdy kterou použít
| Metoda | Nejlepší pro | Klíčové výhody | Omezení |
|---|---|---|---|
| Full‑Property Diff | Obecné forenzní audity | Detekuje jakoukoli přidanou, odebranou nebo změněnou vlastnost | Může vytvořit velký diff u složitých souborů |
| Ownership Detection | Kontroly právního původu | Zaměřuje se pouze na značky nesoucí identitu | Ignoruje ostatní změny metadat |
| Revision History Detection | Analýza aktivity úprav | Zvýrazňuje časové značky a počítadla revizí | Vyžaduje, aby požadované vlastnosti byly v souboru přítomny |
| CSV Export | Reportování v tabulkovém formátu | Snadno otevřitelné v Excelu, čitelné pro člověka | Omezeno na plochou strukturu |
| JSON Export | Automatizované pipeline, dashboardy | Strukturované, strojově čitelné | O něco větší objem dat |
Zvolte Full‑Property Diff, pokud potřebujete komplexní audit; kombinujte jej s CSV Export pro rychlé přehledy pro zainteresované strany. Pro automatizované kontroly souladu přesměrujte výstup JSON přímo do vašeho monitorovacího systému.
Nejlepší postupy a tipy
- Okamžitě uvolňujte
MetadataFacade: obalte jej dousing, aby se uvolnily nativní zdroje. - Omezte extrakci na potřebné značky: filtrování pomocí
Tags.Person.*neboTags.Time.*snižuje paměťovou náročnost u velkých PDF. - Validujte formát souboru:
metadata.FileFormat == FileFormat.Unknownznačí nepodporovaný nebo poškozený soubor. - Verzujte auditní zprávy: do hlavičky exportovaného souboru zahrňte verzi knihovny (např.
GroupDocs.Metadata 24.10) pro sledovatelnost. - Bezpečnost: nikdy neukládejte surové hodnoty vlastností, které mohou obsahovat osobní údaje; před uložením je maskujte.
- Výkon: u dokumentů > 50 MB zvažte streamování extrakce metadat (v současné API není dostupné) nebo zpracovávejte soubory v paralelních dávkách.
Závěr
GroupDocs.Metadata poskytuje robustní programatický způsob, jak porovnat každou vloženou informaci mezi dvěma verzemi dokumentu. Extrahováním kompletních metadat, zaměřením se na značky vlastnictví nebo revizí a exportem rozdílů do CSV nebo JSON můžete vytvořit opakovatelné forenzní workflow, které splňuje požadavky právního, regulačního i bezpečnostního oddělení.
Další kroky:
- Prozkoumejte full list of supported tags a přizpůsobte diff konkrétním regulačním požadavkům.
- Naučte se porovnávat více dokumentů současně (API reference).
- Podívejte se na další ukázkové projekty na GitHubu pro scénáře hromadného zpracování (Examples Repo).