web-dev-qa-db-ja.com

C#での4者間XML比較

A、B、C、Dの4つのXMLファイルがあります。AとBの違いがCとDの違いと同じかどうかを知りたいです。

XMLファイルは、同じ.NETオブジェクトのシリアル化です。主な違いの1つは、特定の製品で使用可能な機能を説明する特定のリストにあります。 (機能の説明自体は別のオブジェクトです)。

4つすべての構造は非常に似ていますが、ある値には別の値があり、一部の値は変更される場合があります。たとえば、ドキュメントAを検討すると、

<xmldoc>
   <a></a>
   <c></c>
   <d></d>
<xmldoc>

ドキュメントB

<xmldoc>
   <a></a>
   <b></b> -- Added 
   <c></c> -- C and D are still ordered in the same way (except for the addition of <b>
   <d></d>
   <e></e> -- Also added, but it doesn't affect the sort of the other ones
<xmldoc>

次のドキュメントがあるとします。ドキュメントCはドキュメントAとまったく同じです:

<xmldoc>
   <a></a>
   <c></c>
   <d></d>
<xmldoc>

ドキュメントDはドキュメントBと同一です。

CDの違いはABの違いとまったく同じなので、これは合格です。ただし、代わりに次のようなドキュメントDがあるとします。

<xmldoc>
   <a></a>
   <b></b> 
   <f></f> <!-- Added -->
   <c></c>
   <d></d>
   <e></e>
   <f></f>
<xmldoc>

CDの違いは、ABの違いと同じではなくなりました。

ドキュメントAが次のように表示されるケースはないと確信しています。

<xmldoc>
   <c></c>
   <a></a> -- This is the same as the original document A except that this was reordered - this shouldn't happen
   <d></d>
<xmldoc>

私の最初の考えは、Microsoftの XML Diff Patch ライブラリを使用することでした。これは、2つのファイルを比較し、比較される2つのファイルの違いを説明するXMLドキュメントであるDiffGramを生成します。私の考えでは、AとBを比較してDiffGram Xを取得し、CとDを比較してDiffGram Yを取得してから、XとYの間で3番目のXML比較を実行できます。

アイデアは紙の上でいいですね。残念ながら、それほど単純ではありません。 AとBの違いはCとDの違いに非常に似ていますが、XとYは互いに似ていません。

問題は、次のようなDiffGramsを提供することです。

<xd:node match="4">
           <xd:node match="2">
              <xd:node match="1">
                 <xd:remove match="1-3" />
              </xd:node>
           </xd:node>

           <xd:node match="1">
              <xd:node match="1">
                 <xd:remove match="1-3" />
              </xd:node>
           </xd:node>
        </xd:node>

これには2つの問題があります。最初に、それは非常に不可解です-より人間が読める形式であることが望ましいですが、それは世界の終わりではありませんそうでない場合(私の主な目的はここではプログラマティックであるため)。第二に(そしてもっと重要なこととして)、それはその特定の比較に含まれる特定のXMLファイルと非常に密接に結びついているようです。

私はもともと、この目的に適しているが、推奨を得るのにあまり運がなかった.NETライブラリ(できればNuGetパッケージとして入手可能)の推奨を求めるSoftware Recommendation Stack Exchangeに投稿しました。 (完全な開示:その質問はまだ削除していませんが、まもなく削除する予定です)。そのようなライブラリが存在する場合、私はそれを見つけることができませんでした(それらの多くは、それらを使用したい目的のために設計されていないか、.NETフレームワーク用に作成されていないようです)。しかし、誰もがそのようなライブラリーが間違いなく受け入れられる解決策であることを知っている場合(事実、私はそれを自分で実装する必要があることを強く望みます)。

誰かがこのようなことを成功させましたか(独自のソリューションを作成するか、MicrosoftのXML Diffライブラリを使用するか、または別のサードパーティライブラリを使用することによって)?もしそうなら、あなたは何をしましたか?

私はこれが質問の幅が広すぎないことを望んでいます(もしそうなら私に知らせて編集します)、私がこれを自分で書くことになった場合、これに対する良いアプローチは何でしょうか?

私の考えでは、AとBを比較してDiffGram Xを取得し、CとDを比較してDiffGram Yを取得してから、XとYの間で3番目のXML比較を実行できます。

それは良いスタートのようです。ここで欠けているのは、「DiffGram X」を読み取り可能な表現X 'に変換するプログラムまたはxsltスクリプトのようなものだと思います。次に、同じ変換をDiffgram Yに適用して、判読可能なY 'を作成できます。 X 'とY'を比較すると、最終的なDiffGram Zが得られます。これは、読み取り可能なZ 'に変換される可能性があります。

このスクリプトまたはプログラムがどのように見えるかは、おそらく、入力ファイルの構造についてどのような想定ができるかに依存します。それらは本当に任意のネストされたXMLツリーで構成されていますか?属性、名前空間の違いの要素、要素のテキストも比較する必要がありますか? DiffGramsを単純化するためにその知識を使用できないとしたら、私は驚きます。

3
Doc Brown

XSLT 1.0を使用して2つのxmlファイルを比較するために、xslt差分シートを開発しました。 https://github.com/sflynn1812/xslt-diff-turbo

シートの上部にある変数を変更して、比較するファイルを指定します。

実際の例を以下に示します。たとえば、ファイルa.xmlがファイルb.xmlと比較される場合:

a.xml

<?xml version="1.0" encoding="utf-8" ?>
<a>
  <b>test c</b>
  <c>
    <d>test</d>
  </c>
  <b>test</b>
  <c>
    <d>test</d>
  </c>
  <b>test</b>
  <c>
    <d>test</d>
  </c>
</a>

b.xml

<?xml version="1.0" encoding="utf-8" ?>
<a>
  <b>test 2</b>
  <c>
    <d>test</d>
  </c>
  <b>test</b>
  <c>
    <d>test</d>
  </c>
  <b>test</b>
  <c>
    <d>test</d>
  </c>
</a>

出力は次のようになります。a.xmlの不一致は、tree-> mismatch内のb.xmlにはリストされません。 compare-> mismatchでa.xmlにないb.xml間の不一致:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <root>
    <tree>
      <mismatch>
        <a>
          <b>test 2</b>
        </a>
      </mismatch>
      <match>
        <a>
          <c>
            <d>test</d>/
          </c>
          <b>test</b>
          <c>
            <d>test</d>
          </c>
          <b>test</b>
          <c>
            <d>test</d>
          </c>
        </a>
      </match>
    </tree>
    <compare>
      <mismatch>
        <a>
          <b>test c</b>
        </a>
      </mismatch>
      <match>
        <a>
          <c>
            <d>test</d>
          </c>
          <b>test</b>
          <c>
            <d>test</d>
          </c>
          <b>test</b>
          <c>
            <d>test</d>
          </c>
        </a>
      </match>
    </compare>
  </root>
</root>

ドキュメントAとドキュメントB、ドキュメントCとドキュメントDの違いを確認しようとしている場合は、xpathクエリを使用して両方のファイルの一致しない出力を選択し、次にXSLTシートを3回実行します。違いの間。

1
Stephen Flynn

広義の答えです。 XML情報セットと呼ばれる推奨事項があります。

https://www.w3.org/TR/xml-infoset

2つのXMLドキュメントの違い(または「デルタ」)を計算し、その違いを比較する最も正確な方法は、API、コンポーネント(そのまま、拡張、またはカスタム)のサポートを使用した後だと思いますその勧告で最も忠実に定義された構成要素。

1
YSharp

変更のDiffGram表現は、この状況ではうまく機能しません。ファイルにパッチを適用することは問題ありませんが、このタイプのアプリケーションには実際にはありません。 DeltaXML を使用すると、AドキュメントとBドキュメントの違いをよりわかりやすく表現できます。

<xmldoc deltaxml:deltaV2="A!=B" deltaxml:version="2.0" deltaxml:content-type="full-context" xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1">
 <a deltaxml:deltaV2="A=B" />
 <b deltaxml:deltaV2="B" />
 <c deltaxml:deltaV2="A=B" />
 <d deltaxml:deltaV2="A=B" />
 <e deltaxml:deltaV2="B" />
</xmldoc>

次に、2番目の比較で非常によく似たものが得られます。CからDへのCはAのようなものですが、Dには要素が追加されています(ここではこれらのAとBを呼び出しているため、できる限り最初の結果に近い結果を取得しています。 ):

<xmldoc deltaxml:deltaV2="A!=B" deltaxml:version="2.0" deltaxml:content-type="full-context" xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1">
 <a deltaxml:deltaV2="A=B" />
 <b deltaxml:deltaV2="B" />
 <f deltaxml:deltaV2="B" />
 <c deltaxml:deltaV2="A=B" />
 <d deltaxml:deltaV2="A=B" />
 <e deltaxml:deltaV2="B" />
</xmldoc>

これは基本的な双方向比較です。これは.NETで利用できます。ご覧のように、これら2つの結果を比較して、有用なdiffを取得できます(名前空間を変更する必要があるため、デルタファイルは通常のファイルとして扱われます)。

XMLマージを使用することもできます(ただし、これはJavaのみ)ですが、1つのステージに進み、3つのファイルすべてを1つに表示します。AはCと同じなので、これを1つとして扱うことができます。 AとBの間、およびAとDの間の変化を知りたいのです。

<xmldoc deltaxml:deltaV2="A!=B!=D" deltaxml:version="2.0" deltaxml:content-type="full-context" xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1" xmlns:dxu="http://www.deltaxml.com/ns/unified-delta-v1">
 <a deltaxml:deltaV2="A=B=D" />
 <b deltaxml:deltaV2="B=D" />
 <f deltaxml:deltaV2="D" />
 <c deltaxml:deltaV2="A=B=D" />
 <d deltaxml:deltaV2="A=B=D" />
 <e deltaxml:deltaV2="B=D" />

それはおそらくあなたがここで必要なものです。最終的な目標が何であるかは言いません。たとえば、同時編集スタイルの更新を行う、つまり両方の編集パスで行われた変更をマージするなどです。あなたが発見したように、これはかなり難しいです!これがお役に立てば幸いです。ロビン

1