XMLDiff не может правильно распознать различия?

Что мне здесь не хватает? Есть ли вариант, что XMLDiff должен заботиться об именах элементов и искать лучшее соответствие для правильного распознавания следующих изменений?

класс Helper для сравнения двух файлов XML:

public class XMLDiffer
{
    public XDocument Diff(string originalXML, string changedXML)
    {
        //http://msdn2.microsoft.com/en-us/library/aa302294.aspx
        XmlDiff xmlDiff = new XmlDiff(XmlDiffOptions.IgnoreChildOrder | XmlDiffOptions.IgnoreComments | XmlDiffOptions.IgnoreWhitespace);

        xmlDiff.Algorithm = XmlDiffAlgorithm.Precise;
        StringBuilder diffgramStringBuilder = new StringBuilder();
        bool xmlComparisonResult = false;
        using (StringReader legacySr = new StringReader(originalXML), nextgenSr = new StringReader(changedXML))
        {
            using (XmlReader legacyReader = XmlReader.Create(legacySr), nextgenReader = XmlReader.Create(nextgenSr))
            {
                using (StringWriter sw = new StringWriter(diffgramStringBuilder))
                {
                    using (XmlWriter diffgramWriter = XmlWriter.Create(sw))
                    {
                        xmlComparisonResult = xmlDiff.Compare(legacyReader, nextgenReader, diffgramWriter);
                    }
                }
            }
        }
        XDocument xdoc = XDocument.Parse(diffgramStringBuilder.ToString());
        return xdoc;
    }

    public string GetChangeHtml(string originalXML, string changedXML)
    {
        XmlDiffView view = new XmlDiffView();
        var diffgram = Diff(originalXML, changedXML);
        string ret = "";
        using (StringReader legacySr = new StringReader(originalXML), diffGramSr = new StringReader(diffgram.ToString()))
        {
            using (XmlReader legacyReader = XmlReader.Create(legacySr), diffgramReader = XmlReader.Create(diffGramSr))
            {
                using (StringWriter sw = new StringWriter())
                {
                    view.Load(legacyReader, diffgramReader);
                    view.GetHtml(sw);
                    ret = sw.ToString();
                }
            }
        }
        return ret;
    }

}

Со следующим тестом:

[TestMethod]
public void XMLDiff_AreNotSame_GetChangeHtmlAll()
{
    //Arrange
    string source = "<root><child>some text</child><child>more text</child><child1>REMOVED</child1></root>";
    //Ordering of the generic child nodes is not changed,  but it might
    string target = "<root><child>some text CHANGE</child><child>more text</child><child>ADDITION</child></root>";

    XMLDiffer differ = new XMLDiffer();

    //Act
    var diffview = differ.GetChangeHtml(source, target);

    //Assert
    Assert.IsNotNull(diffview);
}

Создает следующее (добавлены элементы html и table): https://pste.eu/p/Fm7Z.html

Подробнее о библиотеке: http://msdn2.microsoft.com/en-us/library/aa302294.aspx

Ссылка Nuget для ссылок: https://www.nuget.org/packages/XMLDiffPatch/

1 ответ

Решение

В итоге я реализовал следующие классы, чтобы получить изменения:

public class XMLComparer : IEqualityComparer<XNode>
{
    public bool Equals(XNode e1, XNode e2)
    {
        if (!(e1 is XElement)) return true;
        if (!(e2 is XElement)) return false;
        var el1 = e1 as XElement;
        var el2 = e2 as XElement;
        return Tuple.Create(el1.Name, el1.Value).Equals(Tuple.Create(el2.Name, el2.Value));
    }

    public int GetHashCode(XNode n)
    {
        if (!(n is XElement)) return 0;
        var el = n as XElement;
        return Tuple.Create(el.Name, el.Value).GetHashCode();
    }

}

public class XMLDifference
{
    public bool IsNew { get; set; }
    public XElement Node { get; set; }
}

public class XMLDifferenceComparer
{
    public List<XMLDifference> GetDifferences(string original, string changed)
    {
        List<XMLDifference> ret = new List<XMLDifference>();
        var originalDoc = XDocument.Parse(original);
        var changedDoc = XDocument.Parse(changed);
        //Get differences that are present in new xml version
        var differences = changedDoc.Root.Descendants().Except(originalDoc.Root.Descendants(), new XMLComparer());
        ret.AddRange(GetList(differences, true));
        //Get differences that have changed since the old xml version
        var oldValues = originalDoc.Root.Descendants().Except(changedDoc.Root.Descendants(), new XMLComparer());
        ret.AddRange(GetList(oldValues, false));
        return ret;
    }

    private List<XMLDifference> GetList(IEnumerable<XNode> nodes, bool isNew)
    {
        List<XMLDifference> ret = new List<XMLDifference>();
        foreach (XNode d in nodes)
        {
            var diff = new XMLDifference();
            diff.IsNew = isNew;

            var el = d as XElement;
            diff.Node = el;
            ret.Add(diff);
        }
        return ret;
    }
}

Он может распознавать изменения, но не является специфичным для элемента, он не может отобразить, какой именно элемент был изменен и как, вызванный отсутствием уникальных идентификаторов для каждого элемента.

Основная идея для этого решения пришла отсюда: https://gist.github.com/krcourville/6933451

Другие вопросы по тегам