この章では、Oracle XML DBでC API for XMLを使用するためのガイドラインを示します。
この章の内容は次のとおりです。
C API for XMLは、Oracle XDK(Oracle XML Developer's Kit)およびOracle XML DBの両方で使用されます。これは、CベースのDOM脚注1 API for XMLです。データベース内外のXMLデータに対して使用できます。このAPIには、Oracle XDKで従来のXML記憶域に、またはOracle XML DBで表にXMLType列として格納されるXMLに使用できるパフォーマンス向上拡張機能もあります。
|
注意: Oracle Database 10gリリース1以前のリリースのC DOM関数は、下位互換性のみの目的でサポートされており、拡張はされません。 |
C API for XMLは、Oracle XML DBのXMLType上に実装されます。W3CのDOM勧告において、ドキュメントという用語は広い意味(URI、ファイル・システム、メモリー・バッファ、標準入出力)で使用されます。C API for XMLは、Oracle XDKおよび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)インタフェースは、将来のリリースで非推奨になる予定です。
OCIアプリケーションは、通常はサーバーに格納されているXMLデータまたはクライアントで作成されたXMLデータで動作します。この項では、この2つのアクセス方法について詳しく説明します。
Oracle XML DBでは、抽象データ型XMLTypeを使用したXMLインスタンスの格納および操作がサポートされています。これらのXMLインスタンスは、C DOM API for XMLとともにOracle Call Interface(OCI)を使用して、クライアント側でアクセスおよび操作できます。xmldocnodeを使用してXMLTypeをバインドおよび定義できます。この構造は、OCI文でXML値のバインド、定義および操作に使用できます。OCI文を使用してサーバーからXMLデータを選択し、C DOM API関数で使用できます。同様に、値はSQL文に直接バインドしなおすことができます。
アプリケーション・プログラムのメイン・フローには、サーバー・ハンドルや文ハンドルなど、通常のOCIハンドルの初期化の後に、XMLコンテキスト・パラメータの初期化が続きます。その後で、データベースでXMLインスタンスを操作するか、またはクライアント側で新規インスタンスを作成できます。初期化されたXMLコンテキストは、すべてのC DOM関数で使用できます。
次のように、XmlLoadDom()を使用して、クライアント上で新しいXMLTypeインスタンスを構成できます。
例15-1に示すように、xmlctxを初期化します。
ユーザー・バッファ、ローカル・ファイルまたはURIからXMLデータを構成します。これらの戻り値は(xmldocnode *)で、他の一般的なC APIで使用できます。
必要に応じて、(xmldocnode *)を(void*)にキャストし、バインド値として直接提供できます。
XMLCreateDocument()を使用して、空のXMLTypeインスタンスを構成できます。これは、他の型に対してOCIObjectNew()を使用するのに類似しています。
XMLコンテキストは、すべてのC DOM API関数に必須のパラメータです。このOPAQUE型のコンテキストは、データ・エンコーディング、エラー・メッセージの言語などに関係する情報をカプセル化します。コンテキストの内容は、Oracle XDKアプリケーションおよびOracle XML DBに対して異なります。Oracle XML DBには、XMLコンテキストを初期化(OCIXmlDbInitXmlCtx())、および終了(OCIXmlDbFreeXmlCtx())するための2つのOCI関数が用意されています。
OCIXmlDbInitXmlCtx()関数の構文は次のとおりです。
xmlctx *OCIXmlDbInitXMlCtx (OCIEnv *envhp,
OCISvcHp *svchp,
OCIError *errhp,
ocixmldbparam *params,
ub4 num_params );
表15-1で、各パラメータについて説明します。
例15-1に、C DOM APIを使用してXML文書を構成し、Oracle Databaseのmy_table表に保存するCプログラムを示します。OCI関数のOCIXmlDbInitXmlCtx()とOCIXmlDbFreeXmlCtx()をコールし、XMLコンテキストを初期化および終了します。これらのOCI関数は、ヘッダー・ファイルocixmldb.hで定義されます。
例15-1のCコードでは、データベース・スキーマでmy_table表を作成するため、次のSQLコードを最初に実行したことを前提としています。
CONNECT CAPIUSER
Enter password: password
Connected.
CREATE TABLE my_table OF XMLType;
例15-4では、my_table表を問い合せ、例15-1で挿入されたデータを表示します。
例15-1 OCIXmlDbInitXmlCtx()およびOCIXmlDbFreeXmlCtx()の使用
この例では、OCI関数のOCIXmlDbInitXmlCtx()およびOCIXmlDbFreeXmlCtx()を使用して、XMLコンテキストを初期化および終了する方法を示します。C DOM APIを使用してXML文書を構成し、データベース内に保存します。コードでは、ここには示されていない、ヘルパー関数のexec_bind_xml、init_oci_handlesおよびfree_oci_handlesが使用されます。ヘルパー関数を含む、この例の詳細は、付録A「Oracleが提供するXML Schemaおよび例」の「XMLコンテキスト(OCI)の初期化および終了」を参照してください。
#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.
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データを読書きするためには、次の手順を実行する必要があります。
メタデータのコンテキスト・インスタンスを作成します。
このコンテキストを、データベース内のバイナリXMLデータにアクセスするために使用するデータ接続に関連付けます。データ接続は、専用接続(OCISvcCtx)でも接続プール(OCICPool)でもかまいません。
すると、アプリケーションがデータ接続上でバイナリXMLデータをエンコードまたはデコードする必要がある場合、それに必要なメタデータが自動的にフェッチされます。一連の動作の全体は次のとおりです。
環境(OCIEnv)、接続(OCISvcCtx)、エラー・コンテキスト(OCIError)に応じて、通常のOCIハンドルを作成します。
必要に応じて1つ以上のメタデータ・コンテキストを作成します。メタデータ・コンテキストはメタデータ・リポジトリと呼ばれることもあり、OCIBinXMLReposCtxはOCIコンテキスト・データ構造です。
専用接続からはOCIBinXMLCreateReposCtxFromConnを使用して、接続プールからはOCIBinXMLCreateReposCtxFromCPoolを使用してメタデータ・コンテキストを作成します。
メタデータ・コンテキストをバイナリXMLデータ接続に関連付けます。これにはOCIBinXmlSetReposCtxForConnを使用します。
(オプション)XMLデータがデータベース外に由来するものの場合は、setPicklePreferenceを使用して、それ以降データベースに送信されるXMLデータがバイナリXML形式になるよう指定します。これは、DOM文書(xmldomdoc)に適用されます。バイナリXMLを指定しない場合、データはテキスト(CLOB)として格納されます。
OCIライブラリを使用して、データベースに対してXMLデータを読書きします。バイナリXML文書のエンコードやデコードに必要なときは常に、メタデータ・コンテキストを使用して、必要なメタデータが自動的にフェッチされます。
C DOM API for XMLを使用して、クライアント・レベルのXMLデータに対して操作します。
例15-2に、これを示します。
例15-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で、XMLTypeインスタンスによりOracle XDK Pull Parserを使用できます。このパーサーを使用する場合、解析処理が起動されます。つまり、解析はオン・デマンドで行われます。アプリケーションは、SAX解析同様、開始タグ、終了タグ、およびコメントにより一連のイベントを介してXML文書にアクセスします。ただし、解析イベントがコールバックで処理されるSAX解析とは異なり、プル解析では、必要な場合のみ(pull)イベントを要求するメソッドがコールされます。これにより、アプリケーションはXML処理の制御をより容易にできます。特に、PullパーサーではSAXパーサーよりフィルタリングに柔軟性があります。
Oracle XDK Pull Parserを使用して、ストリームに基づくXML Schemaの検証もできます。
例15-3は、XMLTypeインスタンスによるOracle XML DB Pull Parserの使用方法を示しています。Pullパーサーを使用するには、UnixシステムおよびLinuxシステムではlibxml10.a静的ライブラリ、Microsoft Windowsシステムではoraxml10.dllが必要です。また、xmlev.hヘッダー・ファイルも必要です。
|
関連項目:
|
例15-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 x.getClobVal() FROM PURCHASEORDER x where rownum = 1";
OCILobLocator *clob;
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 SELECT x.getClobVal() 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
表15-2に、一般的なXML操作のXMLType関数を示します。
表15-2 Cでの一般的なXMLType操作
| 説明 | C API XMLType関数 |
|---|---|
|
空の |
|
|
ソース・バッファからの作成 |
|
|
XPath式の抽出 |
|
|
XSLTスタイルシートを使用した変換 |
|
|
XPathの存在チェック |
|
|
XML Schemaに基づく文書かどうかのチェック |
|
|
スキーマ情報の取得 |
|
|
文書名前空間の取得 |
|
|
使用スキーマの検証 |
|
|
XMLTypeからのDOMの取得 |
Cast |
|
DOMからのXMLTypeの取得 |
Cast |
|
関連項目: 『Oracle XML Developer's Kitプログラマーズ・ガイド』のXML Parser for Cに関する項を参照してください。 |
例15-4 DOMを使用した発注部品のカウント
この例では、DOMを使用して、発注された特定部品のインスタンスの数を判別する方法を示します。対象となる部品は、Id 37429158722です。ヘルパー関数exec_bind_xml、free_oci_handlesおよびinit_oci_handlesの定義は、付録A「Oracleが提供するXML Schemaおよび例」の例A-4を参照してください。
#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);
/* We are only interested in 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勧告に準拠していることを示しています。