広範なユニットテストの基本クラスの一部として、C#(.NET)で1つのXmlDocumentオブジェクトのノードを別のオブジェクトと再帰的に比較するヘルパー関数を作成しています。これのいくつかの要件:
xsi:schemaLocation
およびxmlns:xsi
、私はどちらがどれを通過できるようにしたいのですが。InnerText
、両方ではありません。私は何かを一緒に廃棄している間:誰かがそのようなコードを書いていて、それをここで共有することは可能でしょうか?
余談ですが、最初のドキュメントと2番目のドキュメントを何と呼びますか?私はそれらを「ソース」および「ターゲット」と呼んでいましたが、sourceはtargetのように見えることを望んでいるので間違っています。例外。
Microsoftには XML diff API があり、これを使用できます。
非公式のNuGet: https://www.nuget.org/packages/XMLDiffPatch 。
今日、この問題の解決策のより完全なリストを検索しましたが、そのうちの1つをすぐに試してみます。
try XMLUnit 。このライブラリは、Javaと.Netの両方で利用可能です
XMLドキュメントの比較は複雑です。 Google for 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;
}
XMLファイルの比較に ExamXML を使用しています。あなたはそれを試すことができます。著者のA7Softは、XMLファイルを比較するためのAPIも提供しています
https://github.com/CameronWills/FatAntelope Microsoft XML Diff APIの別の代替ライブラリ。 2つのXMLドキュメントの順序付けられていない比較を行い、最適な一致を生成するXML差分アルゴリズムを備えています。
ここで説明するX-DiffアルゴリズムのC#ポートです: http://pages.cs.wisc.edu/~yuanwang/xdiff.html
免責事項:書きました:)
自動テストで2つのXML出力を比較するために、XNode.DeepEquals
。
すべての子孫ノードの値を含む2つのノードの値を比較します。
使用法:
var xDoc1 = XDocument.Parse(xmlString1);
var xDoc2 = XDocument.Parse(xmlString2);
bool isSame = XNode.DeepEquals(xDoc1.Document, xDoc2.Document);
//Assert.IsTrue(isSame);
参考: https://docs.Microsoft.com/en-us/dotnet/api/system.xml.linq.xnode.deepequals?view=netcore-2.2
これを行う別の方法は-
これにより、違いの正確な場所がわかりませんが、違いがあるかどうかだけを知りたい場合は、サードパーティのライブラリなしで簡単に行えます。
現在は子の順序を無視するため、OPには関係ありませんが、コードのみのソリューションが必要な場合は、 XmlSpecificationCompare which I やや見当違いの が開発されました。
このXSLT 1.0ベースの比較シートを作成し、b.xmlを入力xmlと比較して、b.xmlにない入力のアイテムの違いを出力します。
@Two Centsの回答に基づいてこのリンクを使用 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;
}
}
}
}