プライマリ・コンテンツに移動
Oracle® XML DB開発者ガイド
12cリリース1 (12.1)
B71282-04
目次へ移動
目次
索引へ移動
索引

前
次

14 C API for XML

C DOM API for XMLTypeでは、CでDOMを使用してXMLTypeインスタンスを操作できます。

14.1 C API for XMLの概要

C API for XMLは、Oracle XML Developer's Kit (XDK)およびOracle XML DBで使用されるDOM APIです。データベース内外のXMLデータに対してこれを使用できます。

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

C API for XMLには、XDKで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)インタフェースは、将来のリリースで非推奨になる予定です。

XMLデータの操作に使用できるCおよびC++のApplication Programming Interface (API)のリファレンス・ドキュメントは、『Oracle Database XML C APIリファレンス』および『Oracle Database XML C++ APIリファレンス』です。

関連項目:

  • PL/SQL API for XMLの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

  • Java APIs for XMLの詳細は、『Oracle Database XML Java API Reference』を参照してください。

14.2 OCIを使用したデータベースに格納されている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関数で使用できます。

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

C DOM APIメソッドのXMLCreateDocument()およびXmlLoadDom()を使用して、クライアント側に新しいXMLTypeインスタンスを構成できます。

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

次のように、XmlLoadDom()を使用して、空でないXMLTypeインスタンスを構成します。

  1. 例14-1に示すように、xmlctxを初期化します。
  2. ユーザー・バッファ、ローカル・ファイルまたはURIからXMLデータを構成します。これらの戻り値は(xmldocnode *)で、他の一般的なC APIで使用できます。
  3. 必要に応じて、(xmldocnode *)を(void*)にキャストし、バインド値として直接提供できます。

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

XMLコンテキストは、すべてのC DOM API関数に必須のパラメータです。このOPAQUE型のコンテキストは、データ・エンコーディング、エラー・メッセージの言語などに関係する情報をカプセル化します。コンテキストの内容は、Oracle XML Developer's KitアプリケーションおよびOracle XML DBに対して異なります。

Oracle XML DBでは、OCI関数OCIXmlDbInitXmlCtx()でXMLコンテキストを初期化し、OCIXmlDbFreeXmlCtx()でXMLコンテキストを終了します。

14.4.1 OCIXmlDbInitXmlCtx()の構文

OCI関数OCIXmlDbInitXmlCtx()は、XMLコンテキストを初期化します。

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

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

表14-1に、パラメータを示します。

表14-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から読み取るパラメータ数。

14.4.2 OCIXmlDbFreeXmlCtx()の構文

OCI関数OCIXmlDbFreeXmlCtx()は、XMLコンテキストを終了します。

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

void OCIXmlDbFreeXmlCtx (xmlctx *xctx);

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

C DOM APIを使用してXML文書を構成し、Oracle Databaseにこれを保存するCプログラムの例を示します。

例14-1に、これを示します。構成された文書は、表my_tableに格納されます。OCI関数のOCIXmlDbInitXmlCtx()およびOCIXmlDbFreeXmlCtx()は、それぞれXMLコンテキストを初期化および終了するために使用されます。これらの関数は、ヘッダー・ファイルocixmldb.hで定義されます。

コードでは、ここには示されていない、ヘルパー関数のexec_bind_xmlinit_oci_handlesおよびfree_oci_handlesが使用されます。ヘルパー関数を含む、この例の完全なリストは、Oracleが提供するXML Schemaおよび例「XMLコンテキスト(OCI)の初期化および終了」を参照してください。

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

CONNECT CAPIUSER
Enter password: password

Connected.

CREATE TABLE my_table OF XMLType;

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

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

#ifndef S_ORACLE
#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 */
static sword exec_bind_xml(OCISvcCtx *svchp,
                           OCIError *errhp,
                           OCIStmt *stmthp,
                           void *xml,
                           OCIType *xmltdo,
                           OraText *sqlstmt);
 
/* Helper function 2: Initialize OCI handles and connect */
static sword init_oci_handles(test_ctx *ctx);
 
/* Helper function 3: Free OCI handles and disconnect */
static 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.

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

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

バイナリXMLはXMLデータの簡潔な、XML Schema対応のエンコーディングです。バイナリXMLはデータベース内のXMLTypeデータの記憶域モデルとして使用できますが、データベース外にあるXMLデータにも使用することができます。

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

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

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

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

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

  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データに対して操作します。

関連項目:

例14-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
static void checkerr(OCIError *errhp, sword status);
static sword create_env(OraText *user, ub2 user_len, OraText *pwd, ub2 pwd_len,
                        OCIEnv **envhp, OCISvcCtx **svchp, OCIError **errhp);
static sword run_example(OCIEnv *envhp, OCISvcCtx *svchp, OCIError *errhp,
                         OCIDuration dur);
static 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;
}
 
static 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;
}
 
static 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 */
  . . .
}

14.7 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の検証もできます。

例14-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プログラマーズ・ガイド』を参照してください。

例14-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

14.8 Cでの一般的なXMLType操作

一般的なXML操作は、C API for XMLによって提供されます。

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

表14-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に関する項を参照してください。

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

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

#ifndef S_ORACLE
#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 */
static sword exec_bind_xml(OCISvcCtx *svchp,
                           OCIError *errhp,
                           OCIStmt *stmthp,
                           void *xml,
                           OCIType *xmltdo,
                           OraText *sqlstmt);
 
/* Helper function 2: Initialize OCI handles and connect */
static sword init_oci_handles(test_ctx *ctx);
 
/* Helper function 3: Free OCI handles and disconnect */
static 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