この章の内容は次のとおりです。
この項の内容は次のとおりです。
Oracle XML Parser for Cは、XML文書を読み取り、DOMまたはSAX APIを使用して、そのコンテンツと構造へのプログラム・アクセスを可能にします。このパーサーは検証モードまたは非検証モードで使用できます。またPull Parserも使用可能です。
この章では、次のテクノロジを十分に理解していると想定します。
Document Object Model(DOM): DOMは、XML文書の構造を示すメモリー内ツリー表現です。
Simple API for XML(SAX): SAXは、イベントベースのXML解析の標準です。
XML Pull Parser for Cの概要: Pull ParserではXMLイベントが使用されます。
Document Type Definition(DTD): XML DTDは、XML文書の有効な構造を定義します。
XMLスキーマ: DTDと同様にXMLスキーマはXML文書の有効な構造を定義します。
XML名前空間: 名前空間は要素名や属性名を識別するためのメカニズムです。
前述のテクノロジの概要説明が必要な場合は、「はじめに」の「関連ドキュメント」にあるXMLの資料を参照してください。
XML 1.0はW3C勧告です。C XDK APIはXML 1.0(Second Edition)をフル・サポートしています。Second Editionの仕様は次のURLにあります。
http://www.w3.org/TR/2000/REC-xml-20001006
DOMレベル1、レベル2およびレベル3の仕様はW3C勧告です。C XDK APIはDOMレベル1および2をフル・サポートしていますが、レベル3はサポートしていません。次のURLに、3つのレベルすべての仕様へのリンクがあります。
http://www.w3.org/DOM/DOMTR
SAXにはバージョン1.0と2.0があり、バージョン1.0は非推奨です。SAXはW3C仕様ではありません。C XDK APIはSAX 1.0および2.0の両方をフル・サポートしています。次のURLに、SAXのドキュメントがあります。
http://www.saxproject.org
XML名前空間はW3C勧告です。仕様は次のURLにあります。
http://www.w3.org/TR/REC-xml-names
Oracle XML Parser for Cは、XML文書が整形式であるかどうか、およびDTDに対して妥当であるかどうか(オプション)を確認します。アプリケーションでは、DOMまたはSAX APIを使用して、解析されたデータにアクセスできます。
XML解析APIの中核は、XML、DOM、SAXの各APIです。表18-1に、これらのAPIのインタフェースを示します。APIに関するドキュメントの詳細は、『Oracle XML APIリファレンス』を参照してください。
表18-1 XML、DOM、SAXの各APIのインタフェース
| パッケージ | インタフェース | 関数名の表記規則 |
|---|---|---|
|
XML |
このパッケージは、1つの
|
関数名は文字列 APIのドキュメントは、『Oracle Database XML C APIリファレンス』を参照してください。 |
|
DOM |
このパッケージは、解析済XMLへのプログラム・アクセスを提供します。このパッケージは次のインタフェースを実装します。
|
関数名は文字列 APIのドキュメントは、『Oracle Database XML C APIリファレンス』を参照してください。 |
|
SAX |
このパッケージは、解析済XMLへのプログラム・アクセスを提供します。このパッケージは |
関数名は文字列 APIのドキュメントは、『Oracle Database XML C APIリファレンス』を参照してください。 |
|
XML Pull Parser |
XMLイベントとはXML文書の表現で、開始タグ、終了タグ、コメントなどのような一連のイベントで文書が表現されるSAXイベントに類似しています。SAXイベントはパーサー(生産者)によって駆動され、XMLイベントはアプリケーション(消費者)によって駆動されるという点で異なります。 |
関数名は文字列 APIのドキュメントは、『Oracle Database XML C APIリファレンス』を参照してください。 |
C XDKのデータ型の完全なリストは、『Oracle XML APIリファレンス』を参照してください。表18-2に、XML Parser for Cで使用するデータ型を示します。
XML Parser for Cのデフォルトは、次のとおりです。
キャラクタ・セットのエンコーディングはUTF-8です。ドキュメントがすべてASCII形式である場合は、パフォーマンス向上のために、エンコーディングをUS-ASCIIに設定することをお薦めします。
パーサーのメッセージは、エラー・ハンドラが提供されていないかぎり、stderrに出力されます。
パーサーは入力文書が整形式であるかどうかを確認しますが、妥当であるかどうかは確認しません。プロパティ"validate"を設定することで、入力の妥当性を検証できます。
|
注意: シングルバイト・キャラクタ・セット(US-ASCII、ISO 8859キャラクタ・セットのいずれか)のみを使用している場合、明示的にデフォルトのエンコーディングを設定することをお薦めします。UTF-8などのマルチバイト・キャラクタ・セットを使用した場合よりパフォーマンスが向上します。 |
パーサーは、空白を処理するときにXML 1.0に準拠します。つまり、パーサーはアプリケーションにすべての空白を報告し、どの空白が無視できる空白であるかを示します。ただし、アプリケーションによっては、プロパティ"discard-whitespace"を設定し、要素の終了タグと次の要素の開始タグの間のすべての空白を削除する方が適切な場合もあります。
|
関連項目:
|
図18-1に、XML Parser for Cのコール順序を示します。
アプリケーションで次の手順を実行します。
XmlCreate()関数を使用して解析プロセスを初期化します。次のサンプル・コード部分は、DOMNamespace.cからの抜粋です。
xmlctx *xctx; ... xctx = XmlCreate(&ecode, (oratext *) "namespace_xctx", NULL);
入力項目を解析します。入力項目は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);
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を使用してイベントに関する情報を取得します。
XmlFreeDocument()を使用して、解析中に使用されたメモリーと構造を削除します。XMLFreeDocument()またはXMLDestroy()をコールするまで、SAXコールバック関数に渡されたパラメータに割り当てられたメモリー、またはDOM解析ツリーとともに格納されたノードおよびデータに割り当てられたメモリーは解放されません。次のサンプル・コード部分は、DOMNamespace.cからの抜粋です。
XmlFreeDocument(xctx, doc);
手順2に戻るか、次の手順に進みます。
Pull ParserはXmlEvCleanPPCtx()をコールして解析中に使用されたメモリーと構造を公開します。アプリケーションは、別の文書を解析するためにXmlEvLoadPPDoc()を再度コールできます。または、Pull Parserコンテキストを再度使用できなくなった後は、XMLEvDestroyPPCtx()をコールできます。
XmlEvCleanPPCtx(xctx, evctx); ... XmlEvDestroyPPCtx(xctx, evctx);
XmlDestroy()を使用して解析プロセスを終了します。次のサンプル・コード部分は、DOMNamespace.cからの抜粋です。
(void) XmlDestroy(xctx);
初期化から終了までのコール順序の途中でスレッドが分岐している場合、アプリケーションで不適切な動作および結果が発生する場合があります。
独自のメモリー割当てにはメモリー・コールバック関数XML_ALLOC_FおよびXML_FREE_Fを使用できます。その場合、両方の関数を指定します。
$ORACLE_HOME/xdk/demo/c/(UNIXの場合)および%ORACLE_HOME%\xdk\demo\c(Windowsの場合)ディレクトリには、DOMインタフェースおよびSAXインタフェースによるXML Parser for Cの使用方法を示すXMLアプリケーションがあります。表18-3に、デモを示します。
makeユーティリティでは、ソース・ファイルfileName.cをコンパイルし、デモ・プログラムfileNameおよび出力ファイルfileName.outを作成できます。予期される出力は、fileName.stdです。
表18-3 Cパーサーのデモ
| ディレクトリ | 内容 | デモ |
|---|---|---|
|
|
DOMNamespace.c DOMSample.c FullDom.c FullDom.xml NSExample.xml Traverse.c XPointer.c class.xml cleo.xml pantry.xml |
次のデモ・プログラムではDOM APIを使用します。
|
|
|
NSExample.xml SAXNamespace.c SAXSample.c cleo.xml |
次のデモ・プログラムではSAX APIを使用します。
|
サンプル・プログラムのコンパイルおよび実行方法を説明するドキュメントは、同じディレクトリ内のREADMEにあります。基本手順は次のとおりです。
ディレクトリを$ORACLE_HOME/xdk/demo/c(UNIXの場合)または%ORACLE_HOME%\xdk\demo\c(Windowsの場合)に変更します。
「UNIXでのC XDK環境変数の設定」および「WindowsでのC XDK環境変数の設定」の説明に従って、環境変数が設定されていることを確認します。
システム・プロンプトでmake(UNIXの場合)またはMake.bat(Windowsの場合)を実行します。makeユーティリティでは、ディレクトリをデモ・サブディレクトリに変更し、makeを実行して次の処理を行います。
ccユーティリティでCソース・ファイルをコンパイルします。たとえば、$ORACLE_HOME/xdk/demo/c/domディレクトリのMakefileには、次の行があります。
$(CC) -o DOMSample $(INCLUDE) $@.c $(LIB)
各デモ・プログラムを実行し、出力をファイルにリダイレクトします。たとえば、$ORACLE_HOME/xdk/demo/c/domディレクトリのMakefileには、次の行があります。
./DOMSample > DOMSample.out
プログラムごとに*.stdファイルと*.outファイルを比較します。*.stdファイルには、各プログラムの予期される出力が入っています。たとえば、DOMSample.stdには、DOMSampleの実行で予期される出力が入っています。
$ORACLE_HOME/bin(UNIXの場合)または%ORACLE_HOME%\bin(Windowsの場合)にあるxmlユーティリティは、XML文書を解析するコマンドライン・インタフェースです。XML文書が整形式であるか、および妥当であるかを確認します。
xmlを使用するには、「UNIXでのC XDK環境変数の設定」および「WindowsでのC XDK環境変数の設定」の説明に従って、環境が設定されていることを確認します。
コマンドラインで次の構文を使用して、xmlを起動します。Windowsではxml.exeを使用します。
xml [options] [document URI] xml -f [options] [document filespec]
表18-4に、コマンドライン・オプションを示します。
表18-4 C XML Parserのコマンドライン・オプション
| オプション | 説明 |
|---|---|
|
|
XSLTプロセッサのベースURIを設定します。 |
|
|
入力文書が整形式であるかどうかを確認しますが、妥当であるかどうかは確認しません。 |
|
|
デフォルトの入力ファイルのエンコーディング(インコーディング)を指定します。 |
|
|
DOM/SAXのエンコーディング(アウトコーディング)を指定します。 |
|
|
ファイルをURIではなくfilespecとして解析します。 |
|
|
ファイルに指定された |
|
|
使用方法のヘルプおよびコマンドライン・オプションの基本リストを表示します。 |
|
|
コマンドライン・オプションの詳細なリストを表示します。 |
|
|
|
|
|
エラー報告用の言語を指定します。 |
|
|
DOMを検索し、要素の数を報告します。次に、出力例を示します。
ELEMENT 1
PCDATA 1
DOC 1
TOTAL 3 * 60 = 180
|
|
|
|
|
|
解析後の文書とDTDの構造を出力します。たとえば、ルート要素 +---ELEMENT greeting +---PCDATA "hello" |
|
|
ルート要素から文書を出力します。たとえば、ルート要素 <greeting>hello</greeting> |
|
|
ルート・ノード(DOC)からXML宣言を含めて出力します。 |
|
|
|
|
|
出力にXML宣言を含めます。 |
|
|
|
|
|
XDKパーサーのバージョンを表示した後、終了します。 |
|
|
|
|
|
すべての空白を保持します。 |
|
|
警告の後で解析を停止します。 |
|
|
SAXインタフェースを実行し、文書を出力します。次に出力例を示します。 StartDocumentXMLDECL version='1.0' encoding=FALSE<greeting> "hello"</greeting>EndDocument |
$ORACLE_HOME/xdk/demo/cにある様々なXMLファイルに対してxmlをテストできます。例18-1に、NSExample.xmlの内容を示します。
例18-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>
次の例に示すように、このファイルを解析し、要素数を計算し、DOMツリーを表示できます。
xml -np NSEample.xml > xml.out
次の例に、出力を示します。
この項の内容は次のとおりです。
XMLデータは多くのエンコーディングに存在します。XMLエンコーディングは次のように制御できます。
自己記述的でないファイルに対して前提とするデフォルト・エンコーディングの指定
DOMまたはSAXの表示用エンコーディングの指定
DOMがシリアライズされている場合の再エンコーディング
入力XMLデータは常にエンコードされています。UTF-16など、エンコーディングによっては完全に自己記述的なものがあり、この場合は実際のデータの開始前に特定のBOMが必要です。文書のXMLDeclまたはMIMEヘッダーでもエンコーディングを指定できます。アプリケーションで特定のエンコーディングを決定できない場合、デフォルトの入力エンコーディングが適用されます。デフォルトを指定していない場合、ASCIIプラットフォームではUTF-8、EBCDICプラットフォームではUTF-Eが想定されます。
APIでは、入力文書のエンコーディング・データが不正である場合に備えて、対策が取られています。たとえば、encoding=asciiと記述されているXMLDeclが含まれるASCII文書がEBCDICに変換されたとします。新しいEBCDIC文書には、(EBCDIC内に)文書がASCIIであると誤って主張するXMLDeclが含まれます。XMLデータを再エンコードするプログラムの正しい動作は、XMLDeclの変換ではなく、これを再生成することです。XMLDeclは、データそのものではなく、メタデータです。しかし、このルールは無視されることが多く、そのため不正な文書が生成されます。この問題を回避するため、APIには入力エンコーディングの強制的な設定を可能にする追加フラグが提供されており、不正なXMLDeclの問題が解決されています。
入力エンコーディングを決定するための優先順位ルールは、次のとおりです。
ユーザーが指定した強制エンコーディング
|
注意: 競合が存在する場合、強制エンコーディングによって致命的エラーになる可能性があります。たとえば、入力文書がUTF-16であり、UTF-16 BOMで始まっているにもかかわらず、ユーザーが強制UTF-8エンコーディングを指定したとします。この場合、パーサーによって競合に関するエラーが発行されます。 |
プロトコル仕様(HTTPヘッダーなど)
XMLDecl仕様
ユーザーのデフォルト入力エンコーディング
デフォルト(ASCIIプラットフォームではUTF-8、EBCDICプラットフォームではUTF-E)
アプリケーションでは、入力エンコーディングが決定された後、文書の解析およびデータの表示が可能になります。表示用エンコーディングを選択できます。元の入力エンコーディングにかかわらず、データにはこの表示用エンコーディングが実行されます。
アプリケーションでシリアライズ形式でDOMを書き戻す時点で、表示用データの再エンコードを選択できます。したがって、シリアライズされた文書を任意のエンコーディングにすることができます。
Cにおけるネイティブな文字列表現はヌル文字で終了します。そのため、プライマリDOMインタフェースではヌル文字で終了する文字列が使用され、戻されます。ただし、Oracle XML DBデータが表形式で格納されている場合、ヌル文字で終了するのではなく、長さがエンコードされます。したがって、XDKでは、頻度の高い場合にパフォーマンスを向上させるために、長さエンコードAPIの追加セットが提供されます。特に、表18-5のDOM関数には2つのAPIがあります。
表18-5 ヌル文字終了および長さエンコードのC API関数
| ヌル文字終了API | 長さエンコードAPI |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
C API関数では、通常、数値のエラー・コード(成功の場合は0(ゼロ)、失敗の場合は0(ゼロ)以外)が戻されるか、または変数によりエラー・コードが戻されます。いずれの場合も、APIによってエラー・コードが格納されます。アプリケーションでは、XmlDomGetLastError()関数をコールして、最新のエラーを取得できます。
デフォルトでは、関数出力エラー・メッセージはstderrに出力されます。ただし、初期化の際にエラー・メッセージ・コールバックを登録できます。エラーが発生すると、登録済コールバックがコールされ、エラーは出力されません。
SAXを使用するには、xmlsaxcb構造を関数ポインタで初期化し、XmlLoadSax()に渡します。また、ユーザー定義コンテキスト構造へのポインタを含むことができます。このポインタは各SAX関数に渡されます。
|
関連項目: SAXコールバック構造については、『Oracle Database XML C APIリファレンス』を参照してください。 |
XML Pull Parserは、XMLイベント・インタフェースを実装しています。
XML Pull ParserとSAXパーサーは類似していますが、Pull Parserを使用する場合はアプリケーション(消費者)がイベントを駆動する一方、SAXパーサーの場合はパーサー(生産者)がイベントを駆動します。XML Pull ParserとSAXのいずれも、開始タグ、終了タグおよびコメントを使用して文書を一連のイベントとして表示します。XML Pull Parserは単純な一連のAPIおよび基礎となる一連のイベントを表示することでアプリケーションに制御を渡します。SAXなどのコールバック内でイベントを処理するのではなく、XmlEvNextのようなメソッドを使用して、アプリケーションは次のイベントをリクエストしたり、または取り出すことができます。そのため、アプリケーションではXML処理においてより手続き的な制御を行います。また、文書全体を解析するSAXアプリケーションとは異なり、処理を途中で停止することもできます。
この項の内容は次のとおりです。
XML Pull Parserを使用するには、示される順序に従って、次の操作を行いません。
XmlCreateをコールしてXMLメタコンテキストを初期化します。
イベント・コンテキストを作成して戻すXmlEvCreatePPCtx関数をコールしてPull Parserコンテキストを初期化します。
XmlEvCreatePPCtx関数は、XmlLoadDomおよびXmlLoadSaxなどにサポートされるすべてのプロパティをサポートします。
XmlEvCreatePPCtx関数およびXmlEvCreatePPCtxVA関数は完全に実装されています。
イベント・コンテキストが、Pull Parserへのすべての副問合せコールに渡されることを確認します。
XmlEvDestoryPPCtx関数をコールしてPull Parserコンテキストを終了し、メモリーを削除します。
XmlDestoryCtx関数をコールしてXMLメタコンテキストを削除します。
例18-3に、イベント・コンテキストの構造を示します。
例18-3 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;
各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以外であることを確認する必要があります。
XMLイベント・コンテキストを作成して初期化した後、XmlEvLoadPPDocおよびXmlEvCleanPPCtxに対して繰り返されたコールを使用して複数の文書を解析できます。これらの関数は完全に実装されています。
XMLイベント・コンテキスト作成中にアプリケーションによって定義されたプロパティは、XmlLoadPPDoc関数への各コールに対して変更できないことに注意してください。プロパティを変更する場合は、イベント・コンテキストを削除して再作成します。
XmlEvCleanPPCtxにより現行のパーサーの内部構造を削除した後、イベント・コンテキストを再利用して別の文書を分析できます。
コールバックを提供して、テキストベースの名前から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は内部的にこのコールバックを2回コールし、1回は名前空間IDをフェッチし、他の1回はタグの実際のIDまたはQname属性をフェッチします。
XmlEvGetTagUriID関数およびXmlEvGetAttrUriID関数によりこのコールバックを1回起動して対応するURIのIDを取得します。
コールバックが指定されない場合、これらのAPIが使用されるとエラーXML_ERR_EVENT_NOIDCBKが戻されます。
次の項では、XML Pull Parserのエラー処理について説明します。
入力文書が不正な形式であるためエラーがスローされると、XML Pull ParserによりXML_EVENT_FATAL_ERRORというメッセージが戻されます。XmlEvGetError関数によりエラー番号およびメッセージが取得されます。
XmlCreate中にアプリケーションによって指定されたエラー処理は、XmlEvCreatePPCtx操作の間、オーバーライドされることに注意してください。XmlEvDestroyPPCtx操作で元のコールバックをリストアした後、アプリケーションはXmlErrSetHandler関数をコールする必要があります。
プログラムのエラーを処理するため、XDKには、アプリケーションがイベント・コンテキスト作成時に指定できるコールバックが用意されています。このコールバックは、アプリケーションが無効なAPIにコールを作成する場合に起動されます。コールバック署名は次のとおりです。
typedef void (* xmlev_err_cb_funcp)(xmlctx *xctx, xmlevctx *evctx,
xmlevtype cur_event);
無効なAPIコールの例は次のとおりです。
XmlEvGetNameはXML_EVENT_CHARACTERSイベントに対してコールされません。
この項では、サンプルPull Parserアプリケーション、解析する文書、および文書から生成するイベントのリストについて説明します。
例18-4 サンプル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);
例18-5 解析するサンプル文書
<!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 -->
これは、属性イベント・プロパティがFALSEで展開エンティティ・プロパティがTRUEである場合に生成される一連のイベントです。
例18-6 サンプル文書の解析により生成されたイベント
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
この項では、Oracle Call Interface(OCI)からのXDK C関数のコールについて説明します。
データベースのXMLType列のXMLにC APIを使用できます。OCIプログラムでは、次のようなOCIハンドルの値を初期化することで、テーブルに格納されたXMLデータにアクセスできます。
環境ハンドル
サービス・ハンドル
エラー・ハンドル
オプションのパラメータ
プログラムでは、これらの入力値をOCIXmlDbInitXmlCtx()関数に渡すことができます。この関数はXMLコンテキストを戻します。プログラムでは、C APIをコールした後、OCIXmlDbFreeXmlCtx()関数によってコンテキストを解放します。
表18-6に、XML操作に使用する関数の一部を示します。
表18-6 XMLType関数
| 関数名 | 説明 |
|---|---|
|
|
空の |
|
|
ソース・バッファからの作成 |
|
|
|
|
|
XSLTスタイルシートを使用した変換 |
|
|
|
|
|
文書がスキーマベースかどうかの確認 |
|
|
スキーマ情報の取得 |
|
|
文書の名前空間の取得 |
|
|
スキーマを使用した検証 |
|
|
|
|
|
DOMからの |
XMLコンテキストは、すべてのC DOM API関数における必須パラメータです。この不透明なコンテキストは、データ・エンコーディング、エラー・メッセージ言語などに関する情報をカプセル化します。XMLコンテキストの内容は、XDKアプリケーションとOracle XML DBアプリケーションでは異なります。
|
注意: XML DBアプリケーションでXDK用のXMLコンテキストを使用したり、XDKアプリケーションで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);
|
関連項目:
|
XmlLoadDom()コールを使用して、クライアントに新しいXMLTypeインスタンスを構築できます。次の基本手順に従います。
「DOM API for Cの使用」の例に示されているように、最初にxmlctxを初期化する必要があります。
次のソースからXMLデータ自体を構築できます。
ユーザー・バッファ
ローカル・ファイル
URI
これらの場所からの戻り値は(xmldocnode *)であり、残りの共通C APIで使用できます。
最後に、(xmldocnode *)を(void *)にキャストし、必要に応じて直接バインド値として提供できます。
XmlCreateDocument()コールを使用して、空のXMLTypeインスタンスを構築できます。この関数は、他のタイプに対するOCIObjectNew()に相当します。前のコールで戻された(xmldocnode *)について操作し、バインド値として提供される必要がある場合、最後にこれを(void *)にキャストできます。
Oracle Database上のXMLデータは、OCI文のコールによって操作できます。xmldocnodeを使用してXMLType値をバインドして定義し、OCI文を使用してデータベースからXMLデータを選択できます。このデータは、C DOM関数で直接使用できます。同様に、SQL文に直接値をバインドできます。
例18-7に、DOM APIを使用してスキーマベース文書を構築し、データベースに保存する方法を示します。ヘッダー・ファイルxml.hおよびocixmldb.hをインクルードする必要があることに注意してください。
例18-7 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;
}
例18-8に、DOM APIを使用してデータベースから文書を取得し、変更する方法を示します。
例18-8 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;
}