ヘッダーをスキップ
Oracle® XML DB開発者ガイド
11gリリース2 (11.2)
B70200-03
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

16 C API for XMLの使用

この章では、Oracle XML DBでC API for XMLを使用するためのガイドラインを示します。内容は次のとおりです。

C API for XMLの概要(Oracle XDKおよびOracle XML DB)

C API for XMLは、Oracle XML Developer's Kit (XDK)およびOracle XML DBの両方で使用されます。これはCベースのDOM脚注 1  API for XMLです。データベース内外のXMLデータに対して使用できます。このAPIには、XDKでXMLデータの従来のXML記憶域に、またはOracle XML DBで表のXMLType列として記憶域に使用できるパフォーマンス向上拡張機能もあります。


注意:

Oracle Database 10gリリース1以前のリリースのC DOM関数は、下位互換性のみの目的でサポートされています。

C API for XMLは、Oracle XML DBのXMLType上に実装されます。W3CのDOM勧告において、ドキュメントという用語は広い意味(URI、ファイル・システム、メモリー・バッファ、標準入出力)で使用されます。C API for XMLは、Oracle XML Developer's KitおよびOracle XML DBアプリケーションに必要なすべての機能を含んだ結合プログラム・インタフェースです。これは、XSLTおよびXML Schemaの実装用に提供されています。DOM 2.0勧告に厳密に従っていましたが、オブジェクト指向のDOM 2.0勧告からフラットCの名前空間へのマッピングにはいくつかのネーミング変更が必要でした。たとえば、getName()()メソッドは、getAttrName()メソッドに名前が変更されました

C API for XMLは以前のOracle APIに置き換わります。特に、oraxmlインタフェース(最上位、DOM、SAXおよびXSLT)およびoraxsd.h(Schema)インタフェースは、将来のリリースで非推奨になる予定です。

Oracle XML DBでのOCIおよびC API for XMLの使用

OCIアプリケーションは、通常はサーバーに格納されているXMLデータまたはクライアントで作成されたXMLデータで動作します。この項では、この2つのアクセス方法について詳しく説明します。

データベースに格納されているXMLTypeデータへのアクセス

Oracle XML DBでは、抽象データ型XMLTypeを使用したXMLインスタンスの格納および操作がサポートされています。これらのXMLインスタンスは、C DOM API for XMLとともにOracle Call Interface(OCI)を使用して、クライアント側でアクセスおよび操作できます。C DOM構造xmldocnodeを使用してXMLTypeをバインドおよび定義できます。この構造は、OCI文でXML値のバインド、定義および操作に使用できます。OCI文を使用してサーバーからXMLデータを選択し、C DOM API関数で使用できます。同様に、値はSQL文に直接バインドしなおすことができます。

アプリケーション・プログラムのメイン・フローには、サーバー・ハンドルや文ハンドルなど、通常のOCIハンドルの初期化の後に、XMLコンテキスト・パラメータの初期化が続きます。その後で、データベースでXMLインスタンスを操作するか、またはクライアント側で新規インスタンスを作成できます。初期化されたXMLコンテキストは、すべてのC DOM関数で使用できます。

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

次のように、XmlLoadDom()を使用して、クライアント上で新しいXMLTypeインスタンスを構成できます。

  1. 例16-1に示すように、xmlctxを初期化します。

  2. ユーザー・バッファ、ローカル・ファイルまたはURIからXMLデータを構成します。これらの戻り値は(xmldocnode *)で、他の一般的なC APIで使用できます。

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

XMLCreateDocument()を使用して、空のXMLTypeインスタンスを構成できます。これは、他の型に対してOCIObjectNew()を使用するのに類似しています。

C DOM API関数のXMLコンテキスト・パラメータ

XMLコンテキストは、すべてのC DOM API関数に必須のパラメータです。このOPAQUE型のコンテキストは、データ・エンコーディング、エラー・メッセージの言語などに関係する情報をカプセル化します。コンテキストの内容は、Oracle XML Developer's KitアプリケーションおよびOracle XML DBに対して異なります。Oracle XML DBには、XMLコンテキストを初期化(OCIXmlDbInitXmlCtx())、および終了(OCIXmlDbFreeXmlCtx())するための2つのOCI関数が用意されています。

OCIXmlDbInitXmlCtx()構文

OCIXmlDbInitXmlCtx()関数の構文は次のとおりです。

xmlctx *OCIXmlDbInitXMlCtx (OCIEnv        *envhp,
                            OCISvcHp      *svchp,
                            OCIError      *errhp,
                            ocixmldbparam *params,
                            ub4           num_params);

表16-1で、各パラメータについて説明します。

表16-1 OCIXmlDbInitXMlCtx()パラメータ

パラメータ 説明

envhp (IN)

OCI環境ハンドル。

svchp (IN)

OCIサービス・ハンドル。

errhp (IN)

OCIエラー・ハンドル。

params (IN)

オプション値の配列:

  • OCI継続時間。デフォルト値はOCI_DURATION_SESSIONです。

  • 次のユーザー登録コールバックであるエラー・ハンドラ。

    void (*err_handler) (sword errcode, 
                         (CONST OraText *) errmsg);
    

num_params (IN)

paramsから読み取るパラメータ数。


OCIXmlDbFreeXmlCtx()構文

xctx (IN)パラメータが終了対象のXMLコンテキストである場合のOCIXmlDbFreeXmlCtx() 関数の構文は次のとおりです。

void OCIXmlDbFreeXmlCtx (xmlctx *xctx);

XMLコンテキストの初期化および終了

例16-1に、C DOM APIを使用してXML文書を構成し、Oracle Databaseのmy_table表に保存するCプログラムを示します。OCI関数のOCIXmlDbInitXmlCtx()OCIXmlDbFreeXmlCtx()をコールし、XMLコンテキストを初期化および終了します。これらのOCI関数は、ヘッダー・ファイルocixmldb.hで定義されます。

例16-1のCコードでは、データベース・スキーマcapiusermy_table表を作成するため、次のSQLコードを最初に実行したことを前提としています。

CONNECT CAPIUSER
Enter password: password

Connected.

CREATE TABLE my_table OF XMLType;

例16-1では、OCI関数のOCIXmlDbInitXmlCtx()およびOCIXmlDbFreeXmlCtx()を使用して、XMLコンテキストを初期化および終了する方法を示します。

例16-1 OCIXMLDBINITXMLCTX()およびOCIXMLDBFREEXMLCTX()の使用

#ifndef S_ORACLE
#include <s.h>
#endif
#ifndef ORATYPES_ORACLE
#include <oratypes.h>
#endif
#ifndef XML_ORACLE
#include <xml.h>
#endif
#ifndef OCIXML_ORACLE
#include <ocixml.h>
#endif
#ifndef OCI_ORACLE
#include <oci.h>
#endif
#include <string.h>
 
typedef struct test_ctx {
        OCIEnv *envhp;
        OCIError *errhp;
        OCISvcCtx *svchp;
        OCIStmt *stmthp;
        OCIServer *srvhp;
        OCIDuration dur;
        OCISession *sesshp;
        oratext *username;
        oratext *password;
} test_ctx;
 
/* Helper function 1: execute a sql statement which binds xml data */
STATICF sword exec_bind_xml(OCISvcCtx *svchp,
                    OCIError *errhp,
                    OCIStmt *stmthp,
                    void *xml,
                    OCIType *xmltdo,
                    OraText *sqlstmt);
 
/* Helper function 2: Initialize OCI handles and connect */
STATICF sword init_oci_handles(test_ctx *ctx);
 
/* Helper function 3: Free OCI handles and disconnect */
STATICF sword free_oci_handles(test_ctx *ctx);
 
void main()
{
  test_ctx temp_ctx;
  test_ctx *ctx = &temp_ctx;
  OCIType *xmltdo = (OCIType *) 0;
  xmldocnode *doc = (xmldocnode *)0;
  ocixmldbparam params[1];
  xmlnode *quux, *foo, *foo_data, *top;
  xmlerr err;
  sword status = 0;
  xmlctx *xctx;
 
  oratext ins_stmt[] = "insert into my_table values (:1)"; 
  oratext tlpxml_test_sch[] = "<TOP/>";
  ctx->username = (oratext *)"capiuser";
  ctx->password = (oratext *)"***********"; /* Replace with real password */
 
  /* Initialize envhp, svchp, errhp, dur, stmthp */
  init_oci_handles(ctx);
 
  /* Get an xml context */
  params[0].name_ocixmldbparam = XCTXINIT_OCIDUR;
  params[0].value_ocixmldbparam = &ctx->dur;
  xctx = OCIXmlDbInitXmlCtx(ctx->envhp, ctx->svchp, ctx->errhp, params, 1);
 
  /* Start processing - first, check that this DOM supports XML 1.0 */
  printf("\n\nSupports XML 1.0? : %s\n",
         XmlHasFeature(xctx, (oratext *) "xml", (oratext *) "1.0") ?
         "YES" : "NO");
 
  /* Parse a 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", err);
  }
  else
  {
    /* Get the document element */
    top = (xmlnode *)XmlDomGetDocElem(xctx, doc);
 
    /* Print out the top element */
    printf("\n\nOriginal top element is :\n");   
    XmlSaveDom(xctx, &err, top, "stdio", stdout, NULL);
 
    /* Print out the document-note that the changes are reflected here */
    printf("\n\nOriginal document is :\n");
    XmlSaveDom(xctx, &err, (xmlnode *)doc, "stdio", stdout, NULL);
 
    /* Create some elements and add them to the document */
    quux = (xmlnode *) XmlDomCreateElem(xctx ,doc, (oratext *) "QUUX");
    foo = (xmlnode *) XmlDomCreateElem(xctx, doc, (oratext *) "FOO");
    foo_data = (xmlnode *) XmlDomCreateText(xctx, doc, (oratext *) "data");
    foo_data = XmlDomAppendChild(xctx, (xmlnode *) foo, (xmlnode *) foo_data);
    foo = XmlDomAppendChild(xctx, quux, foo);
    quux = XmlDomAppendChild(xctx, top, quux);
 
    /* Print out the top element */
    printf("\n\nNow the top element is :\n");   
    XmlSaveDom(xctx, &err, top, "stdio", stdout, NULL);
 
    /* Print out the document. Note that the changes are reflected here */
    printf("\n\nNow the document is :\n");
    XmlSaveDom(xctx, &err, (xmlnode *)doc, "stdio", stdout, NULL);
 
    /* Insert the document into my_table */
    status = OCITypeByName(ctx->envhp, ctx->errhp, ctx->svchp, 
                           (const text *) "SYS", (ub4) strlen((char *)"SYS"), 
                           (const text *) "XMLTYPE",
                           (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0,
                           (ub4) 0, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER,
                           (OCIType **) &xmltdo);
    if (status == OCI_SUCCESS)
    {
      exec_bind_xml(ctx->svchp, ctx->errhp, ctx->stmthp, (void *)doc, xmltdo, 
                    ins_stmt);
    }
  }
  /* Free xml ctx */
  OCIXmlDbFreeXmlCtx(xctx);
 
  /* Free envhp, svchp, errhp, stmthp */
  free_oci_handles(ctx);
}

このCプログラムのコンパイルおよび実行からの出力は、次のとおりです。

Supports XML 1.0? : YES
 
Original top element is :
<TOP/>
 
Original document is :
<TOP/>
 
Now the top element is :
<TOP>
  <QUUX>
    <FOO>data</FOO>
  </QUUX>
</TOP>
 
Now the document is :
<TOP>
  <QUUX>
    <FOO>data</FOO>
  </QUUX>
</TOP>

これは、my_tableで構成された文書を問い合せた結果です。

SELECT * FROM my_table;

SYS_NC_ROWINFO$
---------------
<TOP> 
  <QUUX> 
    <FOO>data</FOO> 
  </QUUX> 
</TOP> 
 
1 row selected.

例16-1では、C DOM APIを使用してXML文書を構成し、データベース内に保存します。コードでは、ここには示されていない、ヘルパー関数のexec_bind_xmlinit_oci_handlesおよびfree_oci_handlesが使用されます。ヘルパー関数を含む、この例の詳細は、付録A「Oracleが提供するXML Schemaおよび例」「XMLコンテキスト(OCI)の初期化および終了」を参照してください。

例16-4では、my_table表を問い合せ、例16-1で挿入されたデータを表示します。

バイナリXMLでのC API for XMLの使用

XMLデータはXMLTypeを使用してOracle XML DBに格納でき、この抽象データ型の記憶域モデルの1つはバイナリXMLです。バイナリXMLはXMLデータの簡潔な、XML Schema対応のエンコーディングです。データベース内のXMLTypeの記憶域モデルとして使用することができますが、データベース外にあるXMLデータに対しても使用することができます。「Oracle XML DBでのOCIおよびC API for XMLの使用」で説明したように、XMLデータのクライアント側処理には、Oracle XML DBに格納されているデータ、またはデータベース外にある一時データが関与します。

C APIを使用して、Oracle XML DBに対して、バイナリXML形式でエンコードされたXMLデータを読み書きすることができます。この処理には通常の読書きプロシージャが関与します。

バイナリXMLはXML Schemaに対応しており、必要性とデータに応じて、各種のコード体系を使用することができます。このため、バイナリXMLデータを操作するためには、関連するXML Schemaとエンコーディングについて、データとこのメタデータの両方が必要です。

データベースに格納されているXMLTypeデータの場合、このメタデータもデータベースに格納されます。ただし、データベースとデータのセットアップに応じて、メタデータが適用されるデータと同一のサーバーにメタデータが格納されない場合があります。この場合、データベースに対してバイナリXMLデータを読書きするためには、次の手順を実行する必要があります。

  1. メタデータのコンテキスト・インスタンスを作成します。

  2. このコンテキストを、データベース内のバイナリXMLデータにアクセスするために使用するデータ接続に関連付けます。データ接続は、専用接続(OCISvcCtx)でも接続プール(OCICPool)でもかまいません。

すると、アプリケーションがデータ接続上でバイナリXMLデータをエンコードまたはデコードする必要がある場合、それに必要なメタデータが自動的にフェッチされます。一連の動作の全体は次のとおりです。

  1. 環境(OCIEnv)、接続(OCISvcCtx)、エラー・コンテキスト(OCIError)に応じて、通常のOCIハンドルを作成します。

  2. 必要に応じて1つ以上のメタデータ・コンテキストを作成します。メタデータ・コンテキストはメタデータ・リポジトリと呼ばれることもあり、OCIBinXMLReposCtxはOCIコンテキスト・データ構造です。

    専用接続からはOCIBinXMLCreateReposCtxFromConnを使用して、接続プールからはOCIBinXMLCreateReposCtxFromCPoolを使用してメタデータ・コンテキストを作成します。

  3. メタデータ・コンテキストをバイナリXMLデータ接続に関連付けます。これにはOCIBinXmlSetReposCtxForConnを使用します。

  4. (オプション)XMLデータがデータベース外に由来するものの場合は、setPicklePreferenceを使用して、それ以降データベースに送信されるXMLデータがバイナリXML形式になるよう指定します。これは、DOM文書(xmldomdoc)に適用されます。バイナリXMLを指定しない場合、データはテキスト(CLOB)として格納されます。

  5. OCIライブラリを使用して、データベースに対してXMLデータを読書きします。バイナリXML文書のエンコードやデコードに必要なときは常に、メタデータ・コンテキストを使用して、必要なメタデータが自動的にフェッチされます。

    C DOM API for XMLを使用して、クライアント・レベルのXMLデータに対して操作します。

例16-2に、これを示します。

例16-2 バイナリXMLでのC API for XMLの使用

. . .
/* Private types and constants */
#define SCHEMA        (OraText *)"SYS"
#define TYPE          (OraText *)"XMLTYPE"
#define USER          (OraText *)"oe"
#define USER_LEN      (ub2)(strlen((char *)USER))
#define PWD           (OraText *)"oe"
#define PWD_LEN       (ub2)(strlen((char *)PWD))
#define NUM_PARAMS    1
STATICF void checkerr(OCIError *errhp, sword status);
STATICF sword create_env(OraText *user, ub2 user_len, OraText *pwd, ub2 pwd_len,
                         OCIEnv **envhp, OCISvcCtx **svchp, OCIError **errhp);
STATICF sword run_example(OCIEnv *envhp, OCISvcCtx *svchp, OCIError *errhp,
                          OCIDuration dur);
STATICF void cleanup(OCIEnv *envhp, OCISvcCtx *svchp, OCIError *errhp);
 
int main (int argc, char *argv[])
{
  OCIEnv     *envhp;
  OCISvcCtx  *svchp;
  OCIError   *errhp;
  printf("*** Starting Binary XML Example program\n");
  if (create_env(USER, USER_LEN, PWD, PWD_LEN, &envhp, &svchp, &errhp))
    {
      printf("FAILED: create_env()\n");
      cleanup(envhp, svchp, errhp);
      return OCI_ERROR;
    }
  if (run_example(envhp, svchp, errhp, OCI_DURATION_SESSION))
    {
      printf("FAILED: run_example()\n");
      cleanup(envhp, svchp, errhp);
      return OCI_ERROR;
    }
  cleanup(envhp, svchp, errhp);
  printf ("*** Completed Binary XML example\n");
  return OCI_SUCCESS;
}
 
STATICF sword create_env(OraText *user, ub2 user_len,
                         OraText *pwd,  ub2 pwd_len,
                         OCIEnv **envhp, OCISvcCtx **svchp, OCIError **errhp)
{
  sword       status;
  OCIServer  *srvhp;
  OCISession *usrp;
  OCICPool   *poolhp;
  OraText    *poolname;
  ub4         poolnamelen;
  OraText    *database =(OraText *)"";
  OCIBinXmlReposCtx *rctx;
  /* Create and initialize environment. Allocate error handle. */
  . . .
  if ((status = OCIConnectionPoolCreate((dvoid *)*envhp, (dvoid*)*errhp,
                                        (dvoid *)poolhp, &poolname,
                                        (sb4 *)&poolnamelen, 
                                        (OraText *)0, 
                                        (sb4) 0, 1, 10, 1, 
                                        (OraText *)USER, 
                                        (sb4) USER_LEN, 
                                        (OraText *)PWD, 
                                        (sb4) PWD_LEN,
                                        OCI_DEFAULT)) != OCI_SUCCESS)
    {
      printf ("OCIConnectionPoolCreate - Fail %d\n", status);
      return OCI_ERROR;
    }
  status = OCILogon2((OCIEnv *)*envhp, *errhp, svchp, (OraText *)USER,
                     (ub4)USER_LEN, (const oratext *)PWD, (ub4)PWD_LEN,
                     (const oratext *)poolname, poolnamelen, OCI_CPOOL);
  if (status)
    {
      printf ("OCILogon2 - Fail %d\n", status);
      return OCI_ERROR;
    }
  OCIBinXmlCreateReposCtxFromCPool(*envhp, poolhp, *errhp, &rctx);
  OCIBinXmlSetReposCtxForConn(*svchp, rctx);
  return OCI_SUCCESS;
}
 
STATICF sword run_example(OCIEnv *envhp, OCISvcCtx *svchp, OCIError *errhp,
                          OCIDuration dur)
{
  OCIType   *xmltdo = (OCIType *)0;
  OCIStmt   *stmthp;
  OCIDefine *defnp;
  xmldocnode *xmldoc = (xmldocnode *)0;
  ub4        xmlsize = 0;
  text      *selstmt = (text *)"SELECT doc FROM po_binxmltab";
  sword      status;
  struct xmlctx *xctx = (xmlctx *) 0;
  ocixmldbparam params[NUM_PARAMS];
  xmlerr xerr = (xmlerr) 0;
  /* Obtain type definition for XMLType. Allocate statement handle.
     Prepare SELECT statement. Define variable for XMLType. Execute statement. */
  . . .
  /* Construct xmlctx for using XML C API */
  params[0].name_ocixmldbparam = XCTXINIT_OCIDUR;
  params[0].value_ocixmldbparam = &dur;
  xctx = OCIXmlDbInitXmlCtx(envhp, svchp, errhp, params, NUM_PARAMS);
  /* Print result to local string */
  XmlSaveDom(xctx, &xerr, (xmlnode *)xmldoc, "stdio", stdout, NULL);
  /* Free instances */
  . . .
}

関連項目:


Oracle XML DBでのOracle XML Developer's Kit Pull Parserの使用

Oracle XML DBで、XMLTypeインスタンスによりOracleX XML Developer's Kit Pull Parserを使用できます。このパーサーを使用する場合、解析はオン・デマンドで行われ、アプリケーションが解析処理を起動します。アプリケーションは、Simple API for XML(SAX)解析同様、開始タグ、終了タグ、およびコメントにより一連のイベントを介してXML文書にアクセスします。ただし、解析イベントがコールバックで処理されるSAX解析とは異なり、プル解析では、必要な場合のみ(pull)イベントを要求するメソッドがコールされます。これにより、アプリケーションはXML処理の制御をより容易にできます。特に、PullパーサーではSAXパーサーよりフィルタリングに柔軟性があります。

Oracle XML Developer's Kit Pull Parserを使用して、ストリームに基づくXML Schemaの検証もできます。

例16-3は、XMLTypeインスタンスによるOracle XML DB Pull Parserの使用方法を示しています。Pullパーサーを使用するには、UNIXシステムおよびLinuxシステムではlibxml10.a静的ライブラリ、Microsoft Windowsシステムではoraxml10.dllが必要です。また、xmlev.hヘッダー・ファイルも必要です。


関連項目:

  • Oracle XML Developer's Kit Pull Parserの詳細は、『Oracle XML Developer's Kitプログラマーズ・ガイド』を参照してください。

  • ストリームに基づく検証のPullパーサーの使用方法の詳細は、『Oracle XML Developer's Kitプログラマーズ・ガイド』を参照してください。


例16-3 Oracle XML DB Pull Parserの使用

#define MAXBUFLEN 64*1024
void main()
{
  test_ctx temp_ctx;
  test_ctx *ctx = &temp_ctx;
  OCIType *xmltdo = (OCIType *) 0;
  ocixmldbparam params[1];
  sword status = 0;
  xmlctx *xctx;
  OCIDefine *defnp = (OCIDefine *) 0;
  oratext sel_stmt[] =
    "SELECT XMLSerialize(DOCUMENT x.OBJECT_VALUE AS CLOB) FROM PURCHASEORDER x where rownum = 1";
  OCILobLocator *cob;
  ub4 amtp, nbytes;
  ub1 bufp[MAXBUFLEN];
  ctx->username = (oratext *)"oe";
  ctx->password = (oratext *)"*************";    /* Replace with real password */
 
  /* Initialize envhp, svchp, errhp, dur, stmthp */
  init_oci_handles(ctx);
 
  /* Get an xml context */
  params[0].name_ocixmldbparam = XCTXINIT_OCIDUR;
  params[0].value_ocixmldbparam = &ctx->dur;
  xctx = OCIXmlDbInitXmlCtx(ctx->envhp, ctx->svchp, ctx->errhp, params, 1);
 
  /* Start processing */
  printf("\n\nSupports XML 1.0? : %s\n",
         XmlHasFeature(xctx, (oratext *) "xml", (oratext *) "1.0") ?
         "YES" : "NO");
 
  /* Allocate the lob descriptor */
  status = OCIDescriptorAlloc((dvoid *) ctx->envhp, (dvoid **) &clob,
                       (ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0);
  if (status)
  {
    printf("OCIDescriptorAlloc Failed\n");
    goto error;
  }
  status = OCIStmtPrepare(ctx->stmthp, ctx->errhp,
                 (CONST OraText *)sel_stmt, (ub4) strlen((char *)sel_stmt),
                 (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
  if (status)
  {
    printf("OCIStmtPrepare Failed\n");
    goto error;
  }
  status = OCIDefineByPos(ctx->stmthp, &defnp, ctx->errhp, (ub4) 1,
                 (dvoid *) &clob, (sb4) -1, (ub2 ) SQLT_CLOB,
                 (dvoid *) 0, (ub2 *)0,
                 (ub2 *)0, (ub4) OCI_DEFAULT);
  if (status)
  {
    printf("OCIDefineByPos Failed\n");
    goto error;
  }
  status = OCIStmtExecute(ctx->svchp, ctx->stmthp, ctx->errhp, (ub4) 1,
                          (ub4) 0, (CONST OCISnapshot*) 0, (OCISnapshot*) 0,
                          (ub4) OCI_DEFAULT);
  if (status)
  {
    printf("OCIStmtExecute Failed\n");
    goto error;
  }
  /* read the fetched value into a buffer */
  amtp = nbytes = MAXBUFLEN-1;
  status = OCILobRead(ctx->svchp, ctx->errhp, clob, &amtp,
                (ub4) 1, (dvoid *) bufp, (ub4) nbytes, (dvoid *)0,
                (sb4 (*)(dvoid *, CONST dvoid *, ub4, ub1)) 0,
                (ub2) 0, (ub1) SQLCS_IMPLICIT);
  if (status)
  {
    printf("OCILobRead Failed\n");
    goto error;
  }
  bufp[amtp] = '\0';
  if (amtp > 0)
  {
     printf("\n=> Query result of %s: \n%s\n", sel_stmt, bufp);
     /********** PULL PARSING ******************/
     status = pp_parse(xctx, bufp, amtp);
     if (status)
       printf("Pull Parsing failed\n");
  }
error: 
  /* Free XML Ctx */
  OCIXmlDbFreeXmlCtx(xctx);
 
  /* Free envhp, svchp, errhp, stmthp */
  free_oci_handles(ctx);
}
#define ERRBUFLEN 256
sb4 pp_parse(xctx, buf, amt)
xmlctx  *xctx;
oratext *buf;
ub4     amt;
{
  xmlevctx *evctx;
  xmlerr   xerr = XMLERR_OK;
  oratext  message[ERRBUFLEN];
  oratext  *emsg = message;
  xmlerr   ecode;
  boolean  done, inattr = FALSE;
  xmlevtype event;
 
  /* Create an XML event context - Pull Parser Context */
  evctx = XmlEvCreatePPCtx(xctx, &xerr,
                           "expand_entities", FALSE,
                           "validate", TRUE,
                           "attr_events", TRUE,
                           "raw_buffer_len", 1024,
                           NULL);
 if (!evctx)
  {
    printf("FAILED: XmlEvCreatePPCtx: %d\n", xerr);
    return OCI_ERROR;
  }
  /* Load the document from input buffer */
  xerr = XmlEvLoadPPDoc(xctx, evctx, "buffer", buf, amt, "utf-8");
  if (xerr)
  {
    printf("FAILED: XmlEvLoadPPDoc: %d\n", xerr);
    return OCI_ERROR;
  }
  /* Process the events until END_DOCUMENT event or error */
  done = FALSE;
  while(!done)
  {
    event = XmlEvNext(evctx);
    switch(event)
    {
      case XML_EVENT_START_ELEMENT:
        printf("START ELEMENT: %s\n", XmlEvGetName0(evctx));
        break;
      case XML_EVENT_END_ELEMENT:
        printf("END ELEMENT: %s\n", XmlEvGetName0(evctx));
        break;
      case XML_EVENT_START_DOCUMENT:
        printf("START DOCUMENT\n");
        break;
      case XML_EVENT_END_DOCUMENT:
        printf("END DOCUMENT\n");
        done = TRUE;
        break;
      case XML_EVENT_START_ATTR:
        printf("START ATTRIBUTE: %s\n", XmlEvGetAttrName0(evctx, 0));
        inattr = TRUE;
        break;
      case XML_EVENT_END_ATTR:
        printf("END ATTRIBUTE: %s\n", XmlEvGetAttrName0(evctx, 0));
        inattr = FALSE;
        break;
      case XML_EVENT_CHARACTERS:
        if (inattr)
          printf("ATTR VALUE: %s\n", XmlEvGetText0(evctx));
        else
          printf("TEXT: %s\n", XmlEvGetText0(evctx));
        break;
      case XML_EVENT_ERROR:
      case XML_EVENT_FATAL_ERROR:
        done = TRUE;
        ecode = XmlEvGetError(evctx, &emsg);
        printf("ERROR: %d: %s\n", ecode, emsg);
        break;
    }
  }
  /* Destroy the event context */
  XmlEvDestroyPPCtx(xctx, evctx);
  return OCI_SUCCESS;
}

このCプログラムのコンパイルおよび実行からの出力は、次のとおりです。

=> Query result of XMLSerialize(DOCUMENT x.OBJECT_VALUE AS CLOB) FROM PURCHASEORDER x where rownum = 1: 
<PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:noNamespaceSchemaLocation=
                 "http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd">
  <Reference>AMCEWEN-20021009123336171PDT</Reference>
  <Actions>
    <Action>
      <User>KPARTNER</User>
    </Action>
  </Actions>
  <Reject/>
  <Requestor>Allan D. McEwen</Requestor>
  <User>AMCEWEN</User>
  <CostCenter>S30</CostCenter>
  <ShippingInstructions>
    <name>Allan D. McEwen</name>
    <address>Oracle Plaza
Twin Dolphin Drive
Redwood Shores
CA
94065
USA</address>
    <telephone>650 506 7700</telephone>
  </ShippingInstructions>
  <SpecialInstructions>Ground</SpecialInstructions>
  <LineItems>
    <LineItem ItemNumber="1">
      <Description>Salesman</Description>
      <Part Id="37429158920" UnitPrice="39.95" Quantity="2"/>
    </LineItem>
    . . .
  </LineItems>
</PurchaseOrder>
 
START DOCUMENT
START ELEMENT: PurchaseOrder
START ATTRIBUTE: xmlns:xsi
ATTR VALUE: http://www.w3.org/2001/XMLSchema-instance
END ATTRIBUTE: xmlns:xsi
START ATTRIBUTE: xsi:noNamespaceSchemaLocation
ATTR VALUE: http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd
END ATTRIBUTE: xsi:noNamespaceSchemaLocation
START ELEMENT: Reference
TEXT: AMCEWEN-20021009123336171PDT
END ELEMENT: Reference
START ELEMENT: Actions
START ELEMENT: Action
START ELEMENT: User
TEXT: KPARTNER
END ELEMENT: User
END ELEMENT: Action
END ELEMENT: Actions
START ELEMENT: Reject
END ELEMENT: Reject
START ELEMENT: Requestor
TEXT: Allan D. McEwen
END ELEMENT: Requestor
START ELEMENT: User
TEXT: AMCEWEN
END ELEMENT: User
START ELEMENT: CostCenter
TEXT: S30
END ELEMENT: CostCenter
START ELEMENT: ShippingInstructions
START ELEMENT: name
TEXT: Allan D. McEwen
END ELEMENT: name
START ELEMENT: address
TEXT: Oracle Plaza
Twin Dolphin Drive
Redwood Shores
CA
94065
USA
END ELEMENT: address
START ELEMENT: telephone
TEXT: 650 506 7700
END ELEMENT: telephone
END ELEMENT: ShippingInstructions
START ELEMENT: SpecialInstructions
TEXT: Ground
END ELEMENT: SpecialInstructions
START ELEMENT: LineItems
START ELEMENT: LineItem
START ATTRIBUTE: ItemNumber
ATTR VALUE: 1
END ATTRIBUTE: ItemNumber
START ELEMENT: Description
TEXT: Salesman
END ELEMENT: Description
START ELEMENT: Part
START ATTRIBUTE: Id
ATTR VALUE: 37429158920
END ATTRIBUTE: Id
START ATTRIBUTE: UnitPrice
ATTR VALUE: 39.95
END ATTRIBUTE: UnitPrice
START ATTRIBUTE: Quantity
ATTR VALUE: 2
END ATTRIBUTE: Quantity
END ELEMENT: Part
END ELEMENT: LineItem
. . .
END ELEMENT: LineItems
END ELEMENT: PurchaseOrder
END DOCUMENT

Cでの一般的なXMLType操作

表16-2に、一般的なXML操作のXMLType関数を示します。

表16-2 Cでの一般的なXMLType操作

説明 C API XMLType関数

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

XmlCreateDocument()

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

XmlLoadDom()

XPath式の抽出

XmlXPathEvalexpr()とそのグループ関数

XSLTスタイルシートを使用した変換

XmlXslProcess()とそのグループ関数

XPathの存在チェック

XmlXPathEvalexpr()とそのグループ関数

XML Schemaに基づく文書かどうかのチェック

XmlDomIsSchemaBased()

スキーマ情報の取得

XmlDomGetSchema()

文書名前空間の取得

XmlDomGetNodeURI()

使用スキーマの検証

XmlSchemaValidate()

XMLTypeからのDOMの取得

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

DOMからのXMLTypeの取得

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



関連項目:

『Oracle XML Developer's Kitプログラマーズ・ガイド』のXML Parser for Cに関する項を参照してください。

例16-4では、DOMを使用して、発注された特定部品のインスタンスの数を判別する方法を示します。対象となる部品は、Id 37429158722です。ヘルパー関数exec_bind_xmlfree_oci_handlesおよびinit_oci_handlesの定義は、付録A「Oracleが提供するXML Schemaおよび例」例A-5を参照してください。

例16-4 DOMを使用した発注部品のカウント

#ifndef S_ORACLE
#include <s.h>
#endif
#ifndef ORATYPES_ORACLE
#include <oratypes.h>
#endif
#ifndef XML_ORACLE
#include <xml.h>
#endif
#ifndef OCIXML_ORACLE
#include <ocixml.h>
#endif
#ifndef OCI_ORACLE
#include <oci.h>
#endif
#include <string.h>
 
typedef struct test_ctx {
        OCIEnv *envhp;
        OCIError *errhp;
        OCISvcCtx *svchp;
        OCIStmt *stmthp;
        OCIServer *srvhp;
        OCIDuration dur;
        OCISession *sesshp;
        oratext *username;
        oratext *password;
} test_ctx;
 
/* Helper function 1: execute a sql statement which binds xml data */
STATICF sword exec_bind_xml(OCISvcCtx *svchp,
                    OCIError *errhp,
                    OCIStmt *stmthp,
                    void *xml,
                    OCIType *xmltdo,
                    OraText *sqlstmt);
 
/* Helper function 2: Initialize OCI handles and connect */
STATICF sword init_oci_handles(test_ctx *ctx);
 
/* Helper function 3: Free OCI handles and disconnect */
STATICF sword free_oci_handles(test_ctx *ctx);
 
void main()
{
  test_ctx temp_ctx;
  test_ctx *ctx = &temp_ctx;
  OCIType *xmltdo = (OCIType *) 0;
  xmldocnode *doc = (xmldocnode *)0;
  ocixmldbparam params[1];
  xmlnode *quux, *foo, *foo_data, *top;
  xmlerr err;
  sword status = 0;
  xmlctx *xctx;
  ub4 xmlsize = 0;
  OCIDefine *defnp = (OCIDefine *) 0;
  oratext sel_stmt[] = "SELECT SYS_NC_ROWINFO$ FROM PURCHASEORDER";
  xmlnodelist *litems = (xmlnodelist *)0;
  xmlnode *item = (xmlnode *)item;
  xmlnode *part;
  xmlnamedmap *attrs;
  xmlnode *id;
  xmlnode *qty;
  oratext *idval;
  oratext *qtyval;
  ub4 total_qty;
  int i;
  int numdocs;
  
  ctx->username = (oratext *)"oe";
  ctx->password = (oratext *)"***********";   /* Replace with real password */

  /* Initialize envhp, svchp, errhp, dur, stmthp */
  init_oci_handles(ctx);
 
  /* Get an xml context */
  params[0].name_ocixmldbparam = XCTXINIT_OCIDUR;
  params[0].value_ocixmldbparam = &ctx->dur;
  xctx = OCIXmlDbInitXmlCtx(ctx->envhp, ctx->svchp, ctx->errhp, params, 1);
 
  /* Start processing */
  printf("\n\nSupports XML 1.0? : %s\n",
         XmlHasFeature(xctx, (oratext *) "xml", (oratext *) "1.0") ?
         "YES" : "NO");
 
  /* Get the documents from the database using a select statement */
  status = OCITypeByName(ctx->envhp, ctx->errhp, ctx->svchp, (const text *) "SYS",
                         (ub4) strlen((char *)"SYS"), (const text *) "XMLTYPE",
                         (ub4) strlen((char *)"XMLTYPE"), (CONST text *) 0,
                         (ub4) 0, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER,
                         (OCIType **) &xmltdo);
  status = OCIStmtPrepare(ctx->stmthp, ctx->errhp,
                 (CONST OraText *)sel_stmt, (ub4) strlen((char *)sel_stmt),
                 (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
  status = OCIDefineByPos(ctx->stmthp, &defnp, ctx->errhp, (ub4) 1, (dvoid *) 0,
                 (sb4) 0, SQLT_NTY, (dvoid *) 0, (ub2 *)0,
                 (ub2 *)0, (ub4) OCI_DEFAULT);
  status = OCIDefineObject(defnp, ctx->errhp, (OCIType *) xmltdo,
                  (dvoid **) &doc,
                  &xmlsize, (dvoid **) 0, (ub4 *) 0);
  status = OCIStmtExecute(ctx->svchp, ctx->stmthp, ctx->errhp, (ub4) 0, (ub4) 0,
                 (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT);
 
  /* Initialize variables */
  total_qty = 0;
  numdocs = 0; 
 
  /* Loop through all the documents */
  while ((status = OCIStmtFetch2(ctx->stmthp, ctx->errhp, (ub4) 1, (ub4) OCI_FETCH_NEXT,
                                 (ub4)1, (ub4) OCI_DEFAULT)) == 0)
  {
    numdocs++;
 
    /* Get all the LineItem elements */
    litems = XmlDomGetDocElemsByTag(xctx, doc, (oratext *)"LineItem");
    i = 0;
 
    /* Loop through all LineItems */
    while (item = XmlDomGetNodeListItem(xctx, litems, i))
    {
      /* Get the part */
      part = XmlDomGetLastChild(xctx, item);
     
      /* Get the attributes */
      attrs = XmlDomGetAttrs(xctx, (xmlelemnode *)part);
 
      /* Get the id attribute and its value */
      id = XmlDomGetNamedItem(xctx, attrs, (oratext *)"Id");
      idval = XmlDomGetNodeValue(xctx, id);
 
      /* Keep only parts with id 37429158722 */
      if (idval && (strlen((char *)idval) == 11 )
          && !strncmp((char *)idval, (char *)"37429158722", 11))
      {
        /* Get the quantity attribute and its value.*/
        qty = XmlDomGetNamedItem(xctx, attrs, (oratext *)"Quantity");
        qtyval = XmlDomGetNodeValue(xctx, qty);
 
        /* Add the quantity to total_qty */
        total_qty += atoi((char *)qtyval);
      }
      i++;
    }
    XmlFreeDocument(xctx, doc);
    doc = (xmldocnode *)0;
  }
  printf("Total quantity needed for part 37429158722 = %d\n", total_qty);
  printf("Number of documents in table PURCHASEORDER = %d\n", numdocs);
 
  /* Free Xml Ctx */
  OCIXmlDbFreeXmlCtx(xctx);
 
  /* Free envhp, svchp, errhp, stmthp */
  free_oci_handles(ctx);
}

このCプログラムのコンパイルおよび実行からの出力は、次のとおりです。

Supports XML 1.0? : YES
Total quantity needed for part 37429158722 = 42
Number of documents in table PURCHASEORDER = 132


脚注の凡例

脚注1: この場合のDOMは、World Wide Web Consortium(W3C)のDOM 2.0勧告に準拠していることを示しています。