web-dev-qa-db-ja.com

2つのXMLドキュメントをどのように比較しますか?

広範なユニットテストの基本クラスの一部として、C#(.NET)で1つのXmlDocumentオブジェクトのノードを別のオブジェクトと再帰的に比較するヘルパー関数を作成しています。これのいくつかの要件:

  • 最初のドキュメントはsourceです。 XMLドキュメントをどのように見せたいか。したがって、2番目は私が違いを見つけたいもので、最初のドキュメントにないextraノードを含んではいけません。
  • あまりにも多くの重要な違いが見つかった場合に例外をスローする必要があり、説明を一目見ただけで簡単に理解できるはずです。
  • 子要素の順序は重要です。属性の順序は任意です。
  • 一部の属性は無視できます。特にxsi:schemaLocationおよびxmlns:xsi、私はどちらがどれを通過できるようにしたいのですが。
  • 名前空間のプレフィックスは、属性と要素の両方で一致する必要があります。
  • 要素間の空白は無関係です。
  • 要素にはeither子要素orInnerText、両方ではありません。

私は何かを一緒に廃棄している間:誰かがそのようなコードを書いていて、それをここで共有することは可能でしょうか?

余談ですが、最初のドキュメントと2番目のドキュメントを何と呼びますか?私はそれらを「ソース」および「ターゲット」と呼んでいましたが、sourcetargetのように見えることを望んでいるので間違っています。例外。

59

Microsoftには XML diff API があり、これを使用できます。

非公式のNuGet: https://www.nuget.org/packages/XMLDiffPatch

54
Danimal
7
Andrej Adamenko

try XMLUnit 。このライブラリは、Javaと.Netの両方で利用可能です

XMLドキュメントの比較は複雑です。 Google for xmldiff(Microsoftのソリューションもあります)の一部のツール。これをいくつかの方法で解決しました。 XSLTを使用して要素と属性を並べ替え(時々、それらは異なる順序で表示されるため、気にしませんでした)、比較したくない属性をフィルターで除外してから、 XML :: Diff または XML :: SemanticDiff Perlモジュール、または各ドキュメントをすべての要素と属性を別々の行に印刷し、結果にUnixコマンドラインdiffを使用します。

5
runrig

このコードはすべての要件を満たしているわけではありませんが、単純であり、ユニットテストに使用しています。属性の順序は重要ではありませんが、要素の順序は重要です。要素の内部テキストは比較されません。また、属性を比較するときに大文字と小文字を区別しませんでしたが、簡単に削除できます。

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;
}
4
Two Cents

XMLファイルの比較に ExamXML を使用しています。あなたはそれを試すことができます。著者のA7Softは、XMLファイルを比較するためのAPIも提供しています

3
Alex Gulin

https://github.com/CameronWills/FatAntelope Microsoft XML Diff APIの別の代替ライブラリ。 2つのXMLドキュメントの順序付けられていない比較を行い、最適な一致を生成するXML差分アルゴリズムを備えています。

ここで説明するX-DiffアルゴリズムのC#ポートです: http://pages.cs.wisc.edu/~yuanwang/xdiff.html

免責事項:書きました:)

3
cwills

自動テストで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

2
Mirek

これを行う別の方法は-

  1. 両方のファイルの内容を2つの異なる文字列に取得します。
  2. XSLTを使用して文字列を変換します(すべてを2つの新しい文字列にコピーします)。これにより、要素の外側のすべてのスペースが確実に削除されます。これにより、2つの新しい文字列が作成されます。
  3. 次に、2つの文字列を互いに比較します。

これにより、違いの正確な場所がわかりませんが、違いがあるかどうかだけを知りたい場合は、サードパーティのライブラリなしで簡単に行えます。

2
Do Will

現在は子の順序を無視するため、OPには関係ありませんが、コードのみのソリューションが必要な場合は、 XmlSpecificationCompare which I やや見当違いの が開発されました。

2
Eli Algranti

このXSLT 1.0ベースの比較シートを作成し、b.xmlを入力xmlと比較して、b.xmlにない入力のアイテムの違いを出力します。

https://github.com/sflynn1812/xslt-diff

0
Stephen Flynn

@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;

                }
            }
        }
    }
0
Chetan Mehra