Сравнение XmlDocument для равенства (по содержанию)

Если я хочу сравнить содержимое XMlDocument, это просто так?

XmlDocument doc1 = GetDoc1();
XmlDocument doc2 = GetDoc2();

if(doc1 == doc2)
{

}

Я не проверяю, являются ли они одной и той же ссылкой на объект, но если содержимое xml одинаковое.

5 ответов


нет. XmlDocument не переопределяет поведение Equals() метод таким образом, на самом деле это просто выполнение ссылочного равенства, которое потерпит неудачу в вашем примере, если документы на самом деле не являются тем же экземпляром объекта.

Если вы хотите сравнить содержимое (атрибуты, элементы, commments, PIs и т. д.) документа, вам придется реализовать эту логику самостоятельно. будьте осторожны: это не тривиально.

в зависимости от вашего точный сценарий, вы можете удалить все несущественные пробелы из документа (что само по себе может быть сложно) и сравнить полученный xml-текст. Это не идеально-он терпит неудачу для документов, которые семантически идентичны, но отличаются такими вещами, как использование и объявление пространств имен или экранирование определенных значений или нет, порядок элементов и т. д. Как я уже говорил, сравнение XML не является тривиальным.

также необходимо четко определить, что это означает, что два XML-документа должны быть "идентичными". имеет ли значение упорядочение элементов или атрибутов? Имеет ли значение case (в текстовых узлах)? Следует ли игнорировать лишние разделы CDATA? Учитываются ли инструкции по обработке? Как насчет полностью квалифицированных и частично квалифицированных пространств имен?

в любой реализации общего назначения вы, вероятно, захотите преобразовать оба документа в некоторую каноническую форму (будь то XML или какое-либо другое представление), а затем сравнить канонизированный содержание.

уже существуют инструменты, которые выполняют XML-дифференцирование, например Microsoft XML Diff / Patch, вы можете использовать это для выявления различий между двумя документами. Насколько мне известно, этот инструмент не распространяется в исходной форме ... поэтому, чтобы использовать его во встроенном приложении, вам нужно будет написать сценарий процесса (если вы планируете его использовать, сначала убедитесь, что условия лицензирования позволяют его использовать и перераспределение.)

EDIT: проверить @Max Toro's answer если вы используете .NET 3.5 SP1, так как, по-видимому, в XLinq есть опция, которая может быть полезна. Приятно знать, что она существует.


попробовать DeepEquals метод в API XLinq.

XDocument doc1 = GetDoc1(); 
XDocument doc2 = GetDoc2(); 

if(XNode.DeepEquals(doc1, doc2)) 
{ 

} 

см. также семантика равенства деревьев LINQ to XML


простой способ может быть сравнить 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);

LBushkin прав, это не тривиально. Поскольку XML-это строковые данные, вы можете технически выполнить хэш содержимого и сравнить их, но это будет зависеть от таких вещей, как пробелы.

вы можете выполнить структурированный diff (также называемый "XML diffgram") между двумя документами и сравнить результаты. Так, например, наборы данных .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);
        }
    }
}