XmlComparer.Core
1.0.0
dotnet add package XmlComparer.Core --version 1.0.0
NuGet\Install-Package XmlComparer.Core -Version 1.0.0
<PackageReference Include="XmlComparer.Core" Version="1.0.0" />
<PackageVersion Include="XmlComparer.Core" Version="1.0.0" />
<PackageReference Include="XmlComparer.Core" />
paket add XmlComparer.Core --version 1.0.0
#r "nuget: XmlComparer.Core, 1.0.0"
#:package XmlComparer.Core@1.0.0
#addin nuget:?package=XmlComparer.Core&version=1.0.0
#tool nuget:?package=XmlComparer.Core&version=1.0.0
XmlComparer
XmlComparer is a zero-dependency .NET library for structural XML comparison with an HTML side-by-side diff report.
Projects
XmlComparer.Core- Diff engine and HTML formatter.XmlComparer.Runner- CLI/sample runner.XmlComparer.Tests- Unit tests.
Quickstart (CLI)
Run the runner against two XML files and generate an HTML report:
dotnet run --project XmlComparer.Runner -- .\original.xml .\new.xml --out diff.html --json diff.json --key id,code
Options:
--out <path>: Output HTML path (defaultdiff.html)--json [path]: Output JSON diff (defaultdiff.jsonif flag is present)--json-only: Skip HTML output and emit JSON only (defaults todiff.json)--validation-only: Validate against XSDs and emit JSON validation result only (defaults tovalidation.json)--key <comma-list>: Key attributes used to match elements--ignore-values: Ignore text values when comparing--xsd <path>: Validate both XML files against one or more XSDs before diffing (repeatable)
The HTML report embeds the JSON diff in a <script type="application/json" id="xml-diff-json"> tag for single-file portability and assigns window.xmlDiff for easy access. If schema validation is requested, the JSON includes a Validation block alongside Diff, and the HTML shows a validation status panel.
If no arguments are provided, the runner generates sample reports (test1.html - test5.html) in the current folder.
Library Usage
using XmlComparer.Core;
var config = new XmlDiffConfig
{
IgnoreValues = false
};
config.KeyAttributeNames.Add("id");
config.ExcludedNodeNames.Add("metadata");
config.ExcludedAttributeNames.Add("timestamp");
var service = new XmlComparerService(config);
var diff = service.Compare(@"C:\path\old.xml", @"C:\path\new.xml");
string html = service.GenerateHtml(diff);
Friendly API (Recommended)
using XmlComparer.Core;
var result = XmlComparer.CompareFilesWithReport(
@"C:\path\old.xml",
@"C:\path\new.xml",
options => options
.WithKeyAttributes("id", "code")
.ExcludeAttributes("timestamp")
.ExcludeNodes(excludeSubtree: true, "metadata")
.NormalizeWhitespace()
.NormalizeNewlines()
.TrimValues()
.ValidateWithXsds(@"C:\path\schema.xsd")
.IncludeHtml()
.IncludeJson());
File.WriteAllText(@"C:\path\diff.html", result.Html!);
File.WriteAllText(@"C:\path\diff.json", result.Json!);
Dependency Injection Friendly Client
using XmlComparer.Core;
var client = new XmlComparerClient(
new XmlDiffConfig(),
new DefaultMatchingStrategy());
var result = client.CompareContentWithReport(
"<root><child>1</child></root>",
"<root><child>2</child></root>",
options => options.IncludeJson());
Async and Streams
using XmlComparer.Core;
using System.IO;
using System.Threading.Tasks;
var diff = await XmlComparer.CompareFilesAsync(@"C:\a.xml", @"C:\b.xml");
using var left = File.OpenRead(@"C:\a.xml");
using var right = File.OpenRead(@"C:\b.xml");
var diffFromStreams = XmlComparer.CompareStreams(left, right);
String Extension Methods
using XmlComparer.Core;
string xml1 = "<root><child>1</child></root>";
string xml2 = "<root><child>2</child></root>";
var diff = xml1.CompareXmlTo(xml2, options => options.IgnoreValues());
var report = xml1.CompareXmlToWithReport(xml2, options => options.IncludeHtml());
Options Presets (JSON)
using XmlComparer.Core;
var options = new XmlComparisonOptions()
.WithKeyAttributes("id")
.ExcludeAttributes("timestamp")
.IncludeHtml()
.IncludeJson();
string json = options.ToJson();
var loaded = XmlComparisonOptions.FromJson(json);
options.SaveToFile(@"C:\path\options.json");
var loadedFromFile = XmlComparisonOptions.LoadFromFile(@"C:\path\options.json");
The options JSON includes a Version field for forward compatibility.
If you want to round-trip a custom strategy, set a MatchingStrategyId via UseMatchingStrategy(strategy, "id") and rehydrate it in your app.
loaded.ResolveMatchingStrategy(id => id == "default" ? new DefaultMatchingStrategy() : null);
If you want a warning when the JSON has no Version field:
var loadedWithWarning = XmlComparisonOptions.FromJson(json, warning => Console.WriteLine(warning));
You can also register strategies once and resolve by id:
XmlComparisonOptions.MatchingStrategyRegistry.TryRegister(
"default",
() => new DefaultMatchingStrategy());
loaded.ResolveMatchingStrategyFromRegistry();
XmlComparisonOptions.MatchingStrategyRegistry.Unregister("default");
XmlComparisonOptions.MatchingStrategyRegistry.Clear();
if (XmlComparisonOptions.MatchingStrategyRegistry.TryResolve("default", out var strategy))
{
// Use strategy
}
Registry lifecycle tip: register strategies at app startup and clear/unregister on shutdown or in test teardown to avoid stale global state.
JSON Output Schema
The JSON output is an envelope:
{
"Validation": { "IsValid": true, "Errors": [] },
"Diff": { "Name": "root", "Type": "Modified" }
}
If you previously consumed a diff-only JSON object, update your parser to read Diff from the envelope.
The JSON Schema for the envelope is packaged as XmlDiff.schema.json in the NuGet package.
Embedded XSD Usage
If your schemas are embedded resources, build a schema set and pass it to the validator:
using System.Reflection;
using XmlComparer.Core;
var assembly = Assembly.GetExecutingAssembly();
var resources = XmlSchemaSetFactory.ListEmbeddedSchemas(assembly);
var schemaSet = XmlSchemaSetFactory.FromEmbeddedResource(
assembly,
"Your.Assembly.Resources.SampleSchema.xsd");
var validator = new XmlSchemaValidator(schemaSet);
var result = validator.ValidateContent("<root><child>123</child></root>");
Configuration
ExcludedNodeNames: Skip matching nodes entirely by element name.ExcludeSubtree: If true, excluded nodes and their children are ignored entirely; if false, only the node is ignored while its children are compared.ExcludedAttributeNames: Ignore attributes by name.KeyAttributeNames: Attribute names that uniquely identify sibling elements.NormalizeWhitespace: Collapse runs of whitespace before comparing values.NormalizeNewlines: Treat CRLF and CR as LF.TrimValues: Trim leading/trailing whitespace before comparing values.IgnoreValues: Ignore text values when comparing.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|