この章の内容は次のとおりです。
XML SQL Utility(XSU)は、XDKコンポーネントの1つです。XSUを使用すると、Oracle SQL文を介してXMLデータを転送できます。XSUでは、次のタスクを実行できます。
オブジェクト・リレーショナル・データベースの表またはビューのデータをXMLに変換します。XSUは、データベースの問合せを実行し、結果セットをXML文書として戻します。
XML文書からデータを抽出し、正規マッピングを使用して、表またはビューへのデータの挿入、適切な列または属性の値を更新または削除できます。
この項の内容は次のとおりです。
この章では、次のテクノロジを十分に理解していると想定します。
Oracle Database SQL: XSUは、SELECT
文およびDMLを介して、データベースとの間でXMLを転送できます。
PL/SQL: XDKには、Java APIをミラー化するXSU用のPL/SQL APIがあります。
Java Database Connectivity(JDBC): XSUを使用してデータベースとの間でXMLの転送を行うJavaアプリケーションには、JDBC接続が必要です。
XSUの主な機能は次のとおりです。
DTDまたはXMLスキーマを動的に生成します。
XML文書を、文書の文字列またはDOM表現で生成します。
生成中、各<ROW>
要素のデフォルト・タグ名の変更など、単純な変換を実行します。XSLT変換を登録し、生成したXML文書に対して、必要に応じてその変換を適用できます。
SAX2コールバックのストリームとしてXMLを生成します。
生成中のXML属性をサポートします。この属性のサポートにより、特定の列または列のグループが、XML要素ではなくXML属性にマップされるように指定できます。
SQLからXMLへのタグのエスケープが可能です。列名が有効なXMLタグ名ではない場合があります。この問題を回避するには、すべての列名に別名を付けるか、またはタグをエスケープします。
オブジェクトまたは表内のXMLType
列をサポートします。
リレーショナル・データベースの表またはビューにXMLを挿入します。XML文書を指定すると、データベース・オブジェクトのレコードを更新または削除できます。
XSUを使用する場合は、次の制限に注意してください。
XSUは、単一表にのみデータを格納できます。ただし、Oracle XSLTプロセッサを使用して文書を複数の文書に変換し、これらの文書を別々に挿入することで、複数の表にXMLを格納できます。また、複数表にまたがるビューを定義し、ビューへの挿入を行うこともできます。このビューが更新不可能(複雑な結合などのために)な場合は、ビューにまたがってINSTEAD
OF
トリガーを使用して、挿入を実行できます。
属性に格納されたXMLデータはXSUを使用してデータベース・スキーマにロードできませんが、XSLT変換を使用して属性を要素に変更することは可能です。
デフォルトでは、XSUには大/小文字の区別があります。正確な大/小文字を使用するか、大/小文字の区別を無視するように指定できます。
XSUは、入力DTDからリレーショナル・データベース・スキーマを生成できません。
XSUを使用したXMLType
表への挿入はサポートされていません。XMLType
列はサポートされています。
この項の内容は次のとおりです。
次のインタフェースからXSUにアクセスできます。
oracle.xml.sql.query
パッケージのOracleXML
Query
およびOracleXMLSave
Javaクラス: OracleXMLQuery
クラスを使用してリレーショナル・データからXMLを生成し、OracleXMLSave
クラスを使用してDMLを実行します。
PL/SQLパッケージDBMS_XMLQuery
およびDBMS_XMLSave
: Javaクラスをミラー化します。
次のようなXSUアプリケーションを作成できます。
データベース内で実行して内部XSU Java APIにアクセスするJavaプログラム
クライアントで実行してクライアント側XSU Java APIにアクセスするJavaプログラム
PL/SQLパッケージを介してXSUにアクセスするPL/SQLプログラム
OracleXMLQuery
クラスは、XSUのJava APIのXML生成部分を構成します。図11-1に、XSUを使用してXMLを生成するための基本プロセスを示します。
図11-1の基本手順は次のとおりです。
データベースへのJDBC接続を作成します。通常では、JDBCドライバのセットを管理するDriverManager
クラスとの接続を確立します。JDBCドライバをロードした後、getConnection()
をコールします。適切なドライバが見つかると、このメソッドは、データベース・セッションを表すConnection
オブジェクトを戻します。すべてのSQL文は、このセッションのコンテキスト内で実行されます。
次のオプションがあります。
JDBC OCIドライバを使用して接続を作成します。次のコード部分は、この方法を示します。
// import the Oracle driver class
import oracle.jdbc.*;
// load the Oracle JDBC driver
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
// create the connection
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@","hr","password");
シンJDBCドライバを使用して接続を作成します。シン・ドライバはPure Javaで作成されており、すべてのJavaプログラムからコールできます。次のコード部分は、この方法を示します。
Connection conn =
DriverManager.getConnection("jdbc:oracle:thin:@dlsun489:1521:ORCL",
"hr","password");
シン・ドライバにはホスト名(dlsun489
)、ポート番号(1521)およびOracle SID(ORCL
)が必要です。データベースにはアクティブなTCP/IPリスナーが必要です。
サーバー側の内部JDBCドライバが使用するデフォルト接続を使用します。このドライバは、デフォルト・セッションおよびデフォルト・トランザクション・コンテキスト内で実行されます。ユーザーはすでにデータベースに接続されているため、ユーザーのSQL操作はデフォルト・トランザクションの一部です。したがって、ドライバを登録する必要はありません。Connection
オブジェクトを次のように作成します。
Connection conn = new oracle.jdbc.OracleDriver().defaultConnection ();
注意: OracleXMLDataSetExtJdbc はOracle JDBCでのみ使用され、OracleXMLDataSetGenJdbc はOracle以外のJDBCで使用されます。これらのクラスは、oracle.xml.sql.datasetパッケージにあります。 |
XML問合せオブジェクトを作成し、SQL問合せを割り当てます。コンストラクタにSQL問合せを渡して、OracleXMLQuery
クラスのインスタンスを作成します。次に例を示します。
OracleXMLQuery qry = new OracleXMLQuery (conn, "SELECT * from EMPLOYEES");
OracleXMLQuery
のメソッドを起動して、XML問合せオブジェクトを構成します。次の例は、結果セットに20行のみ含めることを指定します。
xmlQry.setMaxRows(20);
OracleXMLQuery
のメソッドを起動して、DOMオブジェクトまたは文字列を戻します。DOMオブジェクトを取得する例を次に示します。
XMLDocument domDoc = (XMLDocument)qry.getXMLDOM();
文字列オブジェクトを取得する場合は次のとおりです。
String xmlString = qry.getXMLString();
必要に応じて、文字列またはDOMに対して追加の処理を行います。
関連項目:
|
OracleXMLSave
クラスを使用して、データベースのXMLを挿入、更新および削除します。図11-2に、基本プロセスを示します。
図11-2の基本手順は次のとおりです。
データベースへのJDBC接続を作成します。この手順は、「XSUのJava APIを使用したXMLの生成: 基本プロセス」で説明している最初の手順と同じです。
XML保存オブジェクトを作成し、DMLを実行するための表を割り当てます。コンストラクタに表名またはビュー名を渡します。次に例を示します。
OracleXMLSave sav = new OracleXMLSave(conn, "employees");
主キー列を指定します。たとえば、次のコードは、employee_id
がキー列であることを指定します。
String [] keyColNames = new String[1]; keyColNames[0] = "EMPLOYEE_ID"; sav.setKeyColumnList(keyColNames);
OracleXMLSave
のメソッドを起動して、XML保存オブジェクトを構成します。次の例は、salary
およびjob_id
列の更新を指定します。
String[] updateColNames = new String[2]; updateColNames[0] = "SALARY"; updateColNames[1] = "JOB_ID"; sav.setUpdateColumnList(updateColNames); // set the columns to update
OracleXMLSave
オブジェクトに対してinsertXML()
、updateXML()
またはdeleteXML()
メソッドを起動します。次に更新の例を示します。
// Assume that the user passes in this XML document as the first argument sav.updateXML(sav.getURL(argv[0]));
DMLの実行中に、XSUは次のタスクを行います。
入力XML文書を解析します。
要素名をターゲットの表またはビューにある列名と照合します。
要素をSQL型に変換し、適切な文にバインドします。
OracleXMLSave
オブジェクトをクローズし、関連するすべてのコンテキストを割当て解除します。次に例を示します。
sav.close();
関連項目:
|
XSUのPL/SQL APIは、XML文書の生成およびデータベースへの格納の方法がJava APIに似ています。DBMS_XMLQuery
は、OracleXMLQuery
Javaクラスのメソッドが反映されたPL/SQLパッケージです。このパッケージには、パッケージに対応付けられたコンテキスト・ハンドルがあります。コンストラクタに類似したファンクションの1つをコールしてコンテキストを作成し、ハンドルを取得してそのハンドルをすべての副問合せコールに使用します。
注意: パフォーマンス向上のため、DBMS_XMLQUERY ではなく、Cで記述されデータベースに組み込まれたCベースのDBMS_XMLGEN の使用を検討してください。 |
XSUは、XMLType
データ型をサポートします。XSUでのXMLType
の使用は、オブジェクトまたは表内にXMLType
列が含まれる場合などに有効です。
XMLを生成すると、XML文書を含むCLOBが生成されます。DBMS_XMLQuery
およびXSU生成エンジンを使用するための基本手順は次のとおりです。
XML問合せコンテキストの変数および生成されたXMLの変数を宣言します。次に例を示します。
v_queryCtx DBMS_XMLQuery.ctxType; v_result CLOB;
DBMS_XMLQuery.newContext
ファンクションをコールし、CLOB
またはVARCHAR2
のいずれかで問合せを指定して、コンテキスト・ハンドルを取得します。次の例では、バインド変数:EMPLOYEE_ID
および:FIRST_NAME
を含むWHERE
句を使用して、employees
表から行を選択する問合せを登録します。
v_queryCtx = DBMS_XMLQuery.newContext('SELECT * FROM employees WHERE employee_id=:EMPLOYEE_ID AND first_name=:FIRST_NAME');
値を問合せにバインドします。バインドは、名前を位置にバインドすることで行われます。clearBindValues
は、すべてのバインド変数を消去し、setBindValue
は、単一のバインド変数に文字列値を設定します。たとえば、employee_id
およびfirst_name
の値を次のようにバインドします。
DBMS_XMLQuery.setBindValue(v_queryCtx,'EMPLOYEE_ID',20); DBMS_XMLQuery.setBindValue(v_queryCtx,'FIRST_NAME','John');
問合せコンテキストを構成します。ROW
タグ名、ROWSET
タグ名、フェッチする行の数などの引数をオプションで設定します。次の例は、デフォルトのROWSET
要素名をEMPSET
に変更します。
DBMS_XMLQuery.setRowSetTag(v_queryCtx,'EMPSET');
結果をフェッチします。getXML
ファンクションを使用して、XMLをCLOB
として取得します。このファンクションをコールすると、DTDまたはXMLスキーマの有無にかかわらずXMLを生成できます。次の例は、文にバインド値を適用し、述語employee_id = 20
およびfirst_name = 'John'
に対応する結果を取得します。
v_result := DBMS_XMLQuery.getXML(v_queryCtx);
XMLの生成結果を処理します。たとえば、プログラムで次の変数を宣言するとします。
v_xmlstr VARCHAR2(32767); v_line VARCHAR2(2000);
v_result
に格納されたCLOB
を次のように出力できます。
v_xmlstr := DBMS_LOB.SUBSTR(v_result,32767); LOOP EXIT WHEN v_xmlstr IS NULL; v_line := substr(v_xmlstr,1,INSTR(v_xmlstr,CHR(10))-1); DBMS_OUTPUT.PUT_LINE('| ' || v_line); v_xmlstr := SUBSTR(v_xmlstr,INSTR(v_xmlstr,CHR(10))+1); END LOOP;
コンテキストをクローズします。次に例を示します。
DBMS_XMLQuery.closeContext(v_queryCtx);
DBMS_XMLSave
は、OracleXMLSave
Javaクラスのメソッドが反映されたPL/SQLパッケージです。このパッケージには、パッケージに対応付けられたコンテキスト・ハンドルがあります。コンストラクタに類似したファンクションの1つをコールしてコンテキストを作成し、ハンドルを取得してそのハンドルをすべての副問合せコールに使用します。
DBMS_XMLSave
を使用するための基本手順は次のとおりです。
XML保存コンテキストの変数およびDML操作の対象となる行数のための変数を宣言します。次に例を示します。
savCtx DBMS_XMLSave.ctxType; v_rows NUMBER;
DBMS_XMLSave.newContext
ファンクションをコールし、DML操作に使用する表名を指定して、コンテキスト・ハンドルを作成します。
savCtx := DBMS_XMLSave.newContext('hr.employees');
実行するDMLの種類に基づいてオプションを設定します。
挿入の場合は、setUpdateColumn
ファンクションに挿入する列のリストを設定できます。デフォルトでは、すべての列に値が挿入されます。次の例は、employees
表の5つの列を設定します。
DBMS_XMLSave.setUpdateColumn(savCtx,'EMPLOYEE_ID'); DBMS_XMLSave.setUpdateColumn(savCtx,'LAST_NAME'); DBMS_XMLSave.setUpdateColumn(savCtx,'EMAIL'); DBMS_XMLSave.setUpdatecolumn(savCtx,'JOB_ID'); DBMS_XMLSave.setUpdateColumn(savCtx,'HIRE_DATE');
更新の場合は、キー列のリストを指定する必要があります。オプションで、更新する列のリストも指定できます。この場合は、キー列名と一致するXML文書内のタグがUPDATE
文のWHERE
句に使用され、更新列のリストと一致するタグがUPDATE
文のSET
句に使用されます。次に例を示します。
DBMS_XMLSave.setKeyColumn(savCtx,'employee_id'); -- set key column -- set list of columns to update. DBMS_XMLSave.setUpdateColumn(savCtx,'salary'); DBMS_XMLSave.setUpdateColumn(savCtx,'job_id');
削除の場合は、デフォルトで、指定した文書の各<ROW>
要素にあるすべてのタグ値と一致するWHERE
句が作成されます。この動作は、キー列のリストを設定することでオーバーライドできます。この場合は、タグ名がリスト内の列と一致するタグ値のみが、削除する行の識別に使用されます(DELETE
文のWHERE
句に使用して有効)。次に例を示します。
DBMS_XMLSave.setKeyColumn(savCtx,'EMPLOYEE_ID');
insertXML
、updateXML
またはdeleteXML
ファンクションのコンテキストおよびXML文書を指定します。次に例を示します。
v_rows := DBMS_XMLSave.deleteXML(savCtx,xmlDoc);
DMLを必要な回数だけ繰り返します。
コンテキストをクローズします。次に例を示します。
DBMS_XMLSave.closeContext(savCtx);
「XSUのJava APIを使用したプログラミング」に示したJavaの例をモデルとして使用してください。
XSUは、他のXDKユーティリティとともにOracle DatabaseソフトウェアCDに含まれています。XSUのコンポーネントおよび依存性の説明は、「Java XDKコンポーネントの依存性」に記載されています。
デフォルトでは、Oracle Universal Installerによって、XSUがディスク上にインストールされ、データベースにロードされます。ユーザーが操作する必要はありません。OracleをインストールしたときにXSUをデータベースにロードしなかった場合は、次のように手動でインストールできます。
Oracle XML DBがインストールされていることを確認します。
xsu12.jar
ファイルをデータベースにロードします。このJARファイルには、XMLType
へのアクセスに関してxdb.jar
への依存性があります。JARファイルの詳細は、表3-1を参照してください。
$ORACLE_HOME/rdbms/admin/dbmsxsu.sql
スクリプトを実行します。このSQLスクリプトは、XSUのPL/SQL APIを構築します。
「XSUの使用: 基本プロセス」で説明しているように、XSUを使用するために、XSUをデータベースにロードする必要はありません。XSUは、Javaをサポートする任意の層に格納できます。
次の項では、インストール・オプションについて説明します。
図11-3に、データベースにインストールされたXSUライブラリを使用するアプリケーションの一般的なアーキテクチャを示します。データベース内で実行するXSUが生成したXMLは、データベースのアドバンスト・キュー内に置いて、他のシステムまたはクライアントにキューさせることができます。XMLは、データベース内のストアド・プロシージャを介して内部に配信するか、Webまたはアプリケーション・サーバーを通じて外部に配信します。
図11-3では、すべての矢印が両方向です。XSUでは、データを生成および保存できるため、データベース内で実行しているXSUにXMLを配信し、それを適切なデータベース表に挿入できます。
アプリケーション・アーキテクチャによっては、中間層のアプリケーション・サーバーを使用する必要がある場合もあります。このアプリケーション層には、Oracleデータベース、Oracleアプリケーション・サーバー、Javaプログラムをサポートするサード・パーティ製のアプリケーション・サーバーなどがあります。
様々な理由のために(たとえば、中間層で異なるJDBCデータ・ソースを統合するために)、中間層でSQL問合せまたはResultSets
からXMLを生成できます。この場合、中間層にXSUをインストールすると、JavaプログラムでJava APIを介してXSUを使用できます。
図11-4に、中間層でXSUを実行するための一般的なアーキテクチャを示します。中間層で、JDBCソースのデータはXSUによってXMLに変換され、Webサーバーまたは他のシステムに送信されます。ここでもプロセスは両方向であるため、XSUを使用してデータを元のJDBCソース(データベース表またはビュー)に戻すことができます。Oracleデータベース自体をアプリケーション・サーバーとして使用する場合は、JavaのかわりにPL/SQLのフロントエンドを使用できます。
図11-5に示すように、WebサーバーがJavaサーブレットをサポートする場合は、XSUをWebサーバー内で実行できます。この場合、XSUを使用するJavaサーブレットを作成できます。XSQLサーブレットは、Oracleが提供する標準のサーブレットです。XSQLサーブレットはXSUの最上位に構築され、XSUの機能にテンプレート形式のインタフェースを提供します。WebサーバーでXML処理を実行し、サーブレットの複雑なプログラミングを避けるために、XSQLサーブレットを使用できます。
関連項目:
|
XSUのデモ・プログラムは、$ORACLE_HOME/xdk/demo/java/xsu
にあります。表11-1に、XSUのテストに使用できるXMLファイルとプログラムを示します。
表11-1 XSUのサンプル・ファイル
ファイル | 説明 |
---|---|
|
|
|
|
|
オブジェクト・リレーショナル・スキーマを設定し、データを移入するSQLスクリプト。「オブジェクト・リレーショナル・スキーマでのXMLのマッピング」を参照してください。 |
|
オブジェクト・リレーショナル・スキーマを設定し、データを移入するSQLスクリプト。「データベース・スキーマまたはSQL問合せの変更」を参照してください。 |
|
リレーショナル表を作成し、最上位にカスタマ・オブジェクトを持つカスタマ・ビューを作成するSQLスクリプト。「データベース・スキーマまたはSQL問合せの変更」を参照してください。 |
|
カスタマについて記述されたXML文書。「データベース・スキーマまたはSQL問合せの変更」を参照してください。 |
|
主キーで従業員を削除するPL/SQLプログラム。「DBMS_XMLSaveを使用したキーによる削除: 例」を参照してください。 |
|
行で従業員を削除するPL/SQLプログラム。「DBMS_XMLSaveを使用した行による削除: 例」を参照してください。 |
|
DOMツリーを生成し、ドキュメント内の順序でツリーを検索して、ノードを1つずつ出力するプログラム。「OracleXMLQueryを使用したDOMツリーの生成」を参照してください。 |
|
デモ・ディレクトリのプログラムについて説明するREADME。 |
|
XML文書を表に挿入するPL/SQLプログラム。「DBMS_XMLSaveを使用したすべての列への値の挿入」を参照してください。 |
|
|
|
XML文書を |
|
XML文書を |
|
XML文書を |
|
|
|
|
|
|
|
新しい従業員を記述したXML文書。「testInsertプログラムの実行」を参照してください。 |
|
新しい従業員を記述したXML文書。「testInsertSubsetプログラムの実行」を参照してください。 |
|
行がなくなると、例外を発生させるプログラム。「該当する行がない場合の例外の生成」を参照してください。 |
|
JDBCの |
|
結果ページを区切るXMLページを生成するプログラム。「OracleXMLQueryを使用した結果ページの区切り: 例」を参照してください。 |
|
結果ページを区切り形式にするPL/SQLスクリプト。最初の10行のバッチで |
|
CLOBを出力バッファへ出力するPL/SQLスクリプト。「DBMS_XMLQueryを使用した単純な問合せからのXMLの生成」を参照してください。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
同じコンテキストおよび設定を使用して、ユーザーの入力に基づいてDMLを実行するPL/SQLスクリプト。「DBMS_XMLSaveを使用したコンテキスト・ハンドルの再利用」を参照してください。 |
|
行の識別のために使用される要素の数を制限し、 |
|
入力XML文書のすべての |
|
XML文書のファイル名を入力として受け入れ、文書内の要素に対応する行を削除するプログラム。「OracelXMLSaveを使用した行による削除」を参照してください。 |
|
入力XML文書のすべての |
|
ランタイム例外を発生させ、 |
|
|
|
XMLデータを列のサブセットに挿入するPL/SQLスクリプト。「DBMS_XMLSaveを使用した列のサブセットへの挿入」を参照してください。 |
|
XMLデータを列のサブセットに挿入するプログラム。「OracleXMLSaveを使用した列のサブセットへのXMLの挿入」を参照してください。 |
|
REFカーソルを定義し、そのカーソルを戻すファンクションを作成するPL/SQLスクリプト。 |
|
|
|
|
|
各従業員の給与および役職名のみを更新し、他の情報を無視するとします。XML文書内のすべての |
|
プロシージャ |
|
XSUを使用して、XMLを |
|
一連の従業員の更新された給与およびその他の情報を含むXML文書。「testUpdateプログラムの実行」を参照してください。 |
|
一連の従業員の更新された給与およびその他の情報を含むXML文書。「testUpdateプログラムの実行」を参照してください。 |
|
2人の従業員の新規データを含むXML文書。「testUpdateListプログラムの実行」を参照してください。 |
|
|
デモの実行手順は次のとおりです。
ディレクトリを$ORACLE_HOME/xdk/demo/java/xsu
ディレクトリ(UNIXの場合)または%ORACLE_HOME%\xdk\demo\java\xsu
ディレクトリ(Windowsの場合)に変更します。
「Java XDK環境の設定」の説明に従って、環境変数が設定されていることを確認します。特に、XSUに対してはxsu12.jar
、JDBC対してはojdbc5.jar
(Java 1.5)がJavaクラスパスに含まれていることを確認してください。UTF-8、ISO8859-1またはJA16SJIS以外のマルチバイト・キャラクタ・セットを使用する場合は、クラスパスにorai18n.jar
を置いて、JDBCが入力ファイルのキャラクタ・セットをデータベースのキャラクタ・セットに変換できるようにします。
次の例のように、Javaプログラムをコンパイルします。
javac samp1.java samp2.java samp10.java
hr/hr
としてOracleデータベースに接続し、SQLスクリプトcreateRelSchema
を実行します。
CONNECT hr @$ORACLE_HOME/xdk/demo/java/xsu/createRelSchema
次の項では、XSUのデモについて詳しく説明します。
XDKには、XSUのためのコマンドラインJavaインタフェースがあります。XSUのコマンドライン・オプションは、JavaクラスOracleXML
を介して利用できます。このAPIを使用するには、「Java XDK環境の設定」の説明に従ってJavaクラスパスが設定されていることを確認します。
XSUの使用情報を標準出力に出力するには、次のコマンドを実行します。
java OracleXML
XSUを使用するには、次のようにgetXML
またはputXML
のいずれかのパラメータを使用します。
java OracleXML getXMLoptions
java OracleXML putXMLoptions
表11-2に、getXML
オプションを示します。
表11-2 getXMLオプション
getXMLオプション | 説明 |
---|---|
|
データベースに接続するためのユーザー名およびパスワードを指定します。このオプションを指定しないと、デフォルトで |
|
JDBCデータベースの接続文字列を指定します。デフォルトの接続文字列は" |
|
XML文書とともにDTDも生成するようにXSUに指示します。 |
|
XML文書とともにスキーマも生成するようにXSUに指示します。 |
|
ROWSETタグを指定し、問合せによって戻されたレコードに対応するすべてのXML要素を囲みます。デフォルトのROWSETタグは、 |
|
ROWタグを指定し、データベース行に対応するデータを囲みます。デフォルトのROWタグは |
|
|
- |
問合せからのスカラー列の1つの値が、 |
|
XMLリスト要素の属性に名前を付け、リストの要素の数を追跡します。生成されるXMLリストは、カーソル問合せまたはコレクションのいずれかに対応します。 |
|
column-elementタグに使用する型名を指定します。デフォルトでは、XSUは |
|
属性 |
|
XML処理命令にスタイルシートを指定します。 |
|
XML処理命令にスタイルシートの型を指定します。 |
|
XML文書に適用するXSLTスタイルシートを指定します。 |
|
XSLT外部実体参照を設定します。 |
|
小文字または大文字のタグ名を生成します。デフォルトでは、大/小文字は、タグ名の生成元のSQLオブジェクト名に一致します。 |
|
SQLオブジェクト名では有効であっても、XMLタグでは無効な文字の対処方法を指定します。このような文字を検出した場合は、エスケープして例外を発生させません。 |
|
XMLにフォーマットされたエラー・メッセージを囲むタグを指定します。 |
|
XSUがJava例外を発生させることを指定します。デフォルトでは、XSUがエラーを捕捉し、XMLエラーを発行します。 |
|
行が戻されなかった場合に例外を発生させます。 |
|
入力データに対して厳密なチェックを行います。 |
|
XMLに変換するために取得される行の最大数を指定します。 |
|
スキップされる行の数を指定します。 |
|
生成されるXMLのキャラクタ・セットのエンコーディングを指定します。 |
|
XML文書内の日付値用の書式を指定します。 |
|
問合せを含むファイル名または問合せ自体を指定します。 |
表11-3に、putXML
オプションを示します。
表11-3 putXMLオプション
putXMLオプション | 説明 |
---|---|
|
データベースに接続するためのユーザー名およびパスワードを指定します。このオプションを指定しないと、デフォルトで |
|
JDBCデータベースの接続文字列を指定します。デフォルトの接続文字列は" |
|
バッチ・サイズを指定します。これによって、バッチされ、一度にデータベースに挿入される行の数を制御し、パフォーマンスを改善できます。 |
|
コミットが実行される挿入レコードの数を指定します。自動コミットを |
|
|
|
XML文書内の日付値用の書式を指定します。 |
|
文書の生成時にSQLからXMLへの名前のエスケープを使用すると、逆マッピングが有効になります。 |
|
列名とタグ名を大/小文字を区別せずに一致させます。たとえば、 |
|
挿入されるXML文書内の空白を保持します。 |
|
挿入前にXML文書に適用するXSLTを指定します。 |
|
XSLT外部実体参照を設定します。 |
|
挿入するXML文書を指定します。ローカル・ファイル、URLまたはXML文書をコマンドライン上の文字列として指定します。 |
|
値を挿入する表の名前を指定します。 |
データベース・スキーマからXMLを生成するには、getXML
パラメータを使用します。たとえば、hr
スキーマにあるemployees
表に問合せを行ってXML文書を生成するには、次の構文を使用できます。
java OracleXML getXML -user "hr/password" "SELECT * FROM employees"
前述のコマンドによって次のタスクが実行されます。
現在のデフォルト・データベースへの接続
指定されたSELECT
問合せの実行
SQL結果のXMLへの変換
標準出力へのXMLの出力
getXML
パラメータは、表11-2に示した広範囲なオプションをサポートします。
XSUを使用して、XMLType
列を持つ表からXMLを生成できます。デモ・スクリプトsetup_xmltype.sql
を実行してparts
表を作成し、表にデータを挿入するとします。XSUを使用して、この表から次のようにXMLを生成できます。
java OracleXML getXML -user "hr/password" -rowTag "Part" "SELECT * FROM parts"
次にコマンドの出力を示します。
<?xml version = '1.0'?> <ROWSET> <Part num="1"> <PARTNO>1735</PARTNO> <PARTNAME>Gizmo</PARTNAME> <PARTDESC> <Description> <Title>Description of the Gizmo</Title> <Author>John Smith</Author> <Body> The <b>Gizmo</b> is <i>grand</i>. </Body> </Description> </PARTDESC> </Part> </ROWSET>
new_employees.xml
というXML文書をhr.employees
表に挿入するには、次の構文を使用します。
java OracleXML putXML -user "hr/password" -fileName "new_employees.xml" employees
前述のコマンドによって次のタスクが実行されます。
hr
として現在のデータベースに接続
new_emp.xml
というXML文書の読取り
タグと列名を一致させてXML文書を解析
employees
表への値の適切な挿入
getXML
パラメータは、表11-2に示した広範囲なオプションをサポートします。
この項の内容は次のとおりです。
testXMLSQL.java
デモ・プログラムは、XSUを使用してXMLをString
オブジェクトとして生成します。このプログラムはhr.employees
表に問合せを行って結果セットを標準出力に出力します。
testXMLSQL.java
プログラムは次の手順を実行します。
JDBCドライバを登録し、データベース接続を作成します。次のコード部分は、OCI JDBCドライバを使用し、ユーザー名hr
で接続します。
import oracle.jdbc.*;...Connection conn = getConnection("hr","password");
...
private static Connection getConnection(String username, String password)
throws SQLException
{
// register the JDBC driver
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
// create the connection using the OCI driver
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",username,password);
return conn;
}
XML問合せオブジェクトを作成し、SQL問合せを使用して初期化します。次のコード部分は、hr.employees
に対するSELECT
文を使用してオブジェクトを初期化します。
OracleXMLQuery qry = new OracleXMLQuery(conn, "SELECT * FROM employees");
問合せの結果セットをString
オブジェクトとして取得します。getXMLString()
メソッドは、コンストラクタで指定されたオブジェクト・リレーショナル・データをXMLに変換します。次の例に、この方法を示します。
String str = qry.getXMLString();
次のコードに示すように、問合せオブジェクトをクローズしてすべてのリソースを解放します。
qry.close();
次の手順に従って、testXMLSQL.java
プログラムを実行します。
javac
を使用してtestXMLSQL.java
をコンパイルします。
コマンドラインでjava testXMLSQL
を実行します。
Java実行可能ファイルがクラスを検索できるように、CLASSPATH
がこのディレクトリを指すようにする必要があります。このプログラムのコンパイルおよび実行には、OracleのJDeveloperなどのビジュアルなJavaツールも使用できます。このプログラムを実行すると、画面にXMLファイルが出力されます。次に、いくつかの行が編集されているサンプル出力を示します。
<?xml version = '1.0'?> <ROWSET> <ROW num="1"> <EMPLOYEE_ID>100</EMPLOYEE_ID> <FIRST_NAME>Steven</FIRST_NAME> <LAST_NAME>King</LAST_NAME> <EMAIL>SKING</EMAIL> <PHONE_NUMBER>515.123.4567</PHONE_NUMBER> <HIRE_DATE>6/17/1987 0:0:0</HIRE_DATE> <JOB_ID>AD_PRES</JOB_ID> <SALARY>24000</SALARY> <DEPARTMENT_ID>90</DEPARTMENT_ID> </ROW> <!-- ROW num="2" through num="107" ... --> </ROWSET>
XSUが生成したXMLからDOMツリーを生成するには、XSUにDOM文書を直接リクエストします。この方法は、XML文書の文字列表現を作成するオーバーヘッドを伴わずに、XML文書を解析してDOMツリーを生成します。
XSUは、Oracle XMLパーサーをコールしてデータ値からDOMツリーを構築します。domTest.java
デモ・プログラムは、DOMツリーを生成し、ドキュメント内の順序でツリーを検索して、ノードを1つずつ出力します。
domTest.java
プログラムの最初の2つの手順は、「OracleXMLQueryを使用した文字列の生成」のtestXMLSQL.java
プログラムの場合と同じです。プログラムは次のように続行します。
getXMLDOM()
メソッドを起動してDOMを取得します。次の例に、この方法を示します。
XMLDocument domDoc = (XMLDocument)qry.getXMLDOM();
DOMツリーを出力します。標準出力に出力するためのコードは次のとおりです。
domDoc.print(System.out);
次のようにStringWriter
を作成し、PrintWriter
にラップすることもできます。
StringWriter s = new StringWriter(10000); domDoc.print(new PrintWriter(s)); System.out.println(" The string version ---> \n"+s.toString());
プログラムをコンパイルした後、次のようにコマンドラインから実行します。
java domTest
この項の内容は次のとおりです。
testXMLSQL.java
およびdomTest.java
で、XSUは問合せによって戻されたすべての行からXMLを生成しました。一度に100行のみ必要であるとき、1000行を含む表に問合せを行う場合を考えます。これには、1つの問合せを実行して最初の100行を取得し、別の問合せによって次の100行を取得し、100行ずつ取得していく方法があります。この方法では、問合せの最初の5行をスキップして結果を生成することはできません。この問題を回避するには、次のJavaメソッドを使用します。
OracleXMLSave.setSkipRows()
を使用すると、必要な行数を強制的にスキップさせて結果を生成できます。このメソッドと同等の効果を持つコマンドラインは、-skipRows
パラメータです。
OracleXMLSave.setMaxRows()
を使用すると、XMLに変換される行数を制限できます。このメソッドと同等の効果を持つコマンドラインは、-maxRows
パラメータです。
例11-1では、skipRows
の値を5
に設定し、maxRows
の値を1
に設定します。これによって、hr.employees
表に問合せを行うと、XSUは最初の5行をスキップしてから次の行のXMLを生成します。
例11-1 コマンドラインでのskipRowsおよびmaxRowsの指定
java OracleXML getXML -user "hr/password" -skipRows 5 -maxRows 1 \
"SELECT * FROM employees"
次にサンプル出力を示します(問合せ結果セットの6行目のみが戻されます)。
<?xml version = '1.0'?> <ROWSET> <ROW num="6"> <EMPLOYEE_ID>105</EMPLOYEE_ID> <FIRST_NAME>David</FIRST_NAME> <LAST_NAME>Austin</LAST_NAME> <EMAIL>DAUSTIN</EMAIL> <PHONE_NUMBER>590.423.4569</PHONE_NUMBER> <HIRE_DATE>6/25/1997 0:0:0</HIRE_DATE> <JOB_ID>IT_PROG</JOB_ID> <SALARY>4800</SALARY> <MANAGER_ID>103</MANAGER_ID> <DEPARTMENT_ID>60</DEPARTMENT_ID> </ROW> </ROWSET>
状況によっては、問合せオブジェクトをユーザーのセッション中オープンにしておくことが必要な場合があります。maxRows()
メソッドおよびkeepObjectOpen()
メソッドを使用すると、このような状況に対処できます。
検索の結果をページ区切りの形式にするWeb検索エンジンについて考えてみます。これらのエンジンでは、最初のページに10個の結果、次のページに次の10個のように結果が表示されます。XSUでこのタスクを実行するには、一度に10行ずつリクエストし、ResultSet
をオープン状態にしておきます。こうするとXSUは、次に追加の結果をリクエストされたときに、前回の生成が終了した箇所から生成を開始します。OracleXMLQuery
では、SQL問合せ文字列から結果セットを作成すると、それ以上の結果が必要でないと想定して、通常ではResultSet
を内部的にクローズします。したがって、keepObjectOpen()
を起動してカーソルをアクティブにしておく必要があります。
行数または行内の列数が多すぎる場合もオープンな問合せオブジェクトが必要になります。この場合は、1つの大きな文書を生成するのではなく、複数の小さな文書を生成できます。
paginateResults.java
プログラムは、結果ページを区切り形式にするXMLページの生成方法を示します。出力されるXMLでは、hr
表が20行のみ表示されます。
paginateResults.java
プログラムの最初の手順では、testXMLSQL.java
の場合と同様に、接続を作成します。このプログラムの処理の続きは次のとおりです。
SQL文オブジェクトを作成し、SQL問合せを使用して初期化します。次のコード部分は、java.sql.ResultSet
の2つのオプションを設定します。
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
問合せを文字列として作成し、Statement.executeQuery()
を起動して問合せを実行します。ResultSet
型のオブジェクトが戻されます。次の例に、この方法を示します。
String sCmd = "SELECT first_name, last_name FROM hr.employees"; ResultSet rs = stmt.executeQuery(sCmd);
次のコードに示すような問合せオブジェクトを作成します。
OracleXMLQuery xmlQry = new OracleXMLQuery(conn, rs);
問合せオブジェクトを構成します。次のコードは、セッションの期間中は問合せオブジェクトをオープンにしておくことを指定します。また、戻される行数を20行に制限しています。
xmlQry.keepObjectOpen(true); xmlQry.setRowsetTag("ROWSET"); xmlQry.setRowTag("ROW"); xmlQry.setMaxRows(20);
結果をString
として取得し、出力します。
String sXML = xmlQry.getXMLString(); System.out.println(sXML);
プログラムをコンパイルした後、次のようにコマンドラインから実行します。
java paginateResults
問合せを実行して、結果セットの中から、前のページの結果を取得することが必要になる場合があります。スクロールを使用可能にするには、Oracle.jdbc.ResultSet
クラスをインスタンス化します。このスクロール可能なResultSet
オブジェクトを使用して結果セット内を移動し、移動するたびにXSUを使用してXMLを生成できます。
pageTest.java
プログラムは、JDBCのResultSet
を使用して一度に1ページずつXMLを生成する方法を示します。ResultSet
は、バッチ・サイズの設定や値のバインドなど、XSUで直接処理されない操作のときに使用する必要があります。
pageTest.java
プログラムは、pageTest
オブジェクトを作成し、SQL問合せを使用して初期化します。pageTest
オブジェクトのコンストラクタは、次の手順を実行します。
paginateResults.java
に定義された同じgetConnection()
メソッドをコールして、JDBC接続を作成します。
Connection conn;
...
conn = getConnection("hr","password");
次のように文を作成します。
Statement stmt; ... stmt = conn.createStatement();
コンストラクタに渡される問合せを実行して、スクロール可能な結果セットを取得します。この方法を示すコードは次のとおりです。
ResultSet rset = stmt.executeQuery(sqlQuery);
接続への参照および結果セット・オブジェクトをコンストラクタに渡して、問合せオブジェクトを作成します。次のコード部分は、この方法を示します。
OracleXMLQuery qry; ... qry = new OracleXMLQuery(conn,rset);
問合せオブジェクトを構成します。次のコードコード部分は、問合せオブジェクトをオープン状態で保持し、行がなくなったときに問合せオブジェクトに例外を発生させます。
qry.keepObjectOpen(true); qry.setRaiseNoRowsException(true); qry.setRaiseException(true);
文字列"SELECT * FROM employees"
を渡して問合せオブジェクトを作成した後、プログラムは結果セット内をループします。getResult()
メソッドは、セットの開始行と終了行を指定する整数値を受け取ります。このメソッドは、受け取った値の差を計算して取得する最大行数を設定し、結果を文字列として取得します。次のwhile
ループは、一度に10行ずつ取得し、出力します。
int i = 0; while ((str = test.getResult(i,i+10))!= null) { System.out.println(str); i+= 10; }
プログラムをコンパイルした後、次のようにコマンドラインから実行します。
java pageTest
OracleXMLQuery
クラスは、問合せ文字列またはResultSet
オブジェクトに対してのみXML変換を行います。プログラムがPL/SQLプロシージャを使用し、このプロシージャがREF
カーソルを戻す場合の変換方法を考えてみます。この場合は、「スクロール可能な結果セットの生成」で説明したResultSet
変換メカニズムを使用できます。
REF
カーソルは、PL/SQL内のカーソル・オブジェクトへの参照です。これらのカーソル・オブジェクトは、一連の値を取得するためにプログラムで繰り返し処理されるSQL文です。これらのカーソル・オブジェクトは、JavaではOracleResultSet
オブジェクトに変換されます。Javaプログラムで、CallableStatement
オブジェクトを初期化し、カーソル変数を戻すPL/SQLファンクションを実行し、OracleResultSet
オブジェクトを取得したら、それをOracleXMLQuery
オブジェクトに送信して必要なXMLを取得できます。
testRef.sql
スクリプトで定義されたtestRef
PL/SQLパッケージについて考えてみます。このパッケージは、REF
カーソルを定義するファンクションを作成して戻します。testRefCur
PL/SQLファンクションは、コールされるたびにSELECT
問合せに対してカーソル・オブジェクトをオープンし、そのカーソル・インスタンスを戻します。オブジェクトをXMLに変換するには、次のようにします。
testRef.sql
スクリプトを実行してhr
スキーマ内にtestRef
パッケージを作成します。
refCurTest.java
プログラムをコンパイルおよび実行し、testRefCur
ファンクションに定義されたSQL問合せの結果からXMLを生成します。
スタイルシートを適用するには、applyStylesheet
コマンドを使用して、出力を生成する前にスタイルシートを強制的に適用します。
表またはビューに文書を挿入するには、表名またはビュー名と文書を指定します。XSUは文書(文字列が指定されている場合)を解析し、INSERT
文を作成してこの文にすべての値をバインドします。デフォルトでは、XSUは値を表またはビューのすべての列に挿入します。存在しない要素は、NULL
値として処理されます。次の例では、hr.employees
表から生成したXML文書を表に格納する方法を示します。
testInsert.java
デモ・プログラムは、hr.employees
表のすべての列にXML値を挿入します。
プログラムは次の手順を実行します。
JDBC/OCI接続を作成します。このプログラムは、この章にある前述の例で使用しているのと同じgetConnection()
メソッドをコールします。
Connection conn = getConnection("hr","password");
XML保存オブジェクトを作成します。Connection
の参照およびDML実行対象の表の名前を渡して、オブジェクトを初期化します。次の例に、この方法を示します。
OracleXMLSave sav = new OracleXMLSave(conn, "employees");
入力XML文書内のデータをhr.employees
表に挿入します。次のコード部分は、コマンドラインで指定された文書ファイル名からURLを作成します。
sav.insertXML(sav.getURL(argv[0]));
次のようにXML保存オブジェクトをクローズします。
sav.close();
従業員IDが7369の新しい従業員Janet Smithについてnew_emp.xml
文書を作成する場合を考えます。次のように、ファイル名new_emp.xml
を引数としてtestInsert
プログラムに渡します。
java testInsert "new_emp.xml"
指定した列の値を含む新しい行がemployees
表に挿入されます。行要素内に存在しない要素は、NULL
として扱われます。
プログラムを実行すると、次の形式のINSERT
文が生成されます。
INSERT INTO hr.employees (employee_id, first_name, last_name, email, phone_number, hire_date, salary, commission_pct, manager_id, department_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
列名と一致している入力XML文書内の要素タグが照合され、その値がバインドされます。
値を挿入する必要がない列がある場合もあります。たとえば、取得する値が完全なセットではなく、残りの列のためにトリガーまたはデフォルト値を使用する必要がある場合などです。testInsertSubset.java
デモ・プログラムは、その処理の方法を示します。
プログラムは次の手順を実行します。
JDBC/OCI接続を作成します。このプログラムは、この章にある前述の例で使用しているのと同じgetConnection()
メソッドをコールします。
Connection conn = getConnection("hr","password");
XML保存オブジェクトを作成します。Connection
の参照およびDMLを実行する表名を渡して、オブジェクトを初期化します。次の例に、この方法を示します。
OracleXMLSave sav = new OracleXMLSave(conn, "employees");
文字列の配列を作成します。配列の各要素は、値が挿入される列の名前を指定します。次のコード部分は、列の名前を5つ指定します。
String [] colNames = new String[5]; colNames[0] = "EMPLOYEE_ID"; colNames[1] = "LAST_NAME"; colNames[2] = "EMAIL"; colNames[3] = "JOB_ID"; colNames[4] = "HIRE_DATE";
指定した列を更新するためのXML保存オブジェクトを構成します。次の文は、OracleXMLSave.setUpdateColumnList()
メソッドに、配列への参照を渡します。
sav.setUpdateColumnList(colNames);
入力XML文書内のデータをhr.employees
表に挿入します。次のコード部分は、コマンドラインで指定された文書ファイル名からURLを作成します。
sav.insertXML(sav.getURL(argv[0]));
次のようにXML保存オブジェクトをクローズします。
sav.close();
new_emp2.xml
文書を使用して、従業員IDが7400の新しい従業員Adamsのデータを格納する場合を考えます。次のように、new_emp2.xml
を引数としてtestInsert
プログラムに渡します。
java testInsert new_emp2.xml
入力ファイルに指定されていない列の値は、無視されます。入力に含まれる各ROW
要素のINSERT
を実行し、INSERT
文はデフォルトでバッチ処理されます。
このプログラムで生成されるINSERT
文は次のとおりです。
INSERT INTO hr.employees (employee_id, last_name, email, job_id, hire_date) VALUES (?, ?, ?, ?, ?);
表名またはビュー名、およびXML文書を指定して、表またはビューのフィールドを更新します。XSUは文書(文字列が指定されている場合)を解析し、1つ以上のUPDATE
文を作成してこの文にすべての値をバインドします。次の例に、XML文書を使用してhr.employees
表を更新する方法を示します。
testUpdate.java
デモ・プログラムは、OracleXMLSave.setKeyColumnList()
メソッドを起動してhr.employees
表を更新します。
testUpdate.java
プログラムは次の手順を実行します。
JDBC/OCI接続を作成します。このプログラムは、この章にある前述の例で使用しているのと同じgetConnection()
メソッドをコールします。
Connection conn = getConnection("hr","password");
XML保存オブジェクトを作成します。Connection
の参照およびDML実行対象の表の名前を渡して、オブジェクトを初期化します。次の例に、この方法を示します。
OracleXMLSave sav = new OracleXMLSave(conn, "employees");
単一要素のString
配列を作成して、更新する表の主キー列の名前を保持します。次のコード部分は、employee_id
列の名前を指定します。
String [] keyColNames = new String[1]; colNames[0] = "EMPLOYEE_ID";
XML保存オブジェクトを配列内に指定された主キーに設定します。次の文は、OracleXMLSave.setKeyColumnList()
メソッドに、keyColNames
配列への参照を渡します。
sav.setKeyColumnList(keyColNames);
入力XML文書内に指定された行を更新します。次の文は、コマンドラインで指定されたファイル名からURLを作成します。
sav.updateXML(sav.getURL(argv[0]));
次のようにXML保存オブジェクトをクローズします。
sav.close();
XSUを使用して、表内の指定したフィールドを更新できます。例11-2のupd_emp.xml
には、追加した2人の従業員、7369および7400の更新済の給与およびその他の情報が含まれます。
例11-2 upd_emp.xml
<?xml version='1.0'?> <ROWSET> <ROW num="1"> <EMPLOYEE_ID>7400</EMPLOYEE_ID> <SALARY>3250</SALARY> </ROW> <ROW num="2"> <EMPLOYEE_ID>7369</EMPLOYEE_ID> <JOB_ID>SA_REP</JOB_ID> <MANAGER_ID>145</MANAGER_ID> </ROW> <!-- additional rows ... --> </ROWSET>
更新の場合は、UPDATE
文のWHERE
句に、キー列の名前のリストを指定します。hr.employees
表では、employee_id
列がキーです。
次のように、前述のプログラムにファイル名upd_emp.xml
を引数として渡します。
java testUpdate upd_emp.xml
このプログラムは、2つのUPDATE
文を生成します。最初のROW
要素には、SALARY
フィールドを更新するためのUPDATE
文が次のように生成されます。
UPDATE hr.employees SET salary = 3250 WHERE employee_id = 7400;
2番目のROW
要素には、次の文が生成されます。
UPDATE hr.employees SET job_id = 'SA_REP' AND MANAGER_ID = 145 WHERE employee_id = 7369;
XML文書内の要素のサブセットのみを使用して、表を更新する場合もあります。このような更新を実行するには、列のリストを指定できます。XSUはすべてのROW
要素に対してバインド変数を持つ同じUPDATE
文を使用するため、列リストを指定すると処理速度が向上します。また、XML文書内にある他のタグを無視できます。
注意: 更新する列のリストを指定すると、更新する列に対応する要素が存在しない場合は、その要素がNULL として処理されることに注意してください。 |
各従業員の給与および役職名を更新し、他のデータを無視するとします。XML文書内のすべてのROW
要素について、更新対象の要素がすべて同じである場合は、OracleXMLSave.setUpdateColumnNames()
メソッドを使用して列を指定できます。testUpdateList.java
プログラムは、この方法を示します。
testUpdateList.java
プログラムは次の手順を実行します。
JDBC/OCI接続を作成します。このプログラムは、この章にある前述の例で使用しているのと同じgetConnection()
メソッドをコールします。
Connection conn = getConnection("hr","password");
XML保存オブジェクトを作成します。Connection
の参照およびDML実行対象の表の名前を渡して、オブジェクトを初期化します。次の例に、この方法を示します。
OracleXMLSave sav = new OracleXMLSave(conn, "employees");
String
型の配列を作成して、更新する表の主キー列の名前を保持します。配列には、更新する表の主キー列の名前を持つ1つの要素のみ指定します。次のコード部分は、employee_id
列の名前を指定します。
String [] colNames = new String[1]; colNames[0] = "EMPLOYEE_ID";
XML保存オブジェクトを配列内に指定された主キーに設定します。次の文は、OracleXMLSave.setKeyColumnList()
メソッドにcolNames
配列への参照を渡します。
sav.setKeyColumnList(keyColNames);
String
型の配列を作成して、更新する列の名前を保持します。次のコード部分は、employee_id
列の名前を指定します。
String[] updateColNames = new String[2]; updateColNames[0] = "SALARY"; updateColNames[1] = "JOB_ID";
XMLの保存オブジェクトに更新する列のリストを設定します。このタスクを実行する文は次のとおりです。
sav.setUpdateColumnList(updateColNames);
入力XML文書内に指定された行を更新します。次のコード部分は、コマンドラインで指定されたファイル名からURLを作成します。
sav.updateXML(sav.getURL(argv[0]));
次のようにXML保存オブジェクトをクローズします。
sav.close();
サンプルXML文書upd_emp2.xml
を使用して、従業員IDが100のSteven Kingおよび従業員IDが206のWilliam Gietzの新しいデータを格納する場合を考えます。次のように、upd_emp2.xml
を引数としてtestUpdateList
プログラムに渡します。
java testUpdateList upd_emp2.xml
この例では、プログラムが2つのUPDATE
文を生成します。最初のROW
要素には、次の文が生成されます。
UPDATE hr.employees SET salary = 8350 AND job_id = 'AC_ACCOUNT' WHERE employee_id = 100;
2番目のROW
要素には、次の文が生成されます。
UPDATE hr.employees SET salary = 25000 AND job_id = 'AD_PRES' WHERE employee_id = 206;
XML文書からの削除の場合は、キー列のリストを指定できます。これらの列は、DELETE
文のWHERE
句で使用されます。キー列名を指定しないと、XML文書の各ROW
要素に対して新しいDELETE
文が作成されます。DELETE
文のWHERE
句にある列のリストと、ROW
要素にある列は一致します。
testDeleteRow.java
デモ・プログラムは、XML文書のファイル名を入力として受け入れ、文書内の要素に対応する行を削除します。
testDeleteRow.java
プログラムは次の手順を実行します。
JDBC/OCI接続を作成します。このプログラムは、この章にある前述の例で使用しているのと同じgetConnection()
メソッドをコールします。
Connection conn = getConnection("hr","password");
XML保存オブジェクトを作成します。Connection
の参照およびDML実行対象の表の名前を渡して、オブジェクトを初期化します。次の例に、この方法を示します。
OracleXMLSave sav = new OracleXMLSave(conn, "employees");
入力XML文書内で指定された行を削除します。次のコード部分は、コマンドラインで指定されたファイル名からURLを作成します。
sav.deleteXML(sav.getURL(argv[0]));
次のようにXML保存オブジェクトをクローズします。
sav.close();
「OracleXMLSaveを使用した行の挿入」で追加した従業員7400および7369を削除する必要があるとします。
この例を正しく実行するには、データベースに接続し、hr.job_history
表に対する制約を無効にします。
CONNECT hr ALTER TABLE job_history DISABLE CONSTRAINT JHIST_EMP_FK; EXIT
次のように、testDeleteRow
プログラムにupd_emp.xml
を渡します。
java testDeleteRow upd_emp.xml
プログラムは、XML文書内の各ROW
要素にあるタグ名に基づいてDELETE
文を構成します。次の文が実行されます。
DELETE FROM hr.employees WHERE salary = 3250 AND employee_id = 7400; DELETE FROM hr.employees WHERE job_id = 'SA_REP' AND MANAGER_ID = 145 AND employee_id = 7369;
DELETE
文の述語としてキー値のみを使用する場合は、OracleXMLSave.setKeyColumnList()
メソッドを起動します。行の識別に使用する要素の数を制限するこの方法には、DELETE
文をキャッシュし、トランザクションをバッチ化することによるパフォーマンス向上という利点があります。testDeleteKey.java
プログラムは、この方法を示します。
testDeleteKey.java
プログラムは次の手順を実行します。
JDBC/OCI接続を作成します。このプログラムは、この章にある前述の例で使用しているのと同じgetConnection()
メソッドをコールします。
Connection conn = getConnection("hr","password");
XML保存オブジェクトを作成します。Connection
の参照およびDML実行対象の表の名前を渡して、オブジェクトを初期化します。次の例に、この方法を示します。
OracleXMLSave sav = new OracleXMLSave(conn, "employees");
String
型の配列を作成して、表の主キー列の名前を保持します。この配列には、1つの要素のみ指定します。次のコード部分は、employee_id
列の名前を指定します。
String [] colNames = new String[1]; colNames[0] = "EMPLOYEE_ID";
XML保存オブジェクトを配列内に指定された主キーに設定します。次の文は、OracleXMLSave.setKeyColumnList()
メソッドにcolNames
配列への参照を渡します。
sav.setKeyColumnList(keyColNames);
入力XML文書内で指定された行を削除します。次のコード部分は、コマンドラインで指定されたファイル名からURLを作成します。
sav.deleteXML(sav.getURL(argv[0]));
次のようにXML保存オブジェクトをクローズします。
sav.close();
「OracleXMLSaveを使用したキー列による更新」で追加した従業員7400および7369を削除する必要があるとします。前述の例でこれらの従業員がすでに削除されている場合は、次のように、最初にこれらの従業員を元のemployees
表に追加できます。
java testInsert new_emp.xml java testInsert new_emp2.xml
testDeleteRow
プログラムに同じupd_emp.xml
文書を渡して、従業員7400および7369を削除します。
java testDeleteKey upd_emp.xml
次の形式の単一のDELETE
文が生成されます。
DELETE FROM hr.employees WHERE employee_id=?;
次のDELETE
文が、各従業員に対して1つ実行されます。
DELETE FROM hr.employees WHERE employee_id = 7400; DELETE FROM hr.employees WHERE employee_id = 7369;
XSUは、処理中に発生したすべての例外を捕捉し、一般的なランタイム例外であるoracle.xml.sql.OracleXMLSQLException
を発生させます。適切な処置を実行できる場合は、コールするプログラムはこの例外を捕捉する必要がありません。例外クラスには、エラー・メッセージおよび存在する場合は親である例外も取得するためのメソッドがあります。
testException.java
デモ・プログラムは、ランタイム例外を発生させ、Exception.getParentException()
を起動して親である例外を取得します。
前述のプログラムを実行すると、次のエラー・メッセージが生成されます。
Caught SQL Exception:ORA-00904: "SD": invalid identifier
XSUは、処理する行がない場合はNULL
文字列を戻します。ただし、プログラムが例外ハンドラを使用して例外を処理できるように、行がなくなるたびに例外を発生させることができます。OracleXMLQuery.setRaiseNoRowsException()
を起動すると、XSUは、出力用に生成する行がなくなるたびに、oracle.xml.sql.OracleXMLSQLNoRowsException
を発生させます。これはランタイムの例外であり、捕捉する必要はありません。
noRowsTest.java
デモ・プログラムは、pageTest.java
に定義されたpageTest
クラスをインスタンス化します。終了を確認する条件が、結果がnull
かどうかの確認から、例外ハンドラに変更されました。
noRowsTest.java
プログラムは、pageTest
オブジェクトを作成し、SQL問合せを使用して初期化します。プログラムは次のように続行します。
問合せオブジェクトを構成するか、行がなくなった場合の例外を発生させます。次のコード部分は、この方法を示します。
pageTest test = new pageTest("SELECT * from employees"); ... test.qry.setRaiseNoRowsException(true);
結果セット内を無限ループして、一度に10行ずつ取得します。使用可能な行がなくなると、プログラムは例外を発生させます。次のコード部分は、一度に10行ずつ結果セットをスクロールするpageTest.nextPage()
をコールします。
try { while(true) System.out.println(test.nextPage()); }
行がなくなったときの例外を捕捉し、"END OF OUTPUT"と出力します。この方法を示すコードは次のとおりです。
catch(oracle.xml.sql.OracleXMLSQLNoRowsException e) { System.out.println(" END OF OUTPUT "); try { test.close(); } catch ( Exception ae ) { ae.printStackTrace(System.out); } }
プログラムをコンパイルした後、次のようにコマンドラインから実行します。
java noRowsTest
この章の内容は次のとおりです。
注意: パフォーマンス向上のため、DBMS_XMLQuery およびDBMS_XMLSave のかわりに、DBMS_XMLGen およびDBMS_XMLStore の使用を検討してください。前者の2つのパッケージはCで記述され、データベース・カーネルに組み込まれています。XML_Element などのSQL/XML関数を使用して、データベースのXMLにアクセスすることもできます。 |
この項では、DBMS_XMLQuery
パッケージを使用してSQL問合せからXMLを生成する方法を示します。この例を実行するには、hr
としてデータベースに接続し、printClobOut.sql
スクリプトを実行します。このスクリプトは、CLOBを出力バッファに出力する単純なプロシージャprintClobOut
を作成します。SQL*PlusでprintClobOut
プロシージャを実行すると、入力CLOBが画面に出力されます。結果を表示するには、サーバーの出力をON
に設定します。表示バッファを増やして全出力を表示する必要がある場合があります。
simpleQuery.sql
スクリプトを実行して、hr.employees
表から20行選択し、XML文書をCLOBとして取得します。プログラムは、最初に問合せを渡してコンテキスト・ハンドルを取得し、次にgetXML
ファンクションをコールしてCLOB値を取得します。文書のエンコーディングは、データベース・キャラクタ・セットのエンコーディングと同じになります。このサンプル・アプリケーションでは、printClobOut.sql
を実行してprintClobOut
プロシージャが作成されていることが前提になっています。
XSUのPL/SQL APIを使用して、デフォルトのROW
およびROWSET
要素名を変更できます。これらはデフォルトの名前であり、結果の各行の先頭と末尾、および出力XML文書全体の先頭と末尾にそれぞれ置かれます。このタスクを実行するには、PL/SQLプロシージャsetRowTagName
およびsetRowSetTagName
を使用します。
hr
として接続し、SQL*PlusでchangeElementName.sql
スクリプトを実行して、employees
表の最初の20行をXML文書として取得します。無名のPL/SQLブロックによって、ROW
およびROWSET
要素名がEMP
およびEMPSET
に変更されます。このブロックは、printClobOut.sql
の実行によって作成されたprintClobOut
プロシージャをコールすることに注意してください。
生成されるXML文書には、<EMPSET>
文書要素が含まれます。各行は、<EMP>
タグによって区切られています。
次のPL/SQLファンクションをコールして、問合せの結果ページを区切ることができます。
paginateResult.sql
スクリプトを実行して、結果ページを区切る無名ブロックを実行します。最初の10行のバッチでskipRows
を3に設定し、残りのバッチで0に設定すると、employees
表の最初の3行をスキップし、残りの行を一度に10行ずつ出力します。複数のフェッチの場合は、フェッチする行がなくなったときを確認する必要があります。これを行うには、setRaiseNoRowsException
をコールします。このプロシージャは、CLOBへの行の書込みがなかった場合に例外を発生させます。この例外は、終了条件として捕捉および使用できます。
XSUのPL/SQL APIは、次の方法で、生成したXML文書にスタイルシートを設定する機能を提供します。
setStylesheetHeader
プロシージャを使用して、結果にスタイルシート・ヘッダーを設定します。このプロシージャは、XML処理命令を追加して、スタイルシートを含めます。
生成の前に、結果のXML文書にスタイルシートを適用します。このメソッドを使用すると、パフォーマンスが大幅に向上します。このメソッドを使用しない場合は、XML文書をCLOBとして生成し、再度パーサーに送信し、スタイルシートを適用する必要があります。XSUはDOM文書を生成し、XMLパーサーをコールし、スタイルシートを適用してから結果を生成します。結果のXML文書にスタイルシートを適用するには、setXSLT
プロシージャを使用します。このプロシージャは、スタイルシートを使用して結果を生成します。
XSUのPL/SQL APIは、SQL文に値をバインドする機能を提供します。SQL文には、名前付きバインド変数を指定できます。このバインド変数の前には、コロン(:
)を付ける必要があります。bindSQLVariables.sql
スクリプトは、無名のPL/SQLブロックを実行し、employees
表の列にEMPLOYEE_ID
およびFIRST_NAME
の値をバインドします。
表またはビューにXML文書を挿入するには、表名またはビュー名、およびXML文書を指定します。XSUはXML文書(文字列が指定されている場合)を解析し、INSERT
文を作成してこの文にすべての値をバインドします。デフォルトでは、XSUは値を表またはビューのすべての列に挿入します。存在しない要素はNULL
として処理されます。
insProc.sql
デモ・スクリプトを実行して、PL/SQLストアド・プロシージャinsProc
を作成します。このストアド・プロシージャは、次のパラメータを受け入れます。
CLOB
としてのXML文書
文書を挿入する表の名前
insProc
プロシージャを起動して、XML文書を表に挿入できます。
insertClob.sql
スクリプトを実行して、xmldocument
という表を作成し、XML文書をCLOB
として表に格納します。XML文書には、従業員7370のLiz Gardnerが記述され、この従業員をhr.employees
表に挿入します。
例11-3 insertClob.sql
CREATE TABLE hr.xmldocument (docid NUMBER PRIMARY KEY, xml_text CLOB); -- insert an XML document into the CLOB column INSERT INTO hr.xmldocument (docid,xml_text) VALUES (1, '<?xml version="1.0"?> <ROWSET> <ROW num="1"> <EMPLOYEE_ID>7370</EMPLOYEE_ID> <FIRST_NAME>Liz</FIRST_NAME> <LAST_NAME>Gardner</LAST_NAME> <EMAIL>liz.gardner@business.com</EMAIL> <PHONE_NUMBER>650-555-6127</PHONE_NUMBER> <HIRE_DATE>12/18/2004 0:0:0</HIRE_DATE> <SALARY>3000</SALARY> <COMMISSION_PCT>0</COMMISSION_PCT> <JOB_ID>SH_CLERK</JOB_ID> <MANAGER_ID>103</MANAGER_ID> <DEPARTMENT_ID>20</DEPARTMENT_ID> </ROW> </ROWSET>');
例11-4に示されたinsertEmployee.sql
スクリプトを実行して、insProc
ストアド・プロシージャをコールし、Liz Gardnerをemployees
表に挿入します。
例11-4 insertEmployee.sql
DECLARE v_xml_text CLOB; BEGIN SELECT xml_text INTO v_xml_text FROM hr.xmldocument WHERE docid = 1; insProc(v_xml_text, 'employees'); END; /
「OracleXMLSaveを使用した行の挿入」に示したように、callinsProc
プロシージャを実行すると、例11-5で示す形式のINSERT
文が生成されます。
例11-5 INSERT文の形式
INSERT INTO hr.employees (employee_id, first_name, last_name, email, phone_number, hire_date, salary, commission_pct, manager_id, department_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
列名と一致している入力XML文書内の要素タグが照合され、その値がバインドされます。
「OracleXMLSaveを使用した列のサブセットへのXMLの挿入」で説明しているように、値を挿入する必要がない列がある場合もあります。挿入処理を行う列名のリストを作成し、それをDBMS_XMLSave
プロシージャに渡すことができます。setUpdateColumnName
プロシージャを繰り返しコールし、コールするたびに更新する列名を渡すことで、これらの値を設定できます。列名の設定は、clearUpdateColumnList
を起動すると消去されます。
testInsert.sql
デモ・スクリプトを実行して、testInsert
というPL/SQLストアド・プロシージャを作成します。このプロシージャを使用して、CLOB型のXMLデータをhr.employees
表に挿入できます。
例11-6のinsertClob2.sql
スクリプトを実行して、新しい従業員Jordanについて記述されたXML文書をxmldocument
表のCLOB列に挿入します。文書には、employees
表のすべての列に対応する要素が含まれていない点に注意してください。
例11-6 insertClob2.sql
-- insert an XML document into the CLOB column of the xmldocument table with only -- some of the possible elements INSERT INTO hr.xmldocument (docid, xml_text) VALUES (2, '<?xml version="1.0"?> <ROWSET> <ROW num="1"> <EMPLOYEE_ID>7401</EMPLOYEE_ID> <LAST_NAME>Jordan</LAST_NAME> <EMAIL>jim.jordan@business.com</EMAIL> <JOB_ID>SH_CLERK</JOB_ID> <HIRE_DATE>12/17/2004 0:0:0</HIRE_DATE> </ROW> </ROWSET>');
例11-7のinsertEmployee2.sql
スクリプトを実行すると、従業員Jim Jordanのデータがhr.employees
表の列のサブセットに挿入されます。
例11-7 insertEmployee2.sql
DECLARE v_xml_text CLOB; BEGIN SELECT xml_text INTO v_xml_text FROM hr.xmldocument WHERE docid = 2; testInsert(v_xml_text); END; /
「OracleXMLSaveを使用した列のサブセットへのXMLの挿入」の場合と同様に、testInsert
をコールすると、次のINSERT
文が生成されます。
INSERT INTO hr.employees (employee_id, last_name, email, job_id, hire_date) VALUES (?, ?, ?, ?, ?);
「OracleXMLSaveを使用した行の更新」で説明しているように、XML文書を使用して表内の指定したフィールドを更新できます。キーとして使用する列を指定するか、更新する列のリストを渡すことができます。
testUpdateKey.sql
スクリプトを実行して、testUpdateKey
というPL/SQLプロシージャを作成します。このプロシージャは、hr.employees
表のemployee_id
列を主キーとして使用します。
例11-8のinsertClob3.sql
スクリプトを実行して、xmldocument
表のCLOB列にXML文書を挿入します。この文書は、従業員7400の新しい給与、および従業員7369の新しい仕事のIDおよびマネージャIDを指定します。
例11-8 insertClob3.sql
INSERT INTO hr.xmldocument (docid, xml_text) VALUES (3, '<?xml version="1.0"?> <ROWSET> <ROW num="1"> <EMPLOYEE_ID>7400</EMPLOYEE_ID> <SALARY>3250</SALARY> </ROW> <ROW num="2"> <EMPLOYEE_ID>7369</EMPLOYEE_ID> <JOB_ID>SA_REP</JOB_ID> <MANAGER_ID>145</MANAGER_ID> </ROW> </ROWSET>');
例11-9のupdateEmployee.sql
スクリプトを実行して、testUpdateKey
プロシージャにXML文書を渡し、2つのUPDATE
文を生成します。
例11-9 updateEmployee.sql
DECLARE v_xml_text CLOB; BEGIN SELECT xml_text INTO v_xml_text FROM hr.xmldocument WHERE docid = 3; testUpdateKey(v_xml_text); END; /
最初のROW
要素には、次のUPDATE
文が生成されます。
UPDATE hr.employees SET salary = 3250 WHERE employee_id = 7400;
2番目のROW
要素には、次の文が生成されます。
UPDATE hr.employees SET job_id = 'SA_REP' AND MANAGER_ID = 145 WHERE employee_id = 7369;
「OracleXMLSaveを使用した列リストの更新」で説明しているように、更新する列のリストを指定できます。
testUpdateSubset.sql
スクリプトを実行すると、PL/SQLプロシージャtestUpdateSubset
が作成されます。このプロシージャはemployee_id
列をキーとして使用し、hr.employees
表のsalary
およびjob_id
列のみを更新します。
insertClob4.sql
スクリプトを実行して、xmldocument
表にXML文書を挿入します。文書内の<ROW>
要素には、従業員100および206の記述があります。各<ROW>
要素には、説明テキストを含む10個のサブ要素があります。
例11-10のupdateEmployee2.sql
スクリプトを実行して、testUpdateSubset
プロシージャにXML CLOBを渡し、2つのUPDATE
文を生成します。
例11-10 updateEmployee2.sql
DECLARE v_xml_text CLOB; BEGIN SELECT xml_text INTO v_xml_text FROM hr.xmldocument WHERE docid = 4; testUpdateSubset(v_xml_text); END; /
プロシージャは、従業員100および206に関して、setUpdateColumn
プロシージャで指定された列、salary
およびemail
のみを更新します。
「OracleXMLSaveを使用した行の削除」で説明しているように、XSUが使用するキー列のリストを指定して、削除する行を決定できます。これらの列は、DELETE
文のWHERE
句で指定されます。
testDeleteRow.sql
スクリプトを実行して、testDeleteRow
PL/SQLプロシージャを作成します。プロシージャは、入力XML文書のすべての<ROW>
要素に対して、hr.employees
表から行を削除します。
例11-7で追加した従業員Jim Jordanを削除する必要があるとします。例11-11のdeleteEmployeeByRow.sql
スクリプトを実行して、XML文書をCLOBとしてtestDeleteRow
ストアド・プロシージャに渡します。
例11-11 行による削除
DECLARE v_xml_text CLOB; BEGIN SELECT xml_text INTO v_xml_text FROM hr.xmldocument WHERE docid = 2; testDeleteRow(v_xml_text); END; /
前述のtestDeleteRow
のコールは、次のDELETE
文を生成します。
DELETE FROM hr.employees WHERE employee_id = 7401 AND last_name = 'JORDAN' AND email = 'jim.jordan@business.com' AND job_id = 'SH_CLERK' AND hire_date = '12/17/2004 0:0:0';
プログラムは、XML文書内の各<ROW>
要素にあるタグ名に基づいてDELETE
文を構成します。
「OracleXMLSaveを使用したキーによる削除」で説明したように、削除操作の主キーとして使用する列を指定できます。DBMS_XMLSave.setKeyColumn
ファンクションを使用してキーを指定します。
testDeleteKey.sql
を実行して作成されたtestDeleteKey
プロシージャは、入力XML文書のすべての<ROW>
要素に対してemployees
表から行を削除します。
例11-4で追加した従業員Liz Gardnerを削除する必要があるとします。例11-12のdeleteEmployeeByKey.sql
スクリプトを実行して、XML文書をCLOBとしてtestDeleteKey
ストアド・プロシージャに渡します。
例11-12 キーによる削除
DECLARE v_xml_text CLOB; BEGIN SELECT xml_text INTO v_xml_text FROM hr.xmldocument WHERE docid = 1; testDeleteKey(v_xml_text); END; /
前述のプロシージャ・コールで、XSUは次のような単一のDELETE
文を生成します。
DELETE FROM hr.employees WHERE employee_id=?
XSUはこの文を入力XML文書のすべてのROW
要素に使用します。
優れたPL/SQLコードは、発生可能な例外を考慮して作成されています。raiseException.sql
の無名PL/SQLブロックは、DBMS_XMLQuery.getExceptionContent
プロシージャの起動方法を実例で示します。SQL*Plusでスクリプトを実行して、次のエラー・メッセージを出力します。
Exception caught 904 ORA-00904: "Z": invalid identifier
前項で示したDMLの例では、同じコンテキスト・ハンドルを複数の操作のために使用できます。save
コンテキストを作成したときに指定した同一の表に対してすべての挿入が行われる場合は、同じコンテキストを使用して複数のINSERT
を実行できます。同じコンテキストを使用してDML文を混合することもできます。
testDML.sql
スクリプトは、同じコンテキストおよび設定を使用して、ユーザーの入力に基づいてDMLを実行する方法を示します。この例では、すべてのファンクション・コールで同じコンテキストが使用されるように、PL/SQLパッケージの静的変数を使用してコンテキストを格納します。
スクリプトによって作成されたtestDML
パッケージでは、パッケージ全体(セッション)のためのコンテキストを1回作成し、複数のDML操作でコンテキストを再利用します。
注意: キー列employee_id が、行を識別する方法として更新と削除の両方に使用されることに注意してください。 |
スクリプトによって作成された3つのプロシージャのどれをコールしてもemployees
表を更新できます。
testDML.insertXML(xmlclob); testDML.deleteXML(xmlclob); testDML.updateXML(xmlclob);
各プロシージャ・コールが同じコンテキストを使用することで、これらの操作が頻繁に実行される場合は特にパフォーマンスが向上します。
この項では、XSUを使用したプログラムを作成するための追加のヒントと方法を示します。内容は次のとおりです。
表の基本コンポーネントは列ですが、XML文書の基本コンポーネントは要素と属性です。表はどのようにXML文書にマップされるのでしょうか。たとえば、hr.employees
表にlast_name
という列がある場合、この構造はXMLで、last_name
属性を持つ<EMPLOYEES>
要素、または異なるルート要素内の<LAST_NAME>
要素として表現されますが、これはどのような方法で行われるのでしょうか。この項では、これらの疑問に答えるため、SQLからXMLおよびXMLからSQLへのマッピングについて説明します。内容は次のとおりです。
hr.employees
表の列のデータをXML文書として表示する場合を想定します。次のように、コマンドラインでXSUを実行します。
java OracleXML getXML -user "hr/password" -withschema \
"SELECT employee_id, last_name, hire_date FROM employees"
XSUは、入力された問合せに基づいてXML文書を出力します。文書のルート要素は<DOCUMENT>
です。次にサンプル出力を示します。このサンプルでは、関連のない行はコメントに置き換えられています。
<?xml version = '1.0'?> <DOCUMENT xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- children of schema element ... --> </xsd:schema> <ROWSET xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="#/DOCUMENT/xsd:schema[not(@targetNamespace)]"> <ROW num="1"> <EMPLOYEE_ID>100</EMPLOYEE_ID> <LAST_NAME>King</LAST_NAME> <HIRE_DATE>6/17/1987 0:0:0</HIRE_DATE> </ROW> <!-- additional rows ... --> </ROWSET> </DOCUMENT>
生成されたXMLでは、SQL問合せによって戻された行は<ROWSET>
要素の子です。XML文書には、次の特徴があります。
<ROWSET>
要素には、戻された行数に応じて、0個以上の<ROW>
子要素があります。問合せによって行が生成されなかった場合、<ROW>
要素は含まれません。問合せによって行が1つ生成された場合は、1個の<ROW>
要素が含まれます。
各<ROW>
要素には、表の行の1つからのデータが含まれます。特に、各<ROW>
要素には、SELECT
文で指定されたデータベースの列と同一の名前およびコンテンツを持つ子要素が1つ以上あります。
オブジェクト・リレーショナル・スキーマからXML文書を生成する場合を考えてみます。SQL*PlusでcreateObjRelSchema.sql
スクリプトを実行して、オブジェクト・リレーショナル・スキーマを設定し、データを挿入します。スキーマには、ユーザー定義型を使用する2つの列を持つdept1
表があります。
コマンドラインからXSUを起動して、次のようにdept1
表の問合せを実行できます。
% java OracleXML getXML -user "hr/password" -withschema "SELECT * FROM dept1"
XSUは、例11-13のXML文書を戻します。このXML文書では、関連のない行はコメントに置き換えられています。
例11-13 XSUにより生成されたサンプル文書
<?xml version='1.0'?> <DOCUMENT xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <schema targetNamespace="http://xmlns.oracle.com/xdb/SYSTEM" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:SYSTEM="http://xmlns.oracle.com/xdb/SYSTEM"> <!-- children of schema element ... --> </xsd:schema> <ROWSET xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="#/DOCUMENT/xsd:schema[not(@targetNamespace)]"> <ROW num="1"> <DEPTNO>120</DEPTNO> <DEPTNAME>Treasury</DEPTNAME> <DEPTADDR> <STREET>2004 Charade Rd</STREET> <CITY>Seattle</CITY> <STATE>WA</STATE> <ZIP>98199</ZIP> </DEPTADDR> <EMPLIST> <EMPLIST_ITEM> <EMPLOYEE_ID>1</EMPLOYEE_ID> <LAST_NAME>Mehta</LAST_NAME> <SALARY>6000</SALARY> <EMPLOYEE_ADDRESS> <STREET>500 Main Road</STREET> <CITY>Seattle</CITY> <STATE>WA</STATE> <ZIP>98199</ZIP> </EMPLOYEE_ADDRESS> </EMPLIST_ITEM> </EMPLIST> </ROW> </ROWSET> </DOCUMENT>
前述の例と同様に、この例は正規のマッピングを示しています。<ROWSET>
には<ROW>
子要素が含まれ、これらの子要素には、dept1
の列に対応した子要素が含まれます。たとえば、<DEPTNAME>
要素は、dept1.deptname
列に対応しています。スカラー型の列に対応する要素は、列からのデータを含みます。
複雑な型の列に対応する要素の場合、マッピングはより複雑になります。例11-13で、<DEPTADDR>
は、オブジェクト型AddressType
のdept1.deptAddr
列に対応しています。したがって、<DEPTADDR>
は、AddressType
型で指定された属性に対応する子要素を含みます。AddressType
の属性street
は、子XML要素<STREET>
に対応し、他の属性も同様にそれぞれの子要素に対応しています。これらのサブ要素は、対応する属性の型が単純か複雑かによって、それ自体がデータやサブ要素を含む場合があります。
データベースのコレクションに対応する要素を処理する場合も、マッピングの方法が異なります。例11-13で、<EMPLIST>
要素は、EmployeeListType
型のemplist
列に対応します。したがって、<EMPLIST>
要素は、それぞれがコレクションの要素の1つに対応する<EMPLIST_ITEM>
要素のリストを含みます。次の点に注意してください。
<ROW>
要素は、カーディナリティ属性num
を含みます。
特定の列または属性の値がNULL
の場合、その行では、対応するXML要素がすべて省略されます。
最上位のスカラー列の名前がアットマーク(@)で始まる場合、その列はXML要素ではなくXML属性にマップされます。
XMLからSQLへのマッピングは、SQLからXMLへのマッピングの逆の操作です。XSUを使用してXMLからSQLへのマッピングを行う場合は、次の相違点を考慮に入れてください。
XMLからSQLへの変換では、XSUはXML属性を無視します。したがって、XML属性は実際にはSQLにマップされません。
SQLからXMLへの変換では、XSUはSQL問合せによって作成された単一のResultSet
に対してマッピングを行います。問合せは、複数のデータベース表またはビューに対して実行できます。XMLからSQLへの変換では、次の点に注意してください。
1つのXML文書を複数の表またはビューに挿入するには、ターゲットのスキーマにオブジェクト・リレーショナル・ビューを作成する必要があります。
ビューが更新不可能な場合は、INSTEAD OF INSERT
トリガーを使用できます。
XML文書がターゲットのデータベース・スキーマに完全にマップされない場合は、次の方法で対処できます。
ターゲットを変更します。ターゲットのスキーマにオブジェクト・リレーショナル・ビューを作成し、そのビューを新しいターゲットにします。
XSLTを使用してXML文書を変換して、XML文書を変更します。XSLTスタイルシートをXSUに登録すると、マッピングを試行する前に、受信したXMLを自動的に変換できます。
XSUのXMLからSQLへのマッピングを変更します。XML要素とデータベースの列または属性の一致で大/小文字を区別するように、XSUに対して指示できます。たとえば、XSUに対して次のことを指示できます。
ROW
のかわりに、データベースの行に対応する要素名を使用
XML文書の日付を解析するときに使用する日付書式の指定
特定の構造を持つXMLを生成する必要がある場合もあります。生成されたXML文書のデフォルトの構造が要求する構造と異なる場合があるため、このプロセスにはある程度の柔軟性が必要になります。次のいずれかの方法を使用して、生成されたXML文書の構造をカスタマイズできます。
ソースのカスタマイズは、SQL問合せまたはデータベース・スキーマを変更することによって行います。最も単純で強力なソースのカスタマイズは次のとおりです。
データベース・スキーマで、任意のXML文書構造にマップするオブジェクト・リレーショナル・ビューを作成します。
問合せで、次のことを行います。
カーソル副問合せまたはキャスト多重集合構造を使用して、フラットなスキーマから取得したXML文書でネストを作成します。
列名および属性名に別名を付けて、任意のXML要素を取得します。
アットマーク(@)で始まる識別子を使用して、最上位のスカラー型の列に別名を付け、これらの列をXML要素ではなくXML属性にマップします。たとえば、次の文を実行すると、<ROW>
要素が属性empno
を持つXML文書が生成されます。
SELECT employee_name AS "@empno",... FROM employees;
例11-14のcustomer.xml
文書について考えてみます。
例11-14 customer.xml
<?xml version = "1.0"?> <ROWSET> <ROW num="1"> <CUSTOMER> <CUSTOMERID>1044</CUSTOMERID> <FIRSTNAME>Paul</FIRSTNAME> <LASTNAME>Astoria</LASTNAME> <HOMEADDRESS> <STREET>123 Cherry Lane</STREET> <CITY>SF</CITY> <STATE>CA</STATE> <ZIP>94132</ZIP> </HOMEADDRESS> </CUSTOMER> </ROW> </ROWSET>
データベース表のセットを設計して、このデータを格納する必要があるとします。XMLは複数のレベルを持つネスト構造であるため、前述のXML文書に正規マッピングされるオブジェクト・リレーショナル・データベース・スキーマを使用できます。SQL*PlusでcreateObjRelSchema2.sql
スクリプトを実行して、このようなデータベース・スキーマを作成します。
スクリプトによって作成されるcustomer_tab
表に、customer.xml
文書のデータをロードできます。次のようにコマンドラインからXSU for Javaを起動します。
java OracleXML putXML -user "hr/password" -fileName customer.xml customer_tab
オブジェクト・リレーショナルでないデータベース・スキーマにcustomer.xml
をロードするには、標準のリレーショナル・スキーマの最上位にオブジェクトのビューを作成します。たとえば、必要な列を含むリレーショナル表を作成し、最上位にカスタマ・オブジェクトを持つカスタマ・ビューを作成できます。例11-15に、createRelSchema.sql
スクリプトを示します。
例11-15 createRelSchema.sql
CREATE TABLE hr.cust_tab ( customerid NUMBER(10), firstname VARCHAR2(20), lastname VARCHAR2(20), street VARCHAR2(40), city VARCHAR2(20), state VARCHAR2(20), zip VARCHAR2(20) ); CREATE VIEW customer_view AS SELECT customer_type(customerid, firstname, lastname, address_type(street,city,state,zip)) customer FROM cust_tab;
次のようにデータをcustomer_view
にロードできます。
java OracleXML putXML -user "hr/password" -fileName customer.xml customer_view
または、XSLTを使用してXMLをフラット化し、このXMLをリレーショナル・スキーマに直接挿入することもできます。ただし、この方法は、あまりお薦めできません。
特定の列または列のグループをXML要素ではなくXML属性にマップする必要があるとします。これを達成するには、列名に別名を作成し、この別名の前にアットマーク(@)を付加します。たとえば、mapColumnToAtt.sql
スクリプトを使用してhr.employees
表に問合せを行い、employee_id
をXML属性としてレンダリングできます。
次のようにコマンドラインからmapColumnToAtt.sql
スクリプトを実行できます。
java OracleXML getXML -user "hr/password" -fileName "mapColumnToAtt.sql"
注意: すべてのXML属性の列を先にマップする必要があります。 |
XSUを使用すると、SQLデータをXMLに変換するために使用する規則を変更できます。SQLからXMLへのマッピングでは、次のように変更できます。
<ROWSET>
または<ROW>
タグを変更または省略します。
num
属性を変更または省略します。これは、<ROW>
要素のカーディナリティ属性です。
生成されたXML要素名に大/小文字を指定します。
コレクションの要素に対応するXML要素が、カーディナリティ属性を持つように指定します。
XML文書の日付書式を指定します。
XML文書のnull値は、要素を省略せず、NULL属性を使用して表すように指定します。
この項では、XSUとデータベースの対話方法について説明します。
XSUはSQL問合せを実行し、データベースからResultSet
を取得します。次に、XSUはResultSet
に関するメタデータを取得し、分析します。「SQLからXMLへのデフォルト・マッピング」で説明したマッピングを使用して、XSUはSQLの結果セットを処理し、XML文書に変換します。
XSUは、特定の種類の問合せを処理できません。特に、LONG
型またはLONG RAW
型の列とSELECT
句のCURSOR()
式が混在している場合、処理できません。LONG
およびLONG RAW
は、JDBCがストリームとしてアクセスするデータ型の例で、使用は推奨されません。これらの列をCLOB
に移行すると、問合せは成功します。
XML文書のコンテンツを表またはビューに挿入するとき、XSUは次の手順を実行します。
ターゲットの表またはビューに関するメタデータを取得します。
メタデータに基づいて、SQL INSERT
文を生成します。たとえば、ターゲット表がdept1
で、dept1
からXML文書が生成されるとします。XSUは、次のようなINSERT
文を生成します。
INSERT INTO dept1 (deptno, deptname, deptaddr, emplist) VALUES (?,?,?,?)
XML文書を解析し、各レコードに対して、適切な列または属性に適切な値をバインドします。たとえば、INSERT
文に次のような値をバインドします。
deptno <- 100 deptname <- SPORTS deptaddr <- AddressType('100 Redwood Shores Pkwy','Redwood Shores', 'CA','94065') emplist <- EmployeeListType(EmployeeType(7369,'John',100000, AddressType('300 Embarcadero','Palo Alto','CA','94056'),...)
文を実行します。INSERT
処理を最適化して、バッチで挿入およびコミットできます。
更新および削除の文は、データベース表内の2つ以上の行に影響するという点で挿入と異なります。挿入では、表にトリガーまたは制約がない場合は、XML文書の1つの<ROW>
要素の影響を受けるのは表内で最大1つの行のみです。更新および削除では、一致する列が表内のキー列でない場合は、XML要素が2つ以上の行と一致する場合があります。
更新の文には、更新する行を識別するためにXSUが必要とするキー列のリストを提供する必要があります。たとえば、次のフラグメントを含むXML文書があるとします。
<ROWSET> <ROW num="1"> <DEPTNO>100</DEPTNO> <DEPTNAME>SportsDept</DEPTNAME> </ROW> </ROWSET>
DEPTNAME
の値をSports
からSportsDept
に変更します。DEPTNO
をキー列として指定すると、XSUは次のUPDATE
文を生成します。
UPDATE dept1 SET deptname = ? WHERE deptno = ?
XSUは、次のように値をバインドします。
deptno <- 100 deptname <- SportsDept
更新の場合は、XML文書にあるすべての要素を更新するのではなく、列の集合のみを更新するように選択できます。
削除の場合は、削除する行をXSUが識別できるように、キー列の集合を指定するように選択できます。キー列の集合を指定しないと、DELETE
文は文書にあるすべての列を一致させようとします。XSUに渡す次のような文書があるとします。
<ROWSET> <ROW num="1"> <DEPTNO>100</DEPTNO> <DEPTNAME>Sports</DEPTNAME> <DEPTADDR> <STREET>100 Redwood Shores Pkwy</STREET> <CITY>Redwood Shores</CITY> <STATE>CA</STATE> <ZIP>94065</ZIP> </DEPTADDR> </ROW> <!-- additional rows ... --> </ROWSET>
XSUは、各ROW
要素に対してDELETE
文を構築します。
DELETE FROM dept1 WHERE deptno = ? AND deptname = ? AND deptaddr = ?
バインドは次のとおりです。
deptno <- 100 deptname <- sports deptaddr <- addresstype('100 redwood shores pkwy','redwood city','ca', '94065')
デフォルトでは、XSUは明示的なコミットを行いません。AUTOCOMMIT
が、JDBC接続のデフォルトであるオンになっている場合、文の各バッチを実行した後、XSUはCOMMIT
を実行します。AUTOCOMMIT
をオフにし、setCommitBatch
を使用して、XSUがコミットする前に実行する文の数を指定することで、この動作をオーバーライドできます。エラーが発生した場合は、XSUへのコール前のターゲット表の状態、またはXSUへの現在のコール中に行われた前回のコミット後の状態にロールバックします。