如果我要比较一个XMlDocument的内容,是不是就这样?
XmlDocument doc1 = GetDoc1();
XmlDocument doc2 = GetDoc2();
if(doc1 == doc2)
{
}
我不是在检查它们是否都是相同的对象引用,而是在检查 xml 的内容是否相同。
在 XLinq API 上尝试 DeepEquals 方法。
XDocument doc1 = GetDoc1();
XDocument doc2 = GetDoc2();
if(XNode.DeepEquals(doc1, doc2))
{
}
没有。 XmlDocument 不会覆盖
Equals()
方法 的行为,因此,它实际上只是执行引用相等 - 在您的示例中这将失败,除非文档实际上是相同的对象实例。
如果你想比较文档的内容(属性、元素、评论、PI 等),你必须自己实现该逻辑。 警告:这不是微不足道的。
根据您的具体情况,您可以从文档中删除所有非必要的空格(这本身可能很棘手),然后他们比较生成的 xml 文本。这并不完美——对于语义相同但在名称空间的使用和声明方式、某些值是否被转义、元素顺序等方面有所不同的文档,它会失败。正如我之前所说,XML 比较并非微不足道。
您还需要清楚地定义两个 XML 文档“相同”的含义。 元素或属性的顺序重要吗?大小写(在文本节点中)重要吗?您应该忽略多余的 CDATA 部分吗?处理指令算吗?完全限定与部分限定的名称空间怎么样?
在任何通用实现中,您可能希望将两个文档都转换为某种规范形式(无论是 XML 还是其他表示形式),然后比较规范化的内容。
执行 XML 差异的工具已经存在,例如 Microsoft XML Diff/Patch, 您可以利用它来识别两个文档之间的差异。据我所知,该工具不是以源代码形式分发的……所以要在嵌入式应用程序中使用它,您需要编写该过程的脚本(如果您打算使用它,您应该首先验证许可条款是否允许它的使用和再分发).
编辑: 如果您使用的是 .NET 3.5 SP1,请查看@Max Toro 的回答,显然 XLinq 中有一个选项可能会有帮助。很高兴知道它存在。
一个简单的方法可能是比较
OuterXml
.
var a = new XmlDocument();
var b = new XmlDocument();
a.LoadXml("<root foo='bar' />");
b.LoadXml("<root foo='bar'/>");
Debug.Assert(a.OuterXml == b.OuterXml);
L布什金是对的,这不是小事。由于 XML 是字符串数据,您可以从技术上对内容执行散列并进行比较,但这会受到空格等因素的影响。
您可以在两个文档之间执行结构化差异(也称为“XML 差异图”)并比较结果。例如,这就是 .NET 数据集跟踪变化的方式。
除此之外,您必须遍历 DOM 并将元素、属性和值相互比较。如果涉及模式,那么您还必须考虑位置等。
通常你想比较不同顺序的 XML 字符串。这可以用这段代码轻松完成
class Testing
{
[Test]
public void Test()
{
Assert.AreEqual(
"<root><a></a><b></b></root>".SortXml()
, "<root><b></b><a></a></root>".SortXml());
}
}
public static class XmlCompareExtension
{
public static string SortXml(this string @this)
{
var xdoc = XDocument.Parse(@this);
SortXml(xdoc);
return xdoc.ToString();
}
private static void SortXml(XContainer parent)
{
var elements = parent.Elements()
.OrderBy(e => e.Name.LocalName)
.ToArray();
Array.ForEach(elements, e => e.Remove());
foreach (var element in elements)
{
parent.Add(element);
SortXml(element);
}
}
}
我知道这个问题有多老,但我必须通过多个来源才能找到我正在寻找的答案。以下是使用 XNode.DeepEquals 但也忽略了属性顺序。在第一次提出这个问题 13 年后,我必须做大量的工作才能得出这个答案,我想其他人可能会觉得这个答案有帮助。
使用 NUnit 作为我的测试套件,您可以传入 2 个 XmlDocument 或一个 XmlDocument 和字符串。这会将 XmlDocuments 转换为 XDocuments,对每个节点的属性进行排序,然后执行 XNode.DeepEquals()。
Assert.That(XmlHelperService.XMLCompare(xmlDoc, expectedStr), Is.EqualTo(true));
Assert.That(XmlHelperService.XMLCompare(xmlDoc, expectedXmlDoc), Is.EqualTo(true));
代码
public class XmlHelperService
{
public static bool XMLCompare(XmlDocument primary, string secondaryStr)
{
XmlDocument secondary = new XmlDocument();
secondary.LoadXml(secondaryStr);
return XMLCompare(primary, secondary);
}
public static bool XMLCompare(XmlDocument primary, XmlDocument secondary)
{
return XNode.DeepEquals(NormalizeXElement(primary.ToXDocument().Root), NormalizeXElement(secondary.ToXDocument().Root));
}
private static XElement NormalizeXElement(XElement element)
{
return new XElement(element.Name,
element.Attributes().OrderBy(x => x.Name.ToString()),
element.Nodes().Select(n =>
{
XElement e = n as XElement;
if (e != null)
return NormalizeXElement(e);
return n;
})
);
}
}
public static class DocumentExtensions
{
public static XDocument ToXDocument(this XmlDocument xmlDocument)
{
using (var nodeReader = new XmlNodeReader(xmlDocument))
{
nodeReader.MoveToContent();
return XDocument.Load(nodeReader);
}
}
}