推荐使用XNode.DeepEquals进行XML语义比较,它自动忽略空白、属性顺序等格式差异,正确处理命名空间URI而非前缀;也可用XmlDocument归一化后字符串比较,或借助Microsoft.XmlDiffPatch实现精细控制。

直接比较两个XML文件的字符串内容通常不可靠,因为格式差异(如空格、换行、属性顺序、命名空间前缀)会导致相同语义的XML字符串不相等。C#中推荐使用基于XML结构和语义的比较方式,核心是用 XmlDocument 或 XDocument 加载后归一化再比对,或借助专门的XML比较库。
使用 XNode.DeepEquals(最简单且推荐)
XNode.DeepEquals 是 .NET 内置方法,自动忽略空白文本节点、属性顺序、声明、注释(默认不忽略注释,需注意),并按逻辑结构比较元素、属性、值和嵌套关系。
- 确保两个 XML 字符串或文件先加载为
XDocument - 调用
XNode.DeepEquals(doc1.Root, doc2.Root)比较根节点(若文档结构一致) - 若需忽略注释和处理指令,可先用
RemoveNodes()清理,或使用第三方库
var doc1 = XDocument.Load("file1.xml");
var doc2 = XDocument.Load("file2.xml");
bool identical = XNode.DeepEquals(doc1.Root, doc2.Root);
用 XmlDocument + XmlWriter 归一化后比较字符串
当需要完全可控的“标准化输出”时,可将两个 XML 加载为 XmlDocument,用 XmlWriterSettings 设置 Indent=false、OmitXmlDeclaration=true、IgnoreWhitespace=true 等,再写入字符串比较。
- 设置
PreserveWhitespace = false可跳过文本节点中的冗余空白 - 调用
Normalize()方法对文档进行规范化(合并相邻文本节点等) - 注意:该方式仍可能受命名空间前缀影响,建议统一前缀或改用
XDocument配合XmlNamespaceManager
处理命名空间和前缀差异
两个语义相同的XML可能使用不同前缀(如 ns:elem vs abc:elem),但属于同一命名空间URI。此时 DeepEquals 默认能正确识别——它比对的是命名空间URI而非前缀。
- 确保加载时未禁用命名空间支持(
XmlReaderSettings.Namespaces = true,默认开启) - 避免手动修改
XElement.Name.NamespaceName,否则会破坏语义一致性 - 如需调试命名空间,可用
doc.Root.Attributes().Where(a => a.IsNamespaceDeclaration)查看声明
需要更精细控制?用 Microsoft.XmlDiffPatch
这是微软提供的开源XML差异工具(现维护于 GitHub),支持生成差异补丁、忽略特定节点、自定义比较规则(如忽略时间戳属性、排序子节点后再比)。
- NuGet 包:
Microsoft.XmlDiffPatch - 适合场景:测试中验证XML输出是否符合预期、生成差异报告、CI 中断言
- 基本用法:创建
XmlDiff实例,设置IgnoreChildOrder、IgnoreComments等选项,调用Compare()










