20 XML Parser for Cの使用

Extensible Markup Language (XML) Parser for Cの使用方法について説明します。

トピック:

20.1 XML Parser for Cの概要

このトピックでは、XML Parser for Cの前提条件および標準について説明します。

トピック:

関連項目:

Document Object Model (DOM)およびSimple API for XML (SAX)を使用したXML解析の概要は、「XML Parsing for Javaの概要」を参照してください。概要の大部分の情報は特定の言語に依存しておらず、Cにも適用されます。

20.1.1 XML Parser for Cの使用の前提条件

Oracle XML Parser for CはXML文書を読み取り、DOMまたはSAXアプリケーション・プログラミング・インタフェース(API)を使用してそのコンテンツと構造へのプログラムでのアクセスを提供します。このパーサーは検証モードまたは非検証モードで使用できます。またPull Parserも使用可能です。

この章では、次のテクノロジを十分に理解していると想定します。

前述のテクノロジの概要説明が必要な場合は、「関連ドキュメント」にあるXMLの資料を参照してください。

20.1.2 XML Parser for Cの標準および仕様

XDK XMLパーサーの標準および仕様について説明します。

  • XML 1.0はW3C勧告です。Oracle XML Developer's Kit (XDK) for C APIはXML 1.0(Second Edition)をフル・サポートしています。

  • DOMレベル1、レベル2およびレベル3の仕様はWorld Wide Web Consortium (W3C)勧告です。XDK for C APIはDOMレベル1および2をフル・サポートしていますが、レベル3はサポートしていません。

  • SAXにはバージョン1.0と2.0があり、バージョン1.0は非推奨です。SAXはW3C仕様ではありません。XDK for C APIはSAX 1.0および2.0の両方をフル・サポートしています。

  • XML名前空間はW3C勧告です。

20.2 XML Parser API for Cの使用

Oracle XML Parser for Cは、XML文書が整形式であるかどうか、およびDTDに対して妥当であるかどうか(オプション)を確認します。アプリケーションでは、DOMまたはSAX APIを使用して、解析されたデータにアクセスできます。

トピック:

20.2.1 Parser API for Cの概要

XML解析APIの中核は、XML、DOM、SAXの各APIです。

表20-1に、これらのAPIのインタフェースを示します。APIドキュメントの詳細は、『Oracle Database XML C APIリファレンス』を参照してください。

表20-1 XML、DOM、SAXの各APIのインタフェース

パッケージ インタフェース 関数名の表記規則

XML

このパッケージは、1つのXMLインタフェースを実装します。インタフェースは次のタスクの関数を定義します。

  • コンテキストの作成と破棄。最上位のXMLコンテキスト(xmlctx)は、連動するXMLコンポーネント間で共通の情報を共有します。

  • XML文書とDTDの作成と解析。

関数名は文字列Xmlで始まります。

APIドキュメントについては、『Oracle Database XML C APIリファレンス』を参照してください。

DOM

このパッケージは、解析済XMLへのプログラム・アクセスを提供します。このパッケージは次のインタフェースを実装します。

  • Attrは、XML属性用のget関数およびset関数を定義します。

  • CharacterDataは、文字データを操作する関数を定義します。

  • Documentは、XMLノードを作成する関数、XML文書に関する情報を取得する関数、文書のDTDを設定する関数を定義します。

  • DocumentTypeは、DTD用のget関数を定義します。

  • Elementは、XML要素用のget関数およびset関数を定義します。

  • Entityは、XMLエンティティ用のget関数を定義します。

  • NameNodeMapは、名前付きノード用のget関数を定義します。

  • Nodeは、XMLノード用のget関数およびset関数を定義します。

  • NodeListは、ノード・リストを解放し、リストからノードを取得する関数を定義します。

  • Notationは、ノードからシステムおよびパブリックIDを取得する関数を定義します。

  • ProcessingInstructionは、命令を処理するget関数およびset関数を定義します。

  • Textは、テキスト・ノードを2つに分割する関数を定義します。

関数名は文字列XmlDomで始まります。

APIドキュメントについては、『Oracle Database XML C APIリファレンス』を参照してください。

SAX

このパッケージは、解析済XMLへのプログラム・アクセスを提供します。このパッケージは、SAXイベントの通知を受け取る関数を定義するSAXインタフェースを実装します。

関数名は文字列XmlSaxで始まります。

APIドキュメントについては、『Oracle Database XML C APIリファレンス』を参照してください。

XML Pull Parser

XMLイベントとはXML文書の表現で、開始タグ、終了タグ、コメントなどのような一連のイベントで文書が表現されるSAXイベントに類似しています。SAXイベントはパーサー(生産者)によって駆動され、XMLイベントはアプリケーション(消費者)によって駆動されるという点で異なります。

関数名は文字列XmlEvで始まります。

APIドキュメントについては、『Oracle Database XML C APIリファレンス』を参照してください。

トピック:

20.2.1.1 XML Parser for Cのデータ型

XML Parser for Cで使用するデータ型について説明します。

XDK for Cのデータ型の完全なリストは、『Oracle Database XML C APIリファレンス』を参照してください。

表20-2 XML Parser for Cで使用するデータ型

データ型 説明

oratext

文字列ポインタ

xmlctx

マスターXMLのコンテキスト

xmlsaxcb

SAXコールバック構造(SAXのみ)

ub4

32ビット以上の符号なし整数

uword

ネイティブな符号なし整数

20.2.1.2 XML Parser for Cのデフォルト

XML Parser for Cのデフォルトについて説明します。

デフォルトは次のとおりです。

  • キャラクタ・セット・エンコーディングは8ビット・エンコーディングのUnicode (UTF-8)です。ドキュメントがすべてASCII形式である場合は、パフォーマンス向上のために、エンコーディングをUS-ASCIIに設定することをお薦めします。

  • パーサーのメッセージは、エラー・ハンドラが提供されていないかぎり、stderrに出力されます。

  • パーサーは入力文書が整形式であるかどうかを確認しますが、妥当であるかどうかは確認しません。プロパティ"validate"を設定することで、入力の妥当性を検証できます。

    注意:

    シングルバイト・キャラクタ・セット(US-ASCII、ISO 8859キャラクタ・セットのいずれかなど)のみを使用している場合、明示的にデフォルトのエンコーディングを設定することをお薦めします。UTF-8などのマルチバイト・キャラクタ・セットを使用した場合よりパフォーマンスが向上します。

  • 空白を処理する際、パーサーはXML 1.0仕様に準拠します。つまり、パーサーは空白をすべてアプリケーションに報告しますが、無視できる空白を示します。ただし、アプリケーションによっては空白文字の破棄プロパティを設定し、要素の終了タグと次の要素の開始タグの間のすべての空白を破棄する場合もあります。

関連項目:

20.2.2 XML Parser for Cのコール順序

XML Parser for Cのコール順序を示します。

図20-1 XML Parser for Cのコール順序

図20-1の説明が続きます
「図20-1 XML Parser for Cのコール順序」の説明

20.2.3 XML Parser for Cの使用: 基本プロセス

XML Parser for Cの使用の基本プロセスについて説明します。

アプリケーションで次の手順を実行します。

  1. XmlCreate()関数を使用して解析プロセスを初期化します。次のサンプル・コード部分は、DOMNamespace.cからの抜粋です。
    xmlctx     *xctx;
    ...
    xctx = XmlCreate(&ecode, (oratext *) "namespace_xctx", NULL);
    
  2. 入力項目を解析します。入力項目はXML文書または文字列バッファのどちらかです。

    DOMで解析する場合、XmlLoadDom()関数を起動します。次のサンプル・コード部分は、DOMNamespace.cからの抜粋です。

    xmldocnode *doc;
    ...
    doc = XmlLoadDom(xctx, &ecode, "file", DOCUMENT,
                     "validate", TRUE, "discard_whitespace", TRUE, NULL);
    

    SAXで解析する場合、XmlLoadSax()関数を起動します。次のサンプル・コード部分は、SAXNamespace.cからの抜粋です。

    xmlerr      ecode;
    ...
    ecode = XmlLoadSax(xctx, &sax_callback, &sc, "file", DOCUMENT,
                       "validate", TRUE, "discard_whitespace", TRUE, NULL);
    

    Pull Parserを使用する場合は、イベント・コンテキストを作成して解析する文書をロードするために次の手順を含めます。

    evctx = XmlEvCreatePPCtx(xctx, &xerr, NULL);
    XmlEvLoadPPDoc(xctx, evctx, "File", input_filenames[i], 0, NULL);
    
  3. DOMインタフェースを使用する場合は、次の手順を含めます。
    • XmlLoadDom()関数を使用してXmlDomGetDocElem()を起動します。この手順により、他のDOM関数が起動されます。通常、これらの関数は、必要に応じてDOM文書を出力するノード関数または出力関数です。次のサンプル・コード部分は、DOMNamespace.cからの抜粋です。

      printElements(xctx, XmlDomGetDocElem(xctx, doc));
      
    • XmlFreeDocument()関数をコールし、解析プロセス中に作成されたすべてのデータ構造を削除します。次のサンプル・コード部分は、DOMNamespace.cからの抜粋です。

      XmlFreeDocument(xctx, doc);
      

    SAXインタフェースを使用する場合は、次の手順を含めます。

    • 次のようなコールバック関数でXmlLoadSax()の起動結果を処理します。

      xmlsaxcb saxcb = {
       UserStartDocument,  /* user's own callback functions */
       UserEndDocument,
       /* ... */
      }; 
      
      if (XmlLoadSax(xctx, &saxcb, NULL, "file", "some_file.xml", NULL) != 0)
        /* an error occured */
      
    • コールバック関数を登録します。不要なSAXコールバック関数は、すべてNULLに設定できます。

    Pull Parserを使用する場合は、次を使用してイベントを繰り返します。

    cur_event = XmlEvNext(evctx);
    

    Get APIを使用してイベントに関する情報を取得します。

  4. XmlFreeDocument()を使用して、解析中に使用されたメモリーと構造を削除します。XMLFreeDocument()またはXMLDestroy()を起動するまで、SAXコールバック関数に渡されたパラメータに割り当てられたメモリー、またはDOM解析ツリーとともに格納されたノードおよびデータに割り当てられたメモリーは解放されません。次のサンプル・コード部分は、DOMNamespace.cからの抜粋です。
    XmlFreeDocument(xctx, doc);
    

    手順2に戻るか、次の手順に進みます。

    Pull ParserはXmlEvCleanPPCtx()を起動して解析中に使用されたメモリーと構造を解放します。アプリケーションでXmlEvLoadPPDoc()を再度起動して別の文書を解析できます。または、Pull Parserコンテキストを再度使用できなくなった後は、XMLEvDestroyPPCtx()を起動できます。

    XmlEvCleanPPCtx(xctx, evctx);
    ...
    XmlEvDestroyPPCtx(xctx, evctx);
    
  5. XmlDestroy()を使用して解析プロセスを終了します。次のサンプル・コード部分は、DOMNamespace.cからの抜粋です。
    (void) XmlDestroy(xctx);
    

    初期化から終了までの起動順序の途中でスレッドが分岐している場合、アプリケーションで不適切な動作および結果が発生する場合があります。

独自のメモリー割当てにはメモリー・コールバック関数XML_ALLOC_FおよびXML_FREE_Fを使用できます。その場合、両方の関数を指定します。

20.2.4 XML Parser for Cのデモ・プログラムの実行

$ORACLE_HOME/xdk/demo/c/(UNIXの場合)および%ORACLE_HOME%\xdk\demo\c(Windowsの場合)ディレクトリには、DOMインタフェースおよびSAXインタフェースによるXML Parser for Cの使用方法を示すXMLアプリケーションがあります。

表20-3に、デモを示します。

makeユーティリティでは、ソース・ファイルfileName.cをコンパイルし、デモ・プログラムfileNameおよび出力ファイルfileName.outを作成できます。予期される出力は、fileName.stdです。

表20-3 Cパーサーのデモ

ディレクトリ 内容 デモ

dom

DOMNamespace.c
DOMSample.c
FullDom.c
FullDom.xml
NSExample.xml
Traverse.c
XPointer.c
class.xml
cleo.xml
pantry.xml

次のデモ・プログラムではDOM APIを使用します。

  • DOMNamespaceプログラムでは、DOM APIに名前空間による拡張を使用します。NSExample.xmlのすべての要素と属性、および名前空間に関するすべての情報が出力されます。

  • DOMSampleプログラムでは、DOM APIを使用して、Cleopatraの概要(XML要素のACTおよびSCENE)を表示します。cleo.xml文書には、『The Tragedy of Antony and Cleopatra』(シェイクスピア戯曲のXMLバージョン)が入っています。

  • FullDomプログラムでは、DOMインタフェース全体の使用例を示します。すべての起動が実行されます。このプログラムでは、エンティティの使用方法を示すFullDom.xmlを入力として受け入れます。

  • Traverseプログラムでは、DOMイテレータ、ツリー・ウォーカーおよび範囲の使用方法を示します。プログラムでは、大学の計算法科目を示すclass.xml文書を入力として受け入れます。

  • XPointerプログラムでは、pantry.xml<pantry>要素の子を検索して、XML Pointer言語の使用方法を示します。

sax

NSExample.xml
SAXNamespace.c
SAXSample.c
cleo.xml

次のデモ・プログラムではSAX APIを使用します。

  • SAXNamespaceプログラムでは、SAX APIに名前空間による拡張を使用します。NSExample.xmlのすべての要素と属性、および名前空間に関するすべての情報が出力されます。

  • SAXSampleプログラムでは、SAX APIを使用して、戯曲Cleopatra内の、指定されたワードを含むすべてのせりふを表示します。ワードを指定しない場合は、ワード"death"が使用されます。cleo.xml文書には、『The Tragedy of Antony and Cleopatra』(シェイクスピア戯曲のXMLバージョン)が入っています。

サンプル・プログラムのコンパイルおよび実行方法を説明するドキュメントは、同じディレクトリ内のREADMEにあります。この場合、基本的な手順は次のようになります。

  1. ディレクトリを$ORACLE_HOME/xdk/demo/c(UNIXの場合)または%ORACLE_HOME%\xdk\demo\c(Windowsの場合)に変更します。

  2. 「UNIXでのXDK for C環境変数の設定」および「WindowsでのXDK for C環境変数の設定」の説明に従って、環境変数が設定されていることを確認します。

  3. システム・プロンプトでmake(UNIXの場合)またはMake.bat(Windowsの場合)を実行します。makeユーティリティでは、ディレクトリを各デモ・サブディレクトリに変更し、makeを実行して次の処理を行います。

    1. ccユーティリティでCソース・ファイルをコンパイルします。たとえば、$ORACLE_HOME/xdk/demo/c/domディレクトリのMakefileには、次の行があります。

      $(CC) -o DOMSample $(INCLUDE) $@.c $(LIB)
      
    2. 各デモ・プログラムを実行し、出力をファイルにリダイレクトします。たとえば、$ORACLE_HOME/xdk/demo/c/domディレクトリのMakefileには、次の行があります。

      ./DOMSample > DOMSample.out
      
  4. プログラムごとに*.stdファイルと*.outファイルを比較します。*.stdファイルには、各プログラムの予期される出力が入っています。たとえば、DOMSample.stdには、DOMSampleの実行で予期される出力が入っています。

20.2.5 XML Parser for Cコマンドライン・ユーティリティの使用

$ORACLE_HOME/bin (UNIXの場合)または%ORACLE_HOME%\bin (Windowsの場合)にあるxmlユーティリティは、XML文書を解析するコマンドライン・インタフェースです。XML文書が整形式であるか、および妥当であるかを確認します。

xmlを使用するには、「UNIXでのXDK for C環境変数の設定」および「WindowsでのXDK for C環境変数の設定」の説明に従って、環境が設定されていることを確認します。

コマンドラインで次の構文を使用して、xmlを起動します。Windowsではxml.exeを使用します。

xml [options] [document URI]
xml -f [options] [document filespec]

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

表20-4 C XML Parserのコマンドライン・オプション

オプション 説明

-B BaseURI

XSLTプロセッサのベースURIを設定します。http://pqr/xsl.txtのベースURIでは、pqr.txthttp://pqr/pqr.txtに解決します。

-c

入力文書が整形式であるかどうかを確認しますが、妥当であるかどうかは確認しません。

-e encoding

デフォルトの入力ファイルのエンコーディング(インコーディング)を指定します。

-E encoding

DOM/SAXのエンコーディング(アウトコーディング)を指定します。

-f file

ファイルをURIではなくfilespecとして解析します。

-G xptr_exprs

ファイルに指定されたXPointerスキームの例を評価します。

-h

使用方法のヘルプおよびコマンドライン・オプションの基本リストを表示します。

-hh

コマンドライン・オプションの詳細なリストを表示します。

-i n

XSLTプロセスを繰り返す回数を指定します。

-l language

エラー報告用の言語を指定します。

-n

DOMを検索し、要素の数を報告します。次に、出力例を示します。

ELEMENT       1
 PCDATA       1
    DOC       1
  TOTAL       3 * 60 = 180

-o XSLoutfile

XSLTプロセッサの出力ファイルを指定します。

-p

解析後の文書/DTDの構造を出力します。たとえば、ルート要素<greeting>hello</greeting>は次のように出力されます。

+---ELEMENT greeting 
    +---PCDATA "hello"

-P

ルート要素から文書を出力します。たとえば、ルート要素<greeting>hello</greeting>は次のように出力されます。

<greeting>hello</greeting>

-PP

ルート・ノード(DOC)からXML宣言を含めて出力します。

-PE encoding

-Pまたは-PPの出力のエンコーディングを指定します。

-PX

出力にXML宣言を含めます。

-s stylesheet

XSLTスタイルシートを指定します。

-v

XDKパーサーのバージョンを表示した後、終了します。

-V var value

CXSLTの最上位の変数をテストします。

-w

空白をすべて保持します。

-W

警告の後で解析を停止します。

-x

SAXインタフェースを実行し、文書を出力します。次に出力例を示します。

StartDocument
XMLDECL version='1.0' encoding=FALSE
<greeting>
    "hello"
</greeting>
EndDocument

トピック:

20.2.5.1 XML Parser for Cコマンドライン・ユーティリティの使用: 例

$ORACLE_HOME/xdk/demo/cにある様々なXMLファイルに対してxml文書をテストできます。

例20-1に、NSExample.xmlの内容を示します。

次の例に示すように、このファイルを解析し、要素数を計算し、DOMツリーを表示できます。

xml -np NSEample.xml > xml.out

例20-2に出力を示します。

例20-1 NSExample.xml

<!DOCTYPE doc [
<!ELEMENT doc (child*)>
<!ATTLIST doc xmlns:nsprefix CDATA #IMPLIED>
<!ATTLIST doc xmlns CDATA #IMPLIED>
<!ATTLIST doc nsprefix:a1 CDATA #IMPLIED>
<!ELEMENT child (#PCDATA)>
]>
<doc nsprefix:a1 = "v1" xmlns="http://www.w3c.org" 
     xmlns:nsprefix="http://www.oracle.com">
<child>
This element inherits the default Namespace of doc.
</child>
</doc>

例20-2 xml.out

   ELEMENT       2
    PCDATA       1
       DOC       1
       DTD       1
  ELEMDECL       2
  ATTRDECL       3
     TOTAL      10 * 112 = 1120
+---ELEMENT doc [nsprefix:a1='v1'*, xmlns='http://www.w3c.org'*, xmlns:nsprefix=
'http://www.oracle.com'*]
    +---ELEMENT child
        +---PCDATA "
This element inherits the default Namespace of doc.
"

20.3 DOM API for Cの使用

このトピックでは、XML文書のエンコーディングの制御、NULL文字終了および長さエンコードの関数の使用、およびエラーの処理について説明します。

トピック:

20.3.1 C APIに対応するXML文書のデータ・エンコーディングの制御

XMLデータは多くのエンコーディングに存在します。XMLエンコーディングは様々な方法で制御できます。

  • 自己記述的でないファイルに対して前提とするデフォルト・エンコーディングの指定

  • DOMまたはSAXの表示用エンコーディングの指定

  • DOMがシリアライズされている場合の再エンコーディング

入力XMLデータは常にエンコードされています。16ビット・エンコーディングのUnicode (UTF-16)など、エンコーディングによっては完全に自己記述的なものがあり、この場合は実際のデータの開始前に特定のバイト・オーダー・マーク(BOM)が必要です。XMLDeclまたは文書のMultipurpose Internet Mail Extensions (MIME)ヘッダーでもエンコーディングを指定できます。アプリケーションで特定のエンコーディングを決定できない場合、デフォルトの入力エンコーディングが適用されます。デフォルトを指定していない場合、ASCIIプラットフォームではUTF-8、EBCDICプラットフォームではUTF-EBCDICが想定されます。

APIでは、入力文書のエンコーディング・データが不正である場合に備えて、対策が取られています。たとえば、encoding=asciiと記述されているXMLDeclが含まれるASCII文書がEBCDICに変換されたとします。新しいEBCDIC文書には、(EBCDIC内に)文書がASCIIであると誤って主張するXMLDeclが含まれます。XMLデータを再エンコードするプログラムの正しい動作は、XMLDeclの変換ではなく、これを再生成することです。XMLDeclは、データそのものではなく、メタデータです。しかし、このルールは無視されることが多く、そのため不正な文書が生成されます。この問題を回避するため、APIには入力エンコーディングの強制的な設定を可能にする追加フラグが提供されており、不正なXMLDeclの問題が解決されています。

入力エンコーディングを決定するための優先順位ルールは、次のとおりです。

  1. ユーザーが指定した強制エンコーディング

    注意:

    競合が存在する場合、強制エンコーディングによって致命的エラーになる可能性があります。たとえば、入力文書がUTF-16であり、UTF-16 BOMで始まっているにもかかわらず、ユーザーが強制UTF-8エンコーディングを指定したとします。この場合、パーサーによって競合に関するエラーが発行されます。

  2. プロトコル仕様(HTTPヘッダーなど)
  3. XMLDecl仕様
  4. ユーザーのデフォルト入力エンコーディング
  5. デフォルト(ASCIIプラットフォームではUTF-8、EBCDICプラットフォームではUTF-E)

アプリケーションでは、入力エンコーディングが決定された後、ドキュメントの解析およびデータの表示が可能になります。表示用エンコーディングを選択できます。元の入力エンコーディングにかかわらず、データにはこの表示用エンコーディングが実行されます。

アプリケーションでシリアライズ形式でDOMを書き戻す時点で、表示用データの再エンコードを選択できます。したがって、シリアライズされた文書を任意のエンコーディングにすることができます。

20.3.2 NULL文字終了および長さエンコードのC API関数の使用

Cにおけるネイティブな文字列表現はNULL文字で終了します。そのため、プライマリDOMインタフェースではNULL文字で終了する文字列が使用され、戻されます。ただし、Oracle XML DB dataデータが表形式で格納されている場合、NULLで終了するのではなく長さがエンコードされます。したがって、XDKでは、頻度の高い場合にパフォーマンスを向上させるために、長さエンコードAPIの追加セットが提供されます。

特に、表20-5のDOM関数には2つのAPIがあります。

表20-5 NULL文字終了および長さエンコードのC API関数

NULL文字終了API 長さエンコードAPI

XmlDomGetNodeName()

XmlDomGetNodeNameLen()

XmlDomGetNodeLocal()

XmlDomGetNodeLocalLen()

XmlDomGetNodeURI()

XmlDomGetNodeURILen()

XmlDomGetNodeValue()

XmlDomGetNodeValueLen()

XmlDomGetAttrName()

XmlDomGetAttrNameLen()

XmlDomGetAttrLocal()

XmlDomGetAttrLocalLen()

XmlDomGetAttrURI()

XmlDomGetAttrURILen()

XmlDomGetAttrValue()

XmlDomGetAttrValueLen()

20.3.3 C APIを使用したエラー処理

C API関数では、通常、数値のエラー・コード(成功の場合は0(ゼロ)、失敗の場合は0(ゼロ)以外)が戻されるか、または変数によりエラー・コードが戻されます。いずれの場合も、APIによってエラー・コードが格納されます。アプリケーションでは、XmlDomGetLastError()関数を起動して、最新のエラーを取得できます。

デフォルトでは、関数出力エラー・メッセージはstderrに出力されます。ただし、初期化の際にエラー・メッセージ・コールバックを登録できます。エラーが発生すると、登録済コールバックがコールされ、エラーは出力されません。

20.4 orastream関数の使用

orastream関数APIは、1つのピースですべて取得するかわりに、大規模なチャンクのデータをノードからストリームするインタフェースです。したがって、64KBより大きいノードにアクセスできます。

orastream APIは、汎用入力または出力ストリームを表します。XDKユーザーはxml.hを介して、このインタフェースを使用します。これは、このインタフェースを実装するorastreamデータ構造および関数のセットにより定義されます。ストリームの作成者は、ストリーム関数アドレスのリストおよびストリーム・コンテキストをOraStreamInitに渡します。この関数は、orastream構造のインスタンスを戻します。

初期化の時点で、複数のストリーム・プロパティを指定します。読取りまたは書込みが指定された場合、ストリームはOraStreamRead()およびOraStreamWrite()を使用してバイト・モードで動作します。"read_char"または"write_char"が指定された場合、ストリームはOraStreamReadChar()およびOraStreamWriteChar()を使用してキャラクタ・モードで動作します。キャラクタ・モードの場合、完全な文字のみを読み込みまたは書き込み、バッファ境界を越えて分割しません。

ストリーム・コンテキストは、orastreamの状態を表すのに使用され、ストリームの存続期間中、存続します。

Javaの入力または出力ストリームと同様、常に、データのソースまたはシンクを指定します。出力ストリームはデータを移入する外部ストリームまたはオブジェクトのアドレスを格納します。同様に、入力ストリームは読み込まれるオブジェクトのアドレスを格納します。

次に、orastream関数の例を示します。

struct orastream;
typedef struct orastream orastream;
typedef ub4 oraerr; /* Error code: zero is success, non-zero is failure */
/* Initialize (Create) & Destroy (Terminate) stream object */
 
orastream  *OraStreamInit(void *sctx, void *sid, oraerr *err, ...);
oraerr     OraStreamTerm(orastream *stream);
 
/* Set or Change SID (streamID) for stream (returns old stream ID through osid)*/
 
oraerr     OraStreamSid(orastream *stream, void *sid, void **osid);
 
/* Is a stream readable or writable? */
 
boolean    OraStreamReadable(orastream *stream);
boolean    OraStreamWritable(orastream *stream);
 
/* Open & Close stream */
 
oraerr     OraStreamOpen(orastream *stream, ubig_ora *length);
oraerr     OraStreamClose(orastream *stream);
 
/* Read | Write byte stream */
 
oraerr     OraStreamRead(orastream *stream, oratext *dest, ubig_ora size,
           oratext **start, ubig_ora *nread, ub1 *eoi);
oraerr     OraStreamWrite(orastream *stream, oratext *src, ubig_ora size,
           ubig_ora *nwrote);
 
/* Read | Write char stream */
 
oraerr     OraStreamReadChar(orastream *stream, oratext *dest, ubig_ora size,
           oratext **start, ubig_ora *nread, ub1 *eoi);
oraerr     OraStreamWriteChar(orastream *stream, oratext *src, ubig_ora size,
           ubig_ora *nwrote);
 
/* Return handles for stream */
 
orastreamhdl *OraStreamHandle(orastream *stream);
 
/* Returns status: if the stream object is currently opened or not */

boolean OraStreamIsOpen(orastream *stream);

ストリーム・エラー・コードは次のとおりです。

#define ORASTREAM_ERR_NULL_POINTER      1      /* NULL pointer given */
#define ORASTREAM_ERR_BAD_STREAM        2      /* invalid stream object */
#define ORASTREAM_ERR_WRONG_DECTION     3      /* tried wrong-direction I/O */
#define ORASTREAM_ERR_UNKNOWN_PROPERTY  4      /* unknown creation prop */
#define ORASTREAM_ERR_NO_DIRECTION      5      /* neither read nor write? */
#define ORASTREAM_ERR_BI_DIRECTION      6      /* both read any write? */
#define ORASTREAM_ERR_NOT_OPEN          7      /* stream not open */
#define ORASTREAM_ERR_WRONG_MODE        8      /* wrote byte/char mode */
/* --- Open errors --- */
#define ORASTREAM_ERR_CANT_OPEN         10     /* can't open stream */
/* --- Close errors --- */
#define ORASTREAM_ERR_CANT_CLOSE        20     /* can't close stream */

関連項目:

orastream APIのパラメータ定義などの参考情報は、『Oracle Database XML C APIリファレンス』を参照してください

例20-3 orastream関数の使用

int test_read()
{
   xmlctx *xctx = NULL;
   oratext *barray, *docName = "NSExample.xml";
   orastream* ostream = (orastream *) 0;
   xmlerr ecode = 0;
   ub4 wcount = 0;
   ubig_ora  destsize, nread;
   oraerr oerr = 0;
   ub1 eoi = 0;
   nread = destsize = 1024;
   if (!(xctx = XmlCreateNew(&ecode, (oratext *)"stream_xctx", NULL, wcount,
                             NULL)))
    {
       printf("Failed to create XML context, error %u\n", (unsigned)ecode);
       return -1;
    }
 
   barray = XmlAlloc(xctx, sizeof(oratext) * destsize);
    
   /* open function should be specified in order to read correctly. */
   if (!(ostream = OraStreamInit(NULL,docName, (oraerr *)&ecode,
                                 "open", fileopen,  
                                 "read", fileread,
                                 NULL)))
   {
      printf("Failed to initialize OrsStream, error %u\n",(unsigned)ecode);
      return -1;
   }  
 
   /* check readable and writable  */
    if (OraStreamReadable(ostream))
       printf("ostream is readable\n");
    else
       printf("ostream is not readable\n");
 
     if (OraStreamWritable(ostream))
       printf("ostream is writable\n");
    else
       printf("ostream is not writable\n");
    
    if (oerr = OraStreamRead(ostream, barray, destsize, &barray, &nread, &eoi))
    {
      printf("Failed to read due to orastream was not open, error %u\n", oerr);
    }
 
   /* open orastream */
   OraStreamOpen(ostream, NULL);
 
   /* read document */
   OraStreamRead(ostream, barray, destsize, &barray, &nread, &eoi);
   
   OraStreamTerm(ostream);
    
   XmlDestroy(xctx);
   return 0;
}
ORASTREAM_OPEN_F(fileopen, sctx, sid, hdl, length)
{
    FILE *fh = NULL;
 
    printf("Opening orastream %s...\n", (oratext *)sid);
 
    if (sid && ((fh= fopen(sid, "r")) != NULL))
    {
        printf("Opening orastream %s...\n", (oratext *)sid);
    }
    else
    {
         printf("Failed to open input file.\n");
         return -1;
     }
 
    /* store file handle generically, NULL means stdout */
    hdl->ptr_orastreamhdl = fh;
 
    return XMLERR_OK;
}
 
ORASTREAM_READ_F(fileread, sctx, sid, hdl,
                         dest, size, start, nread, eoi)
{
    FILE *fh = NULL;
    int i =0;
    printf("Reading orastream %s ...\n", (oratext *)sid);
    
    // read data from file to dest
    if ((fh = (FILE *) hdl->ptr_orastreamhdl) != NULL)
        *nread = fread(dest, 1, size, fh);
    printf("Read %d bytes from orastream...\n", (int) *nread);
 
    *eoi = (*nread < size);
    if (start)
        *start = dest;
 
    printf("printing document ...\n");
    for(i =0; i < *nread; i++)
    printf("%c", (char)dest[i]);
    printf("\nend ...\n");
    return ORAERR_OK;
}

20.5 SAX API for Cの使用

SAXを使用するには、xmlsaxcb構造を関数ポインタで初期化し、XmlLoadSax()に渡します。また、各SAX関数に渡す、ユーザー定義コンテキスト構造へのポインタを含めることができます。

関連項目:

SAXコールバック構造については、『Oracle Database XML C APIリファレンス』を参照してください

20.6 XML Pull Parser for Cの使用

XML Pull Parserは、XMLイベント・インタフェースを実装しています。XML Pull ParserとSAXパーサーは類似していますが、Pull Parserを使用する場合はアプリケーション(コンシューマ)がイベントを駆動する一方、SAXパーサーの場合はパーサー(プロデューサ)がイベントを駆動します。

XML Pull ParserとSAXは両方とも、文書を開始タグ、終了タグおよびコメントのある一連のイベントとして表します。XML Pull Parserは、単純なAPIのセットと基礎となるイベントのセットを公開することによって、アプリケーションに制御を渡します。SAXなどのコールバック内でイベントを処理するのではなく、XmlEvNextのようなメソッドを使用して、アプリケーションは次のイベントをリクエストしたり、または取り出すことができます。そのため、アプリケーションではXML処理においてより手続き的な制御を行います。また、ドキュメント全体を解析するSAXアプリケーションとは異なり、処理を途中で停止することもできます。

トピック:

20.6.1 基本的なXML Pull Parsing機能の使用

XML Pull Parserを使用するために必要な手順について説明します。

  1. XmlCreateを起動してXMLメタコンテキストを初期化します。
  2. イベント・コンテキストを作成して戻すXmlEvCreatePPCtx関数を起動してPull Parserコンテキストを初期化します。

    XmlEvCreatePPCtx関数は、XmlLoadDomおよびXmlLoadSaxなどにサポートされるすべてのプロパティをサポートします。

    XmlEvCreatePPCtx関数およびXmlEvCreatePPCtxVA関数は完全に実装されています。

  3. イベント・コンテキストが、Pull Parserのすべての副問合せの起動に渡されることを確認します。
  4. XmlEvDestoryPPCtx関数を起動してPull Parserコンテキストを終了し、メモリーをクリーンアップします。
  5. XmlDestoryCtx関数を起動してXMLメタコンテキストを破棄します。

トピック:

20.6.1.1 XMLイベント・コンテキスト

XMLイベント・コンテキスト構造を示します。

例20-4 XMLイベント・コンテキスト

typedef  struct {
   void *ctx_xmlevctx;                   /* implementation specific context */
   xmlevdisp *disp_xmlevctx;             /* dispatch table */
   ub4 checkword_xmlevctx;               /* checkword for integrity check */
   ub4 flags_xmlevctx;                   /* mode; default: expand_entity */
   struct xmlevctx *input_xmlevctx;      /* input xmlevctx; chains the XML Event
                                            context */
} xmlevctx;
20.6.1.2 XMLイベント・コンテキストの概要

各XML Pull Parserでは、固有のコンテキストの作成および固有のAPI関数の実装が可能です。

  • ディスパッチ表

    disp_xmlevctxというディスパッチ表には、XmlEvCreatePPCtx関数、XmlEvCreatePPCtxVA関数、XmlEvDestoryPPCtx関数、XmlEvLoadPPDoc関数、およびXmlEvCleanPPCtx関数を除いて、各API関数に1つのポインタが含まれます。

    イベント・コンテキストが作成されると、ポインタdisp_xmlevctxは静的表のアドレスで初期化されます。

  • 実装固有のイベント・コンテキスト

    フィールドctx_xmlevctxは、特定の実装の起動に固有のコンテキストのアドレスで初期化される必要があります。実装固有のイベント・コンテキストは*void型なので、別のアプリケーションとは異なります。

  • 入力イベント・コンテキスト

    各Pull Parserは、xmlevctxという入力イベント・コンテキストを指定できます。このフィールドでは、パーサーにより複数のイベント生産者を連鎖させることが可能です。結果として、コンテキストでディスパッチ関数がNULLと指定されている場合、アプリケーションは入力イベント・コンテキストの連鎖にある次のNULL以外のディスパッチ関数を使用します。基本的なxmlevctxでは、すべてのディスパッチ関数のポインタはNULL以外であることを確認する必要があります。

20.6.2 複数のXML文書の解析

XMLイベント・コンテキストを作成して初期化した後、XmlEvLoadPPDocおよびXmlEvCleanPPCtxを繰り返し起動し、複数の文書を解析できます。

XMLイベント・コンテキスト作成中にアプリケーションによって定義されたプロパティは、XmlLoadPPDoc関数への各起動に対して変更できません。プロパティを変更する場合は、イベント・コンテキストを破棄して再作成します。

XmlEvCleanPPCtxにより現行のパーサーの内部構造を削除した後、イベント・コンテキストを再利用して別の文書を分析できます。

20.6.3 IDコールバック

コールバックを提供して、テキストベースの名前から8バイトの識別子(ID)に変換できます。

コールバック関数署名

typedef  sb8 (*xmlev_id_cb_funcp)( void *ctx , ub1 type, ub1 *token, ub4 tok_len,
              sb8 nmspid, boolean isAttribute);

戻り値

sb8は8バイトのIDです。

引数

  • *ctxはコンテキスト実装です。

  • typeは次の列挙に含まれる型です。

    typedef enum 
    {
      XML_EVENT_ID_URI,
      XML_EVENT_ID_QNAME,
    }xmlevidtype;
    
  • *tokenおよびtok_lenは変換される実際のテキストです。

  • nmspidは名前空間IDです。

  • isAttributeは単一の属性を示すブール値です。

XmlEvGetTagIdおよびXmlEvGetAttrID APIは内部的にこのコールバックを2回起動し、1回は名前空間IDをフェッチし、他の1回はタグの実際のIDまたはQname属性をフェッチします。

XmlEvGetTagUriIDおよびXmlEvGetAttrUriID関数はこのコールバックを1回起動し、対応するUniversal Resource Identifier (URI)のIDを取得します。

コールバックが指定されない場合、これらのAPIが使用されるとエラーXML_ERR_EVENT_NOIDCBKが戻されます。

20.6.4 XML Pull Parserのエラー処理

XML Pull Parserのエラー処理について説明します。

トピック:

20.6.4.1 パーサー・エラー

パーサーで発生するエラーについて説明します。

入力文書が不正な形式であるためエラーがスローされると、XML Pull ParserによりXML_EVENT_FATAL_ERRORというメッセージが戻されます。関数XmlEvGetErrorにより、エラー番号およびメッセージが取得されます。

XmlCreate中にアプリケーションによって指定されたエラー処理は、XmlEvCreatePPCtx操作の間、オーバーライドされます。XmlEvDestroyPPCtx操作で元のコールバックをリストアした後、アプリケーションはXmlErrSetHandler関数を起動する必要があります。

20.6.4.2 プログラミング・エラー

プログラムのエラーを処理するため、XDKには、アプリケーションがイベント・コンテキスト作成時に指定できるコールバックが用意されています。このコールバックは、アプリケーションが無効なAPIに起動する場合に起動されます。

コールバックのシグネチャは次のとおりです。

typedef  void (* xmlev_err_cb_funcp)(xmlctx *xctx, xmlevctx *evctx, 
        xmlevtype cur_event);

無効なAPIの起動の例は次のとおりです。

XmlEvGetNameXML_EVENT_CHARACTERSイベントに対してコールされません。

20.6.5 サンプルPull Parserアプリケーション

サンプルPull Parserアプリケーション、解析する文書、および文書から生成されるイベントのリストについて説明します。

例20-5に、サンプルのアプリケーション・コードを示します。

例20-6に、解析するサンプル文書を示します。

例20-7に、属性イベント・プロパティがFALSEで展開エンティティ・プロパティがTRUEである場合に生成される一連のイベントを示します。

例20-5 サンプルPull Parserアプリケーションの例

# include "xml.h"
# include "xmlev.h"
...
xmlctx *xctx;
xmlevctx *evtcx;
if (!(xctx = XmlCreate(&xerr, (oratext *) "test")))
{
    printf("Failed to create XML context, error %u\n", (unsigned) xerr);
    return -1;
}
...
if(!(evctx = XmlEvCreatePPCtx(xctx, &xerr, NULL)))
{
   printf("Failed to create EVENT context, error %u\n", (unsigned) xerr);
   return -1;
 }
for(i = 0; i < numDocs; i++)
{
  if (xerr = XmlEvLoadPPDoc(xctx, evctx, "file", input_filenames[i], 0, NULL)
     {
       printf("Failed to load the document, error %u\n", (unsigned) xerr);
       return -1;
     }
...
  for(;;)
  {
    xmlevtype cur_event;
    cur_event = XmlEvNext(evctx);
    switch(cur_event)
         {
               case XML_EVENT_FATAL_ERROR:
                     XmlEvGetError(evctx, (oratext **)&errmsg);
                          printf("Error %s\n", errmsg);
               return;
               case XML_EVENT_START_ELEMENT:
                     printf("<%s>", XmlEvGetName0(evctx));
               break;
               case XML_EVENT_END_DOCUMENT:
                     printf("<%s>", XmlEvGetName0(evctx));
               return;
         }
  }
  XmlEvCleanPPCtx(xctx, evctx);
}
XmlEvDestroyPPCtx(xctx, evctx);
XmlDestroy(xctx);

例20-6 解析するサンプル文書

<!DOCTYPE doc [
<!ENTITY ent SYSTEM "file:attendees.txt">
<!ELEMENT doc ANY>
<!ELEMENT meeting (topic, date, publishAttendees)>
<!ELEMENT publishAttendees (#PCDATA)>
<!ELEMENT topic (#PCDATA)>
<!ELEMENT date (#PCDATA)>
]>
<!-- Begin Document -->
<doc>
  <!-- Info about the meeting -->
  <meeting>
    <topic>Group meeting</topic>
    <date>April 25, 2005</date>
    <publishAttendees>&ent;</publishAttendees>
  </meeting>
</doc>
<!-- End Document -->

例20-7 サンプル文書の解析により生成されたイベント

XML_EVENT_START_DOCUMENT
XML_EVENT_START_DTD
XML_EVENT_PE_DECLARATION
XML_EVENT_ELEMENT_DECLARATION
XML_EVENT_ELEMENT_DECLARATION
XML_EVENT_ELEMENT_DECLARATION
XML_EVENT_ELEMENT_DECLARATION
XML_EVENT_ELEMENT_DECLARATION
XML_EVENT_END_DTD 
XML_EVENT_COMMENT
XML_EVENT_START_ELEMENT
XML_EVENT_SPACE
XML_EVENT_COMMENT
XML_EVENT_SPACE
XML_EVENT_START_ELEMENT
XML_EVENT_START_ELEMENT
XML_EVENT_CHARACTERS
XML_EVENT_END_ELEMENT
XML_EVENT_START_ELEMENT
XML_EVENT_CHARACTERS
XML_EVENT_END_ELEMENT
XML_EVENT_START_ELEMENT
XML_EVENT_START_ENTITY
XML_EVENT_CHARACTERS
XML_EVENT_END_ENTITY
XML_EVENT_END_ELEMENT
XML_EVENT_END_ELEMENT
XML_EVENT_SPACE
XML_EVENT_END_ELEMENT
XML_EVENT_COMMENT
XML_EVENT_END_DOCUMENT

20.7 OCIおよびXDK for C APIの使用

この項では、Oracle Call Interface(OCI)からのXDK for C関数へのアクセスについて説明します。

トピック:

20.7.1 XMLType関数の使用および説明

データベースのXMLType列のXMLにC APIを使用できます。Oracle Call Interface (OCI)プログラムでは、OCIハンドルの値を初期化することで、表に格納されたXMLデータにアクセスできます。

これは、次のようなハンドルに適用されます。

  • 環境ハンドル

  • サービス・ハンドル

  • エラー・ハンドル

  • オプションのパラメータ

プログラムでは、これらの入力値をOCIXmlDbInitXmlCtx()関数に渡すことができます。この関数によりXMLコンテキストが戻されます。プログラムによりC APIが起動された後、OCIXmlDbFreeXmlCtx()関数によってコンテキストが解放されます。

表20-6 XMLType関数

関数名 説明

XmlCreateDocument()

空のXMLTypeインスタンスの作成

XmlLoadDom()など

ソース・バッファからの作成

XmlXPathEvalexpr()およびファミリ

XPath式の抽出

XmlXslProcess()およびファミリ

Extensible Stylesheet Language Transformation (XSLT)スタイルシートを使用した変換

XmlXPathEvalexpr()およびファミリ

XPathの有無のチェック

XmlDomIsSchemaBased()

スキーマベースの文書かどうかのチェック

XmlDomGetSchema()

スキーマ情報の取得

XmlDomGetNodeURI()

文書の名前空間の取得

XmlSchemaValidate()

スキーマを使用した検証

(void *)(xmldocnode *)へのキャスト

XMLTypeからのDOMの取得

(xmldocnode *)(void *)へのキャスト

DOMからのXMLTypeの取得

20.7.2 Oracle XML DBに対するXMLコンテキストの初期化

XMLコンテキストは、各C DOM API関数における必須パラメータです。この不透明なコンテキストは、データ・エンコーディング、エラー・メッセージ言語などに関する情報をカプセル化します。XMLコンテキストの内容は、XDKアプリケーションとOracle XML DBアプリケーションでは異なります。

注意:

Oracle XML DBアプリケーションでXDK用のXMLコンテキストを使用したり、XDKアプリケーションでOracle XML DB用のXMLコンテキストを使用しないでください。

Oracle XML DBでは、XMLコンテキストを初期化および解放する2つのOCI関数があり、プロトタイプは次のとおりです。

xmlctx *OCIXmlDbInitXmlCtx (OCIEnv *envhp, OCISvcCtx *svchp, OCIError *errhp,
       ocixmldbparam *params, ub4 num_params);

void OCIXmlDbFreeXmlCtx (xmlctx *xctx);

関連項目:

20.7.3 クライアントでのXMLTypeインスタンスの作成

XmlLoadDom()の起動を使用して、クライアントに新しいXMLTypeインスタンスを構築できます。

次の基本手順に従います。

  1. 「DOM API for Cの使用」の例に示されているように、xmlctxを初期化する必要があります。
  2. 次のソースからXMLデータ自体を構築できます。
    • ユーザー・バッファ

    • ローカル・ファイル

    • URI

    これらの場所からの戻り値は(xmldocnode *)であり、残りの共通C APIで使用できます。

  3. (xmldocnode *)を(void *)にキャストし、必要に応じて直接バインド値として提供できます。

XmlCreateDocument()を起動して、空のXMLTypeインスタンスを構築できます。この関数は、他のタイプに対するOCIObjectNew()に相当します。前の起動で戻された(xmldocnode *)について操作し、バインド値として提供される必要がある場合、最後にこれを(void *)にキャストできます。

20.7.4 データベース・サーバーのXMLデータに対する操作

Oracle Database上のXMLデータは、OCI文を使用して操作できます。xmldocnodeを使用してXMLType値をバインドして定義し、OCI文を使用してデータベースからXMLデータを抽出できます。このデータをC DOM関数で直接使用するか、またはSQL文に値を直接バインドできます。

20.7.5 OCIおよびXDK for C APIの使用: 例

次の例では、DOM APIを使用してXMLスキーマベース文書を構築および保存する方法とデータベース文書を変更する方法を示します。

例20-8に、DOM APIを使用してスキーマベース文書を構築し、データベースに保存する方法を示します。ヘッダー・ファイルxml.hおよびocixmldb.hをインクルードする必要があります。

例20-9に、DOM APIを使用してデータベースから文書を取得し、変更する方法を示します。

例20-8 DOM APIを使用したスキーマベース文書の構築

#include <xml.h>
#include <ocixmldb.h>
static oratext tlpxml_test_sch[] = "<TOP xmlns='example1.xsd'\n\
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' \n\
xsi:schemaLocation='example1.xsd example1.xsd'/>";

void example1()
{
    OCIEnv *envhp;
    OCIError *errhp;
    OCISvcCtx *svchp;
    OCIStmt *stmthp;
    OCIDuration dur;
    OCIType *xmltdo;

    xmldocnode  *doc;
    ocixmldbparam params[1];
    xmlnode *quux, *foo, *foo_data;
    xmlerr       err;

    /* Initialize envhp, svchp, errhp, dur, stmthp */
    /* ........ */

    /* Get an xml context */
    params[0].name_ocixmldbparam = XCTXINIT_OCIDUR;
    params[0].value_ocixmldbparam = &dur;
    xctx = OCIXmlDbInitXmlCtx(envhp, svchp, errhp, params, 1);

    /* Start processing */ 
    printf("Supports XML 1.0: %s\n",
       XmlHasFeature(xctx, (oratext *) "xml", (oratext *) "1.0") ? "YES" : "NO");

    /* Parsing a schema-based document */
    if (!(doc = XmlLoadDom(xctx, &err, "buffer", tlpxml_test_sch,
                          "buffer_length", sizeof(tlpxml_test_sch)-1,
                          "validate", TRUE, NULL)))
    {
       printf("Parse failed, code %d\n");
       return;
    }

    /* Create some elements and add them to the document */
    top = XmlDomGetDocElem(xctx, doc);
    quux = (xmlnode *) XmlDomCreateElem(xctx ,doc, (oratext *) "QUUX");
    foo = (xmlnode *) XmlDomCreateElem(xctx, doc, (oratext *) "FOO");
    foo_data = (xmlnode *) XmlDomCreateText(xctx, doc, (oratext *)"foo's data");
    foo_data = XmlDomAppendChild(xctx, (xmlnode *) foo, (xmlnode *) foo_data);
    foo = XmlDomAppendChild(xctx, quux, foo);
    quux = XmlDomAppendChild(xctx, top, quux);

    XmlSaveDom(xctx, &err, top, "stdio", stdout, NULL);
    XmlSaveDom(xctx, &err, doc, "stdio", stdout, NULL);

    /* Insert the document to my_table */
    ins_stmt = "insert into my_table values (:1)";

    status = OCITypeByName(envhp, errhp, svchp, (const text *) "SYS",
                   (ub4) strlen((char *)"SYS"), (const text *) "XMLTYPE",
                   (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0,
                   (ub4) 0, dur, OCI_TYPEGET_HEADER,
                   (OCIType **) &xmltdo)) ;

    if (status == OCI_SUCCESS)
    {
       exec_bind_xml(svchp, errhp, stmthp, (void *)doc, xmltdo, ins_stmt));
    }

   /* free xml ctx */
   OCIXmlDbFreeXmlCtx(xctx);
}

/*--------------------------------------------------------*/
/* execute a sql statement which binds xml data */
/*--------------------------------------------------------*/
sword exec_bind_xml(svchp, errhp, stmthp, xml, xmltdo, sqlstmt)
OCISvcCtx *svchp;
OCIError *errhp;
OCIStmt *stmthp;
void *xml;
OCIType *xmltdo;
OraText *sqlstmt;
{
   OCIBind *bndhp1 = (OCIBind *) 0;
   OCIBind *bndhp2 = (OCIBind *) 0;
   sword  status = 0;
   OCIInd ind = OCI_IND_NOTNULL;
   OCIInd *indp = &ind;

   if(status = OCIStmtPrepare(stmthp, errhp, (OraText *)sqlstmt,
                    (ub4)strlen((char *)sqlstmt),
                    (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) {
     return OCI_ERROR;
   }

   if(status = OCIBindByPos(stmthp, &bndhp1, errhp, (ub4) 1, (dvoid *) 0,
                   (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0,
                   (ub2 *)0, (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)) {
     return OCI_ERROR;
   }

   if(status = OCIBindObject(bndhp1, errhp, (CONST OCIType *) xmltdo,
               (dvoid **) &xml, (ub4 *) 0, (dvoid **) &indp, (ub4 *) 0)) {
     return OCI_ERROR;
   }

   if(status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT)) {
     return OCI_ERROR;
  }

   return OCI_SUCCESS;
}

例20-9 DOM APIを使用したデータベース文書の変更

#include <xml.h>
#include <ocixmldb.h>
sword example2()
{
    OCIEnv *envhp;
    OCIError *errhp;
    OCISvcCtx *svchp;
    OCIStmt *stmthp;
    OCIDuration dur;
    OCIType *xmltdo;
  
    xmldocnode  *doc;
    xmlnodelist *item_list; ub4 ilist_l;
    ocixmldbparam params[1];
    text *sel_xml_stmt = (text *)"SELECT xml_col FROM my_table";
    ub4    xmlsize = 0;
    sword  status = 0;
    OCIDefine *defnp = (OCIDefine *) 0;

    /* Initialize envhp, svchp, errhp, dur, stmthp */
    /* ... */

    /* Get an xml context */
    params[0].name_ocixmldbparam = XCTXINIT_OCIDUR;
    params[0].value_ocixmldbparam = &dur;
    xctx = OCIXmlDbInitXmlCtx(envhp, svchp, errhp, params, 1);

    /* Start processing */
    if(status = OCITypeByName(envhp, errhp, svchp, (const text *) "SYS",
                   (ub4) strlen((char *)"SYS"), (const text *) "XMLTYPE",
                   (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0,
                   (ub4) 0, dur, OCI_TYPEGET_HEADER,
                   (OCIType **) xmltdo_p)) {
       return OCI_ERROR;
    }

    if(!(*xmltdo_p)) {
       printf("NULL tdo returned\n");
       return OCI_ERROR;
    }

    if(status = OCIStmtPrepare(stmthp, errhp, (OraText *)selstmt,
                    (ub4)strlen((char *)selstmt),
                    (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) {
      return OCI_ERROR;
    }

    if(status = OCIDefineByPos(stmthp, &defnp, errhp, (ub4) 1, (dvoid *) 0,
                   (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0,
                   (ub2 *)0, (ub4) OCI_DEFAULT)) {
       return OCI_ERROR;
    }

    if(status = OCIDefineObject(defnp, errhp, (OCIType *) *xmltdo_p,
                            (dvoid **) &doc,
                            &xmlsize, (dvoid **) 0, (ub4 *) 0)) {
      return OCI_ERROR;
    }

    if(status = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                 (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT)) {
      return OCI_ERROR;
    }

    /* We have the doc. Now we can operate on it */
    printf("Getting Item list...\n");

   item_list = XmlDomGetElemsByTag(xctx,(xmlelemnode *) elem,(oratext *)"Item"); 
    ilist_l   = XmlDomGetNodeListLength(xctx, item_list);
    printf(" Item list length = %d \n", ilist_l);

    for (i = 0; i < ilist_l; i++)
    {
      elem = XmlDomGetNodeListItem(xctx, item_list, i);
      printf("Elem Name:%s\n", XmlDomGetNodeName(xctx, fragelem));
      XmlDomRemoveChild(xctx, fragelem);
    }

    XmlSaveDom(xctx, &err, doc, "stdio", stdout, NULL);

   /* free xml ctx */
   OCIXmlDbFreeXmlCtx(xctx);

   return OCI_SUCCESS;
}