Как бы вы сравнили два XML-документа?
в рамках базового класса для некоторого обширного модульного тестирования я пишу вспомогательную функцию, которая рекурсивно сравнивает узлы одного объекта XmlDocument с другим в C# (.NET). некоторые требования этого:
- первый документ-это источник, например, что я хочу, чтобы XML-документ выглядел. Таким образом, второй-это тот, в котором я хочу найти различия, и он не должен содержать дополнительно узлы не в первой документ.
- должно быть исключение, когда слишком много существенных различий найдено, и это должно быть легко понято человеком, взглянувшим на описание.
- порядок дочерних элементов важен, атрибуты могут быть в любом порядке.
- некоторые атрибуты игнорируются; в частности
xsi:schemaLocation
иxmlns:xsi
, хотя я хотел бы иметь возможность пройти, в каких из них находятся. - префиксы пространств имен должны совпадать в обоих атрибутов и элементы.
- пробелы между элементами не имеет значения.
- элементы или есть дочерние элементы или
InnerText
, но не оба.
пока я что-то ломаю вместе: кто-нибудь написал такой код и можно ли поделиться им здесь?
в стороне, как бы вы назвали первый и второй документы? Я имел в виду их как "источник" и "цель", но он чувствует неправильно, так как источник это то, что я хочу цель выглядеть, иначе я бросаю исключение.
11 ответов:
Microsoft, имеет XML diff API что вы можете использовать
попробовать XMLUnit. Эта библиотека доступна как для Java, так и для .Net
сравнение XML-документов является сложным. Google для xmldiff (есть даже решение Microsoft) для некоторых инструментов. Я решил это несколькими способами. Я использовал XSLT для сортировки элементов и атрибутов (потому что иногда они появлялись в другом порядке, и мне было все равно), и отфильтровывал атрибуты, которые я не хотел сравнивать, а затем либо использовал XML:: Diff или XML:: SemanticDiff модуль perl, или довольно напечатанный каждый документ с каждым элементом и атрибут на отдельной строке, и с помощью командной строки Unix diff на результаты.
этот код не удовлетворяет всем вашим требованиям, но он прост, и я использую его для своих модульных тестов. Порядок атрибутов не имеет значения, но порядок элементов имеет значение. Элемент внутренний текст не сравнивается. Я также игнорировать регистр при сравнении атрибутов, но вы можете легко удалить эту.
public bool XMLCompare(XElement primary, XElement secondary) { if (primary.HasAttributes) { if (primary.Attributes().Count() != secondary.Attributes().Count()) return false; foreach (XAttribute attr in primary.Attributes()) { if (secondary.Attribute(attr.Name.LocalName) == null) return false; if (attr.Value.ToLower() != secondary.Attribute(attr.Name.LocalName).Value.ToLower()) return false; } } if (primary.HasElements) { if (primary.Elements().Count() != secondary.Elements().Count()) return false; for (var i = 0; i <= primary.Elements().Count() - 1; i++) { if (XMLCompare(primary.Elements().Skip(i).Take(1).Single(), secondary.Elements().Skip(i).Take(1).Single()) == false) return false; } } return true; }
другой способ сделать это -
- получить содержимое обоих файлов в две разные строки.
- преобразуйте строки с помощью XSLT (который просто скопирует все в две новые строки). Это гарантирует, что все пробелы вне элементов будут удалены. Это приведет его к двум новым строкам.
- Теперь просто сравните две строки друг с другом.
Это не даст вам точное местоположение разница, но если вы просто хотите знать, есть ли разница, это легко сделать без каких-либо сторонних библиотек.
Я использую ExamXML для сравнения XML-файлов. Ты можешь попробовать. Авторы, A7Soft, также предоставляют API для сравнения XML-файлов
https://github.com/CameronWills/FatAntelope Еще одна альтернативная библиотека для Microsoft XML diff API. Он имеет алгоритм XML diffing для выполнения неупорядоченного сравнения двух XML-документов и получения оптимального соответствия.
Это порт C# алгоритма X-Diff, описанного здесь: http://pages.cs.wisc.edu / ~yuanwang/xdiff.html
отказ от ответственности: я это написал :)
не относится к OP, так как в настоящее время он игнорирует дочерний порядок, но если вы хотите только код решения, вы можете попробовать XmlSpecificationCompare что я несколько ошибочно развитые.
на основе @два цента ответа и с помощью этой ссылки XMLSorting Я создал свой собственный XmlComparer
сравнить программу XML
private static bool compareXML(XmlNode node, XmlNode comparenode) { if (node.Value != comparenode.Value) return false; if (node.Attributes.Count>0) { foreach (XmlAttribute parentnodeattribute in node.Attributes) { string parentattributename = parentnodeattribute.Name; string parentattributevalue = parentnodeattribute.Value; if (parentattributevalue != comparenode.Attributes[parentattributename].Value) { return false; } } } if(node.HasChildNodes) { sortXML(comparenode); if (node.ChildNodes.Count != comparenode.ChildNodes.Count) return false; for(int i=0; i<node.ChildNodes.Count;i++) { string name = node.ChildNodes[i].LocalName; if (compareXML(node.ChildNodes[i], comparenode.ChildNodes[i]) == false) return false; } } return true; }
сортировка XML-программы
private static void sortXML(XmlNode documentElement) { int i = 1; SortAttributes(documentElement.Attributes); SortElements(documentElement); foreach (XmlNode childNode in documentElement.ChildNodes) { sortXML(childNode); } } private static void SortElements(XmlNode rootNode) { for(int j = 0; j < rootNode.ChildNodes.Count; j++) { for (int i = 1; i < rootNode.ChildNodes.Count; i++) { if (String.Compare(rootNode.ChildNodes[i].Name, rootNode.ChildNodes[1 - 1].Name) < 0) { rootNode.InsertBefore(rootNode.ChildNodes[i], rootNode.ChildNodes[i - 1]); } } } // Console.WriteLine(j++); } private static void SortAttributes(XmlAttributeCollection attribCol) { if (attribCol == null) return; bool changed = true; while (changed) { changed = false; for (int i = 1; i < attribCol.Count; i++) { if (String.Compare(attribCol[i].Name, attribCol[i - 1].Name) < 0) { //Replace attribCol.InsertBefore(attribCol[i], attribCol[i - 1]); changed = true; } } } }