Подтвердить что ты не робот

Слияние XML-документов

Все решения, с которыми я столкнулся в отношении слияния документов XML, не выполняют то, что я желаю. Позвольте мне объяснить:

XML-документ 1:

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b title="Original Section">
        <b title="Original Child Section"></b>
        <b title="Original Child Section 2"></b>
    </b>
</a>

Документ XML 2:

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b title="New Section">
        <b title="New Child Section"></b>
    </b>
    <b title="Original Section">
        <b title="Original Child Section">
            <b title="New Child For Old Section"></b>
        </b>
    </b>    
</a>

В заключительный документ вроде этого:

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b title="Original Section">
        <b title="Original Child Section">
            <b title="New Child For Old Section"></b>
        </b>
        <b title="Original Child Section 2"></b>
    </b>    
    <b title="New Section">
        <b title="New Child Section"></b>
    </b>
</a>

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

Приветствия и благодарности заранее!

* EDIT *

Поскольку консенсус в том, что петли и рекурсия являются обязательными, какой был бы самый элегантный и эффективный способ достичь этого? Я полагаю, что другой фундаментальный вопрос к этой проблеме - лучший способ сравнить узлы по мере того, как вы итерации?

4b9b3361

Ответ 1

В конце концов любое решение этой проблемы будет сводиться к циклам и/или рекурсии. Вы говорите основную теорию множеств, и linq может быть полезен для дистилляции процесса, но в конечном итоге он будет итерировать оба набора и слить результаты.

Ответ 2

Я бы написал IEqualityComparer, который указывает, когда два узла являются "совпадением", то есть устанавливает правило соответствия названия.

class XElementComparer : IEqualityComparer<XElement>
{
    public bool Equals(XElement x, XElement y)
    {
        var xTitle = x.Attribute("title");
        var yTitle = y.Attribute("title");

        if (xTitle == null || yTitle == null) return false;

        return xTitle.Value == yTitle.Value;
    }

    public int GetHashCode(XElement obj)
    {
        return base.GetHashCode();
    }
}

И затем напишите рекурсивный метод для траления через ваш XML, объединив узлы, которые соответствуют в соответствии с компаратором.

private XElement Merge(XElement node1, XElement node2)
{
    // trivial cases
    if (node1 == null) return node2;
    if (node2 == null) return node1;

    var elements1 = node1.Elements();
    var elements2 = node2.Elements();

    // create a merged root
    var result = new XElement(node1.Name, node1.Attribute("title")); 

    var comparer = new XElementComparer();
    var mergedNodes = elements1.Union(elements2, comparer).ToList();

    // for the union of the elements, insert their merge values
    foreach (var title in mergedNodes)
    {
        var child1 = elements1.SingleOrDefault(e => comparer.Equals(e, title));
        var child2 = elements2.SingleOrDefault(e => comparer.Equals(e, title));

        result.Add(Merge(child1, child2));
    }

    return result;
}