Как проверить на равенство узлы xml, содержащиеся в разных файлах xml?

У меня есть два файла XML (файл A и файл B, где файл A является подмножеством файла B), которые я прочитал с помощью метода System.Xml.XmlDocument.LoadXml(fileName).

Затем я выбираю узлы в этих файлах с помощью System.Xml.XmlNode.SelectNodes(nodeName). Мне нужно сравнить, что каждый выбранный узел xml в файле A либо равен, либо является подмножеством того же узла в файле B. узел в файле A совпадает с порядком тех же подузлов, содержащихся в этом узле в файле B.

Например,

fileA

<rootNodeA>
 <elementA>
  <subelementA>content</subElementA>
  <subelementB>content</subElementB>
  <subelementB>content</subElementC>
  <subelementB>content</subElementD>
 </elementA>
 <elementB>
  <subelementA>content</subElementA>
  <subelementB>content</subElementB>
 </elementB>
</rootNodeA>

fileB

<rootNodeB>
 <elementA>
  <subelementB>content</subElementB>
  <subelementD>content</subElementD>
 </elementA>
 <elementB>
  <subelementA>content</subElementA>
 </elementB>
</rootNodeB>

Как видите, fileB - это подмножество fileA. Мне нужно проверить, что узел elementA файла B равен или является подмножеством того же узла elementA в файле A. Это должно быть верно для подузлов (subElementA и т. д.), А также содержимого узлов / подузлов.

Кроме того, если вы видите elementA в файле A, имеется 4 подэлементы в порядке A, B, C, D. Для того же самого elementA в файле B есть 2 подэлементы в порядке A, D. Этот порядок, то есть A предшествует D, такой же, как порядок в файле A, это также необходимо проверить.

Моя идея состоит в том, чтобы вычислить хэши узлов, а затем сравнить их, но я не уверен, как и будет ли это соответствовать цели.

Обновлено: Код, который у меня есть,

    HashSet<XmlElement> hashA = new HashSet<XmlElement>();
    HashSet<XmlElement> hashB = new HashSet<XmlElement>();

                foreach (XmlElement node in nodeList)
                {
                    hashA.Add(node);
                }
                foreach(XmlElement node in masterNodeList)
                {
                    hashB.Add(node);
                }
                isSubset = new HashSet<XmlElement>(hashA).IsSubsetOf(hashB);
            return isSubset;

У вас есть четкая цель, но пробовали ли вы что-нибудь еще? Если да, не могли бы вы отредактировать соответствующий код в своем вопросе?

Broots Waymb 13.09.2018 20:46

Как быстро это должно быть? Вы заботитесь об этом (для небольших файлов, таких как 1 МБ или меньше, вам не нужно делать какое-либо решение с длинным кодом (-> означает быстрое и более сложное)). Также - вас волнует контент - должно ли оно быть таким же или только подэлементами?

kademat 13.09.2018 20:49

Вы не можете проверить равенство с помощью хешей, только неравенство. Если вы хотите проверить, является ли B подмножеством A; пройтись по каждому элементу B и проверить, содержит ли A этот элемент.

Dour High Arch 13.09.2018 20:57

Я добавил код, который у меня есть @BrootsWaymb

vdrog 13.09.2018 20:58

@kademat Меня не волнует скорость, мне важно, чтобы контент был одинаковым.

vdrog 13.09.2018 20:59

Экземпляры XmlElement несопоставимы. Два элемента с одинаковой разметкой все равно не будут одинаковыми объект, особенно если они принадлежат разным документам. Что еще хуже, XML допускает разные, но эквивалентные способы записи одного и того же элемента, поэтому обычно вам нужно применить некоторую форму канонизации XML, прежде чем вы начнете сравнивать вещи.

Jeroen Mostert 13.09.2018 21:02
1
6
180
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

это звучит как простая рекурсивная функция.

не проверял, действительно ли это работает, но это должно сработать:

public static bool isSubset(XmlElement source, XmlElement target)
    {
        if (!target.HasChildNodes)
        {
            if (source.HasChildNodes) // surly not same.
                return false;
            return string.Equals(source.Value, target.Value); // equalize values.
        }

        var sourceChildren = source.ChildNodes.OfType<XmlElement>().ToArray(); // list all child tags in source (by order)
        var currentSearchIndex = 0; // where are we searching from (where have we found our match)

        foreach (var targetChild in target.ChildNodes.OfType<XmlElement>())
        {
            var findIndex = Array.FindIndex(sourceChildren, currentSearchIndex, el => el.Name == targetChild.Name);
            if (findIndex == -1)
                return false; // not found in source, therefore not a subset.

            if (!isSubset(sourceChildren[findIndex], targetChild))
                return false; // if the child is not a subset, then parent isn't too.

            currentSearchIndex = findIndex; // increment our search index so we won't match nodes that already passed.
        }
    }

Это не будет проверять, равно ли содержимое источника и цели.

vdrog 13.09.2018 22:35

просто добавьте условие, если Children.count == 0 ... проверить содержимое

Tomer W 13.09.2018 22:50

Он возвращается как false для двух одинаковых элементов, не зная, как отлаживать ваше решение.

vdrog 13.09.2018 23:47

использовать визуальную студию.

Tomer W 14.09.2018 06:52

Спасибо за совет @Tomer W, проблема заключалась в том, что он также захватил пробелы, загрузка файлов изначально с помощью XMLDocument.PreserveWhitespace = false решила эту проблему.

vdrog 14.09.2018 18:59

Молодец. Кроме того, вы можете использовать string.Equals(source.Value.Trim(), target.Value.Trim());, чтобы игнорировать пробелы при сопоставлении.

Tomer W 14.09.2018 19:44

Позвольте нам продолжить обсуждение в чате.

vdrog 14.09.2018 21:17

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