ヘッダーをスキップ
Oracle XML Developer's Kitプログラマーズ・ガイド
11gリリース1(11.1)
E05676-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

21 Cを使用したXML差分の検出

Oracle XDKに含まれているコンポーネントを使用して、2つのXML文書の内容の差分を確認し、片方のXML文書に差分(パッチ)を適用できます。

この章の内容は次のとおりです。

CにおけるXMLDiffの概要

Oracle XmlDiffを使用して、類似した2つのXML文書の差分を定義できます。XmlDiffにより差分を示すXdiffインスタンス・ドキュメントが生成されます。Xdiffインスタンス・ドキュメントは、XMLスキーマの1つであるXdiffスキーマに準拠するXML文書です。

XmlPatchを使用して、Xdiffインスタンス・ドキュメントを受け取り、他の文書に変更を適用できます。これを使用して、多くのXML文書に同一の変更を適用できます。

XmlDiffは、DOM APIの入力および出力のみを目的としてサポートされています。

XmlPatchもまた、DOMの入力およびパッチ文書をサポートしています。

XmlDiffおよびXmlPatchは、C APIまたはコマンドライン・ツールを介して使用でき、2つのSQL関数により表示されます。

XmlHash C APIは、XMLツリーまたはサブツリーのハッシュ値を計算するために提供されます。2つのツリーまたはサブツリー間のハッシュ値が同数の場合、これらのツリーは非常に高い確率で同一です。

XMLDiffに関するプロセスのフロー

このプロセスのフローは、次のとおりです。

  1. XmlDiffを使用して2つの入力文書を比較します。

  2. XmlDiffにより、Xdiffインスタンス・ドキュメントが作成されます。

  3. 必要に応じて、Xdiffインスタンス・ドキュメントをXmlPatchに渡すことができます。

  4. XmlPatchを使用して、比較によって検出された差分を指定した他のドキュメントに適用できます。

XmlDiffの使用

XmlDiffを使用して、2つの入力文書を示すツリーを比較し差分を検出します。

この2つの入力文書では、同一のキャラクタ・セット・エンコーディングを使用する必要があります。Xdiff(出力)インスタンス・ドキュメントには、入力文書のデータ・エンコーディングと同一のエンコーディングが含まれます。

最適化に関するユーザー・オプション

比較に関して、最適化と呼ばれる2つのオプションがあります。

  • グローバル最適化: デフォルト

    文書ツリー全体が比較されます。

  • ローカル最適化

    兄弟関係のレベルで比較が行われます。ローカル最適化では、2つのツリーの対応する親の下にある兄弟関係が比較されます。

グローバル最適化では、大きな文書に対してより多くの時間および領域を使用できますが、生成されるのは常に最小の差分セット(最適差分)です。ローカル最適化の方が処理速度は速いですが、最適差分は生成されない場合があります。

ハッシュに関するユーザー・オプション

一般的に、ハッシュによりグローバル最適化が早くなりますが、質が若干落ちる可能性もあります。ローカル最適化では、ハッシュにより差分出力の質が改善されます。異なるハッシュのレベルを使用すると、ローカル差分およびグローバル差分の両方が生成される可能性があります。

ローカルおよびグローバルの両方の最適化に関するハッシュの使用を指定できます。

ハッシュを指定するには、hashLevelパラメータを入力します。hashLevelが1以上の場合、DOMHash値を使用して、差分がdepth >= hashLevelのすべてのサブツリーを比較できます。ハッシュ値が同一の場合は、サブツリーも同一と推定されます。

XmlDiffでの入力文書の見方

XmlDiffは、比較の実行中、属性順に差分を無視します。

XmlDiffはDocType宣言を無視します。ファイルはDTDに対して検証されません。

名前空間の接頭辞が同一の名前空間URIを参照する場合は、XmlDiffは名前空間の接頭辞における差分を無視します。それ以外の場合で、2つのノードに同じローカル名および内容が含まれていて名前空間URIが異なる場合は、差分が明示されます。


注意:

XmlDiffは入力文書上で、スキーマに基づかない方法で動作します。要素または属性上で、型を認識する方法では動作しません。

XmlDiffコマンドライン・ユーティリティの使用

表21-1に、コマンドライン・オプションを示します。

表21-1 C言語に関するコマンドライン・オプション

オプション 説明

-eエンコーディング

デフォルトの入力ファイルのエンコーディングを指定します。XMLファイルでエンコーディングが指定されていない場合、このエンコーディングは入力対象とみなされます。

-Eエンコーディング

出力/データのエンコーディングを指定します。DOMおよびXdiffインスタンス・ドキュメントはこのエンコーディングで作成されます。デフォルトはUTF8です。

-h hashLevel

ハッシュのレベルを指定します。0レベルがないことを意味します。

1以上の場合、サブツリーにハッシュを使用します。

-g

グローバル最適化(デフォルト)を設定します。

-l

ローカル最適化を設定します。

-p

使用方法のヘルプを表示します。

-u

更新操作の無効にします。


入力文書のサンプル

例21-1は、XmlDiffおよびXmlPatchの使用による更新を説明するxml文書のサンプルです。いくつかの変更が続きます。

例21-1 book1.xml

<?xml version="1.0"?>
<booklist xmlns="http://booklist.oracle.com">
  <book>
    <title>Twelve Red Herrings</title>
    <author>Jeffrey Archer</author>
    <publisher>Harper Collins</publisher>
    <price>7.99</price>
  </book>
  <book>
    <title language="English">The Eleventh Commandment</title>
    <author>Jeffrey Archer</author>
    <publisher>McGraw Hill</publisher>
    <price>3.99</price>
  </book>
  <book>
    <title language="English" country="USA">C++ Primer</title>
    <author>Lippmann</author>
    <publisher>Harper Collins</publisher>
    <price>4.99</price>
  </book>
  <book>
    <title>Emperor's New Mind</title>
    <author>Roger Penrose</author>
    <publisher>Oxford Publishing Company</publisher>
    <price>15.9</price>
  </book>
  <book>
    <title>Evening News</title>
    <author>Arthur Hailey</author>
    <publisher>MacMillan Publishers</publisher>
    <price>9.99</price>
  </book>
</booklist>

次にあげる結果を除いて、例21-1「book1.xml」に非常によく似たbook2.xmlという別ファイルがあるとします。

「The Eleventh Commandment」を削除(delete-node操作の1つ)。

「C++ Primer」の国コードを米国から英国に変更(update-node操作の1つ)。

「Emperor's New Mind」に説明を追加(append-node操作の1つ)。

「Evening News」に版を追加(insert-node-before操作の1つ)。

「Evening News」の価格を更新(update-node操作の1つ)。

Xdiffインスタンス・ドキュメントのサンプル

この項では、前の項で説明された2つのXMLファイルの比較により生成されたXdiffインスタンス・ドキュメントを示します。次の項では、XML処理命令およびこの文書での操作について説明します。

次のようなXmlDiffを起動できます。

> xmldiff book1.xml book2.xml

この表では、引数およびフラグに関するサンプル・アプリケーションについても見ることができます。

例21-2 Xdiffインスタンス・ドキュメントのサンプル

<?xml version="1.0" encoding="UTF-8"?>
<xd:xdiff xsi:schemaLocation="http://xmlns.oracle.com/xdb/xdiff.xsd
xmlns:xd="http://xmlns.oracle.com/xdb/xdiff.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oraxdfns_0="http://booklist.oracle.com">
    <?oracle-xmldiff operations-in-docorder="true" output-model="snapshot" 
        diff-algorithm="global"?> 
    <xd:delete-node xd:node-type="element" xd:xpath="/oraxdfns_0
              :booklist[1]/oraxdfns_0:book[2]"/>
    <xd:update-node xd:node-type="attribute"
         xd:parent-xpath="/oraxdfns_0:booklist[1]/oraxdfns_0:book[3]/oraxdfns_0
              :title[1]" xd:attr-local="country">
                <xd:content>US</xd:content>
    </xd:update-node>
    <xd:append-node xd:node-type="element" xd:parent-xpath="/oraxdfns_0
              :booklist[1]/oraxdfns_0:book[4]">
        <xd:content>
            <oraxdfns_0:description> This is a classic </oraxdfns_0:description>
        </xd:content>
    </xd:append-node>
    <xd:insert-node-before xd:node-type="element" xd:xpath="/oraxdfns_0
              :booklist[1]/oraxdfns_0:book[5]/oraxdfns_0:author[1]">
        <xd:content>
            <oraxdfns_0:edition>Hardcover</oraxdfns_0:edition>
        </xd:content>
    </xd:insert-node-before>
    <xd:update-node xd:node-type="text" xd:xpath="/oraxdfns_0
           :booklist[1]/oraxdfns_0:book[5]/oraxdfns_0:price[1]/text()[1]">
        <xd:content>12.99</xd:content>
    </xd:update-node>
</xd:xdiff>

出力モデルおよびXML処理命令

Xdiffインスタンス・ドキュメントは、XML処理命令(前の項の太字表示箇所)を使用して、差分検出処理の特定の側面を表示します。「Xdiffスキーマ」を参照してください。命令および関連オプションは次のとおりです。

  • operations-in-docorder: オプションはtrueまたはfalseです。

    • true: Xdiffインスタンス・ドキュメントは、文書内と同じ順で最初の文書からノードを参照します。

    • false: Xdiffインスタンス・ドキュメントは、文書内と同じ順で最初の文書からノードを参照しません。

    グローバル最適化の出力はoperations-in-docorder要件に適合しますが、ローカル最適化では適合しません。

  • output-model: オプションは次のとおりです。

    • snapshot: Xmldiffはスナップショット・モデルで出力を生成し、UNIXのdiffモデルに従います。入力文書にどの操作も適用しない場合は、XPathが使用されます。これはデフォルトです。operations-in-docordertrueに設定され、XPathが単純である場合は、XmlPatchはこのモデルの処理のみ実行できます。単純なXPathは子の軸をワイルド・カードなしで要求し、述語の位置を/root[1]/child[2]/text()[2]のように使用する必要があります。

    • current: 各操作は、前の操作までのすべての操作が入力文書に適用されているようにXPathを使用します。XmlDiffが差分を現在のモデルで生成しない場合でも、XmlPatchは手作業で作成したdiff文書を現在のモデルで処理できます。

  • diff-algorithm: このオプションはどの最適化が差分を生成するかを示します。

    • グローバル最適化

    • ローカル最適化

Xdiff操作

XmlDiffは、Xdiffインスタンス・ドキュメントによって明示される操作を使用して差分を検出します。

Xdiffの操作は次のとおりです。

  • 操作対象となるノードの親ノードのXPATHの場所またはノードのXPATHの場所が、parent-xpath属性またはxpath属性によって指定されます。

  • node-type属性により、操作対象となるノードのタイプが指定されます。

  • content子要素により、追加または挿入される新規のサブツリーまたは値が指定されます。

Xdiffインスタンス・ドキュメントに表示されるXdiff操作は、次のとおりです。

  • append-node

    append-node要素により、指定されたタイプのノードが指定された親の最後の子へ追加されるように指定されます。

  • insert-node-before

    insert-node-before要素により、指定されたタイプのノードが指定された参照ノードの前に挿入されるように指定されます。

  • delete-node

    delete-node要素により、削除されるノードにそのすべての子が含まれるように指定されます。これは要素やコメントなどを削除する場合に使用されます。

  • update-node

    update-nodeは、指定されたXPath式を含むノードに関連付けられた値が指定された新規の値に更新されるように指定します。内容は、テキスト・ノードに関する値です。属性の値は、属性ノードに関する値です。

    • テキスト・ノードの更新

      • update node操作の生成はユーザーによってオフにできます。

      • 属性の値は、属性ノードに関する値です。

      • update-nodeは、グローバル最適化によってのみテキスト・ノードに対して生成されます。

    • 要素の更新

      • XmlDiffは、要素ノードに対して更新操作を生成しません。

        Xdiffインスタンス・ドキュメントを手動で変更して、XmlPatchを操作する更新操作を作成できます。または、Xdiffインスタンス・ドキュメントを完全に手書きで入力することも可能です。更新操作に関わる要素のすべての子は削除されます。内容ノードで指定された新規のサブツリーは、すべてインポートされます。

Xdiffインスタンス・ドキュメントの形式

XmlDiffの出力であるXdiffインスタンス・ドキュメントはXML形式で、次の項に示されるXdiffスキーマに準拠しています。

出力文書には、2つの入力文書間の差分を示す一連の操作が含まれます。最初の文書から差分を適用する場合は、2番目の文書を取得します。

Xdiffスキーマ

例21-3に、Xdiffインスタンス・ドキュメント(出力)が従うXdiffスキーマを示します。

例21-3 Xdiffスキーマ: xdiff.xsd

<schema targetNamespace="http://xmlns.oracle.com/xdb/xdiff.xsd"
    xmlns="http://www.w3.org/2001/XMLSchema"
    xmlns:xd="http://xmlns.oracle.com/xdb/xdiff.xsd"
    version="1.0" elementFormDefault="qualified"
    attributeFormDefault="qualified">
    <annotation>
        <documentation xml:lang="ja">
         Defines the structure of XML documents that capture the difference
         between two XML documents. Changes that are not supported by Oracle
         XmlDiff may not be expressible in this schema.

       'oracle-xmldiff' PI in Xdiff document:

       We use 'oracle-xmldiff' PI to describe certain aspects of the diff.
       The PI denotes values for 'operations-in-docorder' and 'output-model'.
       The output of XmlDiff has the PI always. If the user hand-codes a diff doc
       then it must also have the PI in it as the first child of top level xdiff
       element, to be able to call XmlPatch.

       operations-in-docorder:
       Can be either 'true' or 'false'.
       If true, the operations in the diff document refer to the
       elements of the input doc in the same order as document order. Output of
       global algorithm meets this requirement while local does not.

       output-model:
       output models for representing the diff. Can be either 'Snapshot' or
       'Current'.

       Snapshot model:
       Each operation uses Xpaths as if no operations
       have been applied to the input document. (like UNIX diff)
       This is the model used in the output of XmlDiff. XmlPatch works with
       this (and the current model too).
       For XmlPatch to handle this model, "operations-in-docorder" must be
       true and the Xpaths must be simple. (see XmlDif C API documentation).

       Current model:
       Each operation uses Xpaths as if all operations till the previous one
       have been applied to the input document. Works with XmlPatch even if
       the 'operations-in-docorder' criterion is not met and the xpaths are
       not simple.
       <!-- Example:
            <?oracle-xmldiff operations-in-docorder="true" output-model=
            "snapshot" diff-algorithm="global"?>
        -->
      </documentation>
    </annotation>
    <!-- Enumerate the supported node types -->
    <simpleType name="xdiff-nodetype">
        <restriction base="string">
            <enumeration value="element"/>
            <enumeration value="attribute"/>
            <enumeration value="text"/>
            <enumeration value="cdata"/>
            <enumeration value="entity-reference"/>
            <enumeration value="entity"/>
            <enumeration value="processing-instruction"/>
            <enumeration value="notation"/>
            <enumeration value="comment"/>
         </restriction>
    </simpleType>

    <element name="xdiff">
        <complexType>
            <choice minOccurs="0" maxOccurs="unbounded">
                <element name="append-node">
                    <complexType>
                        <sequence>
                            <element name="content" type="anyType"/>
                        </sequence>
                        <attribute name="node-type" type="xd:xdiff-nodetype"/>
                        <attribute name="xpath" type="string"/>
                        <attribute name="parent-xpath" type="string"/>
                        <attribute name="attr-local" type="string"/>
                        <attribute name="attr-nsuri" type="string"/>
                    </complexType>
                </element>

                <element name="insert-node-before">
                    <complexType>
                        <sequence>
                            <element name="content" type="anyType"/>
                        </sequence>
                        <attribute name="xpath" type="string"/>
                        <attribute name="node-type" type="xd:xdiff-nodetype"/>

                    </complexType>
                </element>

                <element name="delete-node">
                    <complexType>
                        <attribute name="node-type" type="xd:xdiff-nodetype"/>
                        <attribute name="xpath" type="string"/>
                        <attribute name="parent-xpath" type="string"/>
                        <attribute name="attr-local" type="string"/>
                        <attribute name="attr-nsuri" type="string"/>
                    </complexType>
                </element>
                 <element name="update-node">
                    <complexType>
                        <sequence>
                            <element name="content" type="anyType"/>
                        </sequence>
                        <attribute name="node-type" type="xd:xdiff-nodetype"/>
                        <attribute name="parent-xpath" type="string"/>
                        <attribute name="xpath" type="string"/>
                        <attribute name="attr-local" type="string"/>
                        <attribute name="attr-nsuri" type="string"/>
                    </complexType>
                </element>
                <element name="rename-node">
                    <complexType>
                        <sequence>
                            <element name="content" type="anyType"/>
                        </sequence>
                        <attribute name="xpath" type="string"/>
                        <attribute name="node-type" type="xd:xdiff-nodetype"/>
                    </complexType>
                </element>
            </choice>
         <attribute name="xdiff-version" type="string"/>
        </complexType>
    </element>
</schema>

アプリケーションでのXMLDiffの使用

アプリケーションでは、XmlDiffは、入力文書のソース・タイプおよび場所を引数とします。ソース・タイプは、URL、ファイル、orastreamおよびstreamコンテキスト・ポインタ、バッファ、buffer_lengthポインタ、またはDOMドキュメント要素(docelement)へのポインタです。

XmlDiffは、Xdiffインスタンス・ドキュメントに関するDOMの文書ノードを戻します。

比較の実行前にDOMとして2つの文書が提供されていない場合、XmlDiffは2つの文書に対してDOMを構築します。


関連項目:

XmlDiffの動作を制御するフラグのC APIの詳細は、『Oracle Database XML C APIリファレンス』を参照してください。

例21-4 XMLDiffアプリケーション

# include <xmldf.h>
...
xmlctx     *xctx;
xmldocnode *doc1, *doc2, *doc3;
uword       hash_level;
oratex     *s, *inp1 = "book1.xml", *inp2="book2.xml";
xmlerr      err;
ub4         flags;

flags = 0; /* defaults : global algorithm */
hash_level = 0; /* no hashing */
/* create XML meta context */
if (!(xctx = XmlCreate(&err, (oratext *) "XmlDiff", NULL)))
{
   printf("Failed to create XML context, error %u\n",
(unsigned) err);
err_exit("Exiting");
}
/* Load the two input files */
if (!(doc1 = XmlLoadDom(xctx, &err, "file", inp1, "discard_whitespace", TRUE,
 NULL)))
{
   printf("Parsing first file failed, error %u\n", (unsigned)err);
   err_exit((oratext *)"Exiting.");
}
if (!(doc2 = XmlLoadDom(xctx, &err, "file", inp2, "discard_whitespace", TRUE,
    NULL)))
{
   printf("Parsing second file failed, error %u\n", (unsigned)err);
   err_exit((oratext *)"Exiting.");
}

/* run XmlDiff on the DOM trees. */

doc3 = XmlDiff(xctx, &err, flags, XMLDF_SRCT_DOM, doc1, NULL, XMLDF_SRCT_DOM,
               doc2, NULL,hash_level, NULL);

if(!doc3)
   printf("XmlDiff Failed, error %u\n", (unsigned)err);
else
{
if(err != XMLERR_OK)
printf("XmlDiff returned error %u\n", (unsigned)err);
/* Now we have the DOM tree in doc3 which represent the Diff */
...
}

XmlFreeDocument(xctx, doc1);
XmlFreeDocument(xctx, doc2);
XmlFreeDocument(xctx, doc3);
XmlDestroy(xctx);

出力のカスタマイズ

カスタマイズ済出力ビルダーは、アプリケーションに適したあらゆる形式の差分を格納します。XmlDiffによって生成され、Xdiffスキーマに準拠したデフォルトのXdiffインスタンス・ドキュメントを使用するかわりに、ユーザー自身のカスタマイズ済出力ビルダーを作成できます。

これを実行するには、XmlDiffが差分を決定した後にコールされるコールバックを提供する必要があります。差分はxmdlfopの配列としてコールバックに渡されます。差分が生成されるたびに、コールバックが呼び出される場合があります。

XPath生成に必要な内部状態の保守が不要なため、カスタマイズ済出力ビルダーを使用する方が、デフォルトを使用するパフォーマンスが向上する場合があります。

デフォルトでは、XmlDiffXdiffスキーマに準拠するXMLでの差分を検出します。必要な場合は、出力ビルダーをプラグインしてください。差分は配列xmldfopとして表示されます。出力ビルダーのコールバック関数を書き込む必要があります。関数署名は次のとおりです。

xmlerr(*xdfobcb)(void *uctx, xmldfop *escript, ub4 escript_siz);

uctxは、ユーザー指定のコンテキストです。

escriptは、サイズescript_sizの配列です。

diff[escript_siz]

mctxは、メモリー・コンテキストです。

プロパティを介してこのメモリー・コンテキストをXmlDiff()に提供します。このメモリー・コンテキストを使用して、escriptに割り当てます。後でescriptを解放する必要があります。

XmlDiff()のコールが戻る前でも発生する差分が検出されたら、出力ビルダーのコールバックを起動します。出力ビルダーのコールバックは、複数回コールされます。

例21-5 カスタマイズ済XMLDiff出力

 /* Sample useage:  */
 ...
 #include <orastruc.h> / * for 'oraprop' * /
 ...
 static oraprop diff_props[] = {
    ORAPROP(XMLDF_PROPN_CUSTOM_OB, XMLDF_PROPI_CUSTOM_OB, POINTER),
    ORAPROP(XMLDF_PROPN_CUSTOM_OBMCX, XMLDF_PROPI_CUSTOM_OBMCX, POINTER),
    ORAPROP(XMLDF_PROPN_CUSTOM_OBUCX, XMLDF_PROPI_CUSTOM_OBUCX, POINTER),
        { NULL }
  };
  ...
  oramemctx *mymemctx;
  ...
  xmlerr myob(void *uctx,  xmldfop *escript, ub4 escript_siz)
  {
     /* process diff which is available in escript * /

     /* free escript - the caller has to do this * /
     OraMemFree(mymemctx, escript);
  }

  main()
  {
   ...
      myctxt  *myctx;

      diff_props[0].value_oraprop.p_oraprop_v = myob;
      diff_props[1].value_oraprop.p_oraprop_v = mymemctx;
      diff_props[2].value_oraprop.p_oraprop_v = myctx;
      XmlDiff(xctx, &err, 0, doc1, NULL, 0, doc2, NULL, 0, diff_props);
 ...
  }

XmlPatchの使用

XmlPatchは、XmlDiffによって生成されたものまたは別のメカニズムにより作成されたもののいずれかのXdiffインスタンス・ドキュメントを受け取り、Xdiffインスタンス・ドキュメント内の指示に従って、指定された他のXML文書を修正します。

XmlPatchコマンドライン・ユーティリティの使用

表21-2に、XmlPatchコマンドライン・オプションを示します。

表21-2 Cコマンドライン・オプションに関するXmlPatch

オプション 説明

-eエンコーディング

デフォルトの入力ファイルのエンコーディングを指定します。XMLファイルでエンコーディングが指定されていない場合、このエンコーディングは入力対象とみなされます。

-Eエンコーディング

出力/データのエンコーディングを指定します。DOMおよびパッチ文書はこのエンコーディングで作成されます。デフォルトはUTF8です。

-i

ファイル名をURLとして解析します。

-h

使用方法のヘルプを表示します。


アプリケーションでのXmlPatchの使用

XmlPatchは、入力文書およびdiff文書のソース・タイプおよび場所を引数とします。ソース・タイプは、URL、ファイル、orastreamおよびstreamコンテキスト・ポインタ、バッファ、buffer_lengthポインタ、またはDOMドキュメント要素(docelement)へのポインタです。


関連項目:

XmlPatchの動作を制御するフラグのC APIの詳細は、『Oracle Database XML C APIリファレンス』を参照してください。

Xdiffスキーマによって設定されたモードはXmlPatchの作業に影響します。

output-modelSnapshotの場合、XmlPatchは、operations-in-docorderTRUEの場合のみ作業します。

output-modelCurrentの場合、operations-in-docorderTRUEに設定する必要はありません。

例21-6 XmlPatchに関するサンプル・アプリケーション

...
#include <xmldf.h>
...
xmlctx     *xctx;
xmldocnode *doc1, *doc2;
oratext    *s;
oratext    *inp1 = "book1.xml"; /* input document */
oratext    *inp2 = "diff.xml", /* diff document */
xmlerr      err;

/* create XML meta context */
if (!(xctx = XmlCreate(&err, (oratext *) "XmlPatch", NULL)))
{
   printf("Failed to create XML context, error %u\n",
(unsigned) err);
err_exit("Exiting");
}
/* Load the two input files */
if (!(doc1 = XmlLoadDom(xctx, &err, "file", inp1, "discard_whitespace", TRUE,
    NULL)))
{
   printf("Parsing first file failed, error %u\n", (unsigned)err);
   err_exit((oratext *)"Exiting.");
}
if (!(doc2 = XmlLoadDom(xctx, &err, "file", inp2, "discard_whitespace", TRUE,
    NULL)))
{
   printf("Parsing second file failed, error %u\n", (unsigned)err);
   err_exit((oratext *)"Exiting.");
}

/* call XmlPatch */
if(!XmlPatch(xctx, &err, 0, XMLDF_SRCT_DOM, doc1, NULL, XMLDF_SRCT_DOM,
           doc2, NULL, NULL));

   printf("XmlPatch Failed, error %u\n", (unsigned)err);
else
{
if(err != XMLERR_OK)
printf("XmlPatch returned error %u\n", (unsigned)err);
/* Now we have the patched document in doc1 */
...
}

XmlFreeDocument(xctx, doc1);
XmlFreeDocument(xctx, doc2);
XmlDestroy(xctx);

XmlHashの使用

Oracle XDKにより、XMLツリーまたはサブツリーに対するハッシュ値を計算するXmlHash,が提供されます。2つのサブツリーのハッシュ値が同一の場合、同じXMLである可能性が非常に高いです。たとえば、XMLツリーがすでにデータベース内にあるかどうかを見る場合、これを使用してすばやく比較できます。

必要な場合、一致がある可能性がある一致に対してXmlDiffを再度実行できます。新規文書のハッシュ値を計算して、データベースに問合せを実行できます。

例21-7に、XmlHashを使用するサンプル・プログラムを示します。

例21-7 XmlHashプログラム

sword main(sword argc, char *argv[])
{
   xmlctx     *xctx;
   xmldfsrct   srct;
   oratext    *data_encoding, *input_encoding, *s, *inp1;
   ub1         flags;
   xmlerr      err;
   ub4         num_args;
   xmlhasht    digest;
   flags = 0; /* defaults */
   srct = XMLDF_SRCT_FILE;
   inp1 = "somexml.xml";
   xctx = XmlCreate(&err, (oratext *) "XmlHash", NULL);

   if (!xctx)
   {
      /* handle error with creating xml context and exit */
      ...
   }

   /* run XmlHash */
   err = XmlHash(xctx, &digest, 0, srct, inp1, NULL, NULL);
   if(err)
      printf("XmlHash returned error:%d \n", err);
   else
      txdfha_pd(digest);

   XmlDestroy(xctx);

   return (sword )err;
}

/* print bytes in xml hash */
static void txdfha_pd(xmlhasht digest)
{
   ub4  i;

   for(i = 0; i < digest.l_xmlhasht; i++)
      printf("%x ", digest.d_xmlhasht[i]);

   printf("\n");
}

XmlDiffおよびXmlPatchのコール

XmlDiffおよびXmlPatchは、コマンドライン・ツールとして、およびC言語からコールされます。SQL関数として使用可能です。


関連項目:

  • 『Oracle Database SQL言語リファレンス』のXMLDiff

  • 『Oracle Database SQL言語リファレンス』のXMLPatch