2つのXMLドキュメントをどのように比較しますか?
-
03-07-2019 - |
質問
いくつかの広範なユニットテストの基本クラスの一部として、C#(.NET)で1つのXmlDocumentオブジェクトのノードを別のXmlDocumentオブジェクトのノードと再帰的に比較するヘルパー関数を作成しています。これのいくつかの要件:
- 最初のドキュメントは、ソースです。 XMLドキュメントをどのように見せたいか。したがって、2番目は違いを見つけたいもので、最初のドキュメントにはない extra ノードを含めることはできません。
- 重要な違いが多すぎる場合は例外をスローする必要があり、説明を一目見ただけで簡単に理解できるはずです。
- 子要素の順序は重要です。属性は任意の順序で指定できます。
- 一部の属性は無視できます。具体的には
xsi:schemaLocation
とxmlns:xsi
ですが、どちらを渡すかを教えてください。 - 名前空間のプレフィックスは、属性と要素の両方で一致する必要があります。
- 要素間の空白は無関係です。
- 要素には、子要素または
InnerText
のいずれかがありますが、両方はありません。
一緒に何かを破棄している間:誰かがそのようなコードを書いていて、ここでそれを共有することは可能でしょうか
余談ですが、1番目と2番目のドキュメントを何と呼びますか?私はそれらを「ソース」と呼んでいます。と" target"ですが、 source は target のように見せたいので間違っていると感じます。そうでない場合は例外をスローします。
解決
Microsoftには、使用できるXML diff API があります p>
他のヒント
今日、この問題の解決策のより完全なリストを検索しましたが、そのうちの1つをすぐに試します:
- http://xmlunit.sourceforge.net/
- http://msdn.microsoft.com/en-us/library/ aa302294.aspx
- http://jolt.codeplex.com/wikipage? title = Jolt.Testing.Assertions.XML.Adaptors
- http://www.codethinked.com/checking- xml-for-semantic-equivalence-in-c
- https://vkreynin.wordpress.com/tag/xml/
- http:// gandrusz。 blogspot.com/2008/07/recently-i-have-run-into-usual-problem.html
- http://xmlspecificationcompare.codeplex.com/
- https://github.com/netbike/netbike.xmlunit
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つの異なる文字列に取得します。
- XSLTを使用して文字列を変換します(これにより、すべてが2つの新しい文字列にコピーされます)。これにより、要素の外側のすべてのスペースが確実に削除されます。これにより、2つの新しい文字列が作成されます。
- ここで、2つの文字列を互いに比較します。
これにより、違いの正確な場所がわかりませんが、違いがあるかどうかだけを知りたい場合は、サードパーティのライブラリなしで簡単に行えます。
現在は子の順序を無視するため、OPには関係ありませんが、コードのみのソリューションが必要な場合は、 XmlSpecificationCompareを試すことができます。 私はやや見当違い
自動テストで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
@Two Centsに基づく回答とこのリンクの使用 XMLSorting i独自の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;
}
}
}
}
このXSLT 1.0ベースの比較シートを作成し、b.xmlを入力xmlと比較し、b.xmlにない入力のアイテムの違いを出力します。