この章の内容は次のとおりです。
XMLはデータ交換の形式になりますが、一方でオブジェクト・リレーショナル・データベースには相当量のデータが存在します。そのため、このオブジェクト・リレーショナルのデータをXMLに変換する機能が必要です。
XML SQL Utility(XSU)を使用すると、次の変換を実行できます。
オブジェクト・リレーショナル・データベースの表またはビューから取得したデータをXMLに変換できます。
XML文書からデータを抽出し、指定のマッピングを使用して、表またはビューの適切な列または属性にデータを挿入できます。
XML文書からデータを抽出して、適切な列または属性の値の更新や削除にこのデータを適用できます。
DTDを動的に生成します。
生成中、ROW要素のデフォルト・タグ名の変更など、単純な変換を実行します。XSL変換を登録し、生成したXML文書に対して、必要に応じてその変換を適用できます。
XML文書を、文書の文字列またはDOM表現で生成します。
データベースの表またはビューにXMLを挿入します。XML文書を指定すると、データベース・オブジェクトのレコードを更新または削除できます。
ネストされた複雑なXML文書を生成します。フラットな表上にオブジェクト・ビューを作成して、これらのビューを問い合せることで、リレーショナル表にXML文書を格納することもできます。オブジェクト・ビューでは、オブジェクト・リレーショナル・インフラストラクチャを使用して、既存のリレーショナル・データから構造化されたデータを作成できます。
SQL問合せを指定してXMLスキーマを生成します。
SAX2コールバックのストリームとしてXMLを生成します。
生成中にXML属性をサポートします。特定の列または列のグループをXML要素ではなくXML属性にマップすることを指定する簡単な方法を提供します。
SQL識別子からXML識別子へのエスケープが可能です。列名が有効なXMLタグ名ではない場合があります。この問題を回避するには、すべての列名に別名を付けるか、またはタグをエスケープします。
オブジェクトまたは表内のXMLType列をサポートします。
|
関連資料:
|
次にXSUに関する重要な情報を示します。
|
注意: Oracle9iでXMLGenは使用されなくなったため、現在のOracleソフトウェアに付属していません。XMLGENは、XML生成に使用されるDBMS_XMLQueryパッケージ、およびDMLとデータの操作に使用されるDBMS_XMLSaveパッケージに置き換えられています。
移行は簡単です。メソッド名は同じです。現在の新しいXSU for PL/SQLには、より多くのメソッドが含まれています。すべてのメソッドは、第1引数としてコンテキスト・ハンドルを取ります。 |
XML SQL Utility(XSU)は次のコンポーネントに依存します。
データベースの接続性 - JDBCドライバ。XSUはすべてのJDBCドライバとともに使用できますが、Oracle JDBCドライバとの使用が最適です。オラクル社では、Oracle以外のデータベースに対して実行しているXSUの保証やサポートは行いません。
Oracle XML Parserバージョン2- xmlparserv2.jar。このファイルはOracleインストールに含まれています。xmlparserv2.jarは、Oracle Technology Network(OTN)のWebサイトからダウンロード可能なXDK Javaコンポーネント・アーカイブの一部にもなっています。
XSUは、xdb.jarやservlet.jarに含まれるクラスにも依存します。これらはOracleインストールにあります。OTNからダウンロード可能なXDK Javaコンポーネント・アーカイブにも含まれています。
XSUはOracleソフトウェアのCDに収録されており、OTNで入手可能なXDK Javaコンポーネント・パッケージの一部にもなっています。XSUは次の2つのファイル形式で提供されます。
$ORACLE_HOME/lib/xsu12.jar -- XSUを構成するすべてのJavaクラスが含まれます。xsu12.jarの最小要件はJDK1.2およびJDBC2です。
$ORACLE_HOME/rdbms/admin/dbmsxsu.sql -- XSU PL/SQL APIを構築するSQLスクリプト。dbmsxsu.sqlを実行する前に、xsu12.jarをデータベースにロードします。
デフォルトでは、Oracleインストーラによって、前述の箇条書き段落で指定したハード・ドライブにXSUがインストールされます。XSUはデータベースにもロードされます。
XSUが最初にOracleをインストールするときにインストールされない場合、後からインストールできます。Oracleインストーラを使用してXSUとその依存コンポーネントをインストールするか、または最新のXDK JavaコンポーネントをOTNからダウンロードできます。
データベースにXSUをロードするには、XSUのインストール方法に応じて、次のいずれかの手順を実行する必要があります。
Oracleインストーラによるインストール: ディレクトリをORACLE_HOMEディレクトリに変更してから、rdbms/adminに移動します。initxml.sqlを実行します。
OTNからのダウンロードによるインストール: ディレクトリを、ダウンロードおよび展開したXDKツリーのbinディレクトリに変更します。xdk loadスクリプトを実行します。Windowsユーザーはxdkload.batを実行します。
XSUはJavaで記述されているため、Javaをサポートする任意の層に格納できます。XSUはクライアント・システムにインストールできます。
XSUを構成するJavaクラスは、Java対応のOracleデータベースにロードできます。XSUには、XSU Java APIをPL/SQLに公開してPL/SQL APIを作成するPL/SQLラッパーが含まれます。この場合、次の作業を実行できます。
データベース内で実行し、XSU Java APIに直接アクセスできる新しいJavaアプリケーションを作成します。
PL/SQL APIを介してXSUにアクセスするPL/SQLアプリケーションを作成します。
SQLを介して直接XSU機能にアクセスします。
図7-1に、このようなシステムに使用する一般的なアーキテクチャを示します。データベース内で実行するXSUが生成したXMLは、データベースのアドバンスト・キュー内に置いて、他のシステムまたはクライアントにキューさせることができます。XMLは、データベースのストアド・プロシージャ内から使用するか、Webサーバーまたはアプリケーション・サーバーを通じて外部に配信できます。
図7-1では、すべての矢印が両方向です。XSUでは、データを生成および保存できるため、様々なソースからデータベース内で実行しているXSUにデータを配信でき、それを適切なデータベース表に戻すことができます。
アプリケーション・アーキテクチャによっては、データベースから分離した中間層のアプリケーション・サーバーを使用する必要があります。このアプリケーション層には、Oracleデータベース、Oracle Application Server、Javaプログラムをサポートするサード・パーティ製のアプリケーション・サーバーなどがあります。
様々な理由で、SQL問合せまたはResultSetsによって中間層でXMLを生成できます。たとえば、中間層で異なるJDBCデータ・ソースを統合するなどの理由があります。この場合、中間層にXSUをインストールでき、JavaプログラムでJava APIを介してXSUを使用できます。
図7-2に、中間層でXSUを実行するための一般的なアーキテクチャを示します。中間層で、JDBCソースのデータはXSUによってXMLに変換され、Webサーバーまたは他のシステムに送信されます。ここでも全体のプロセスは両方向であるため、XSUを使用してデータをJDBCソース(データベース表またはビュー)に戻すことができます。Oracleデータベース自体をアプリケーション・サーバーとして使用する場合は、JavaのかわりにPL/SQLのフロントエンドも使用できます。
図7-3に示すように、WebサーバーがJavaサーブレットをサポートする場合は、XSUをWebサーバー内で実行できます。この場合、XSUを使用するJavaサーブレットを作成して、そのタスクを実行できます。
XSQLサーブレットはこのタスクのみを行います。XSQLサーブレットは、Oracleが提供する標準のサーブレットです。XSQLサーブレットはXSUの最上位に構築され、XSUの機能にテンプレート形式のインタフェースを提供します。WebサーバーでXML処理を実行するには、サーブレットの複雑なプログラミングを避けるために、XSQLサーブレットを使用できます。
この項では、SQLからXML(またはその逆)へのマッピングや変換について説明します。
表emp1について考えてみます。
CREATE TABLE emp1 ( empno NUMBER, ename VARCHAR2(20), job VARCHAR2(20), mgr NUMBER, hiredate DATE, sal NUMBER, deptno NUMBER );
XSUは、次の問合せを指定してXML文書を生成できます。
select * from emp1:
<?xml version='1.0'?>
<ROWSET>
<ROW num="1">
<EMPNO>7369</EMPNO>
<ENAME>sMITH</ENAME>
<JOB>clerk</JOB>
<mgr>7902</mgr>
<HIREDATE>12/17/1980 0:0:0</HIREDATE>
<SAL>800</SAL>
<DEPTNO>20</DEPTNO>
</ROW>
<!-- additional rows ... -->
</ROWSET>
生成されたXMLでは、SQL問合せによって戻された行は、<ROWSET>要素を構成するROWSETタグで囲まれています。この要素は、生成されたXML文書のルート要素でもあります。
<ROWSET>要素には、1つ以上の<ROW>要素が含まれます。
各<ROW>要素には、戻されたデータベース表のいずれかの行からのデータが含まれます。特に、各<ROW>要素には、名前とコンテンツが、SQL問合せのSELECTリストで指定されたデータベースの列の名前とコンテンツである要素が1つ以上あります。
データベースの列に対応するこれらの要素には、列からのデータが含まれます。
次に、オブジェクト・リレーショナル・スキーマでのマッピングを示します。AddressTypeオブジェクト・タイプについて考えてみます。これは属性がすべてスカラー型で次のように作成されるオブジェクト・タイプです。
CREATE TYPE AddressType AS OBJECT ( street VARCHAR2(40), city VARCHAR2(20), state CHAR(2), zip VARCHAR2(10) );
次に示すEmployeeTypeもオブジェクト型ですが、それ自体がオブジェクト型であるempaddr属性(具体的にはAddressType)を持っています。Employee Typeは次のように作成されます。
CREATE TYPE EmployeeType AS OBJECT ( empno NUMBER, ename VARCHAR2(20), salary NUMBER, empaddr AddressType );
次に示すEmployeeListType型は、その要素がオブジェクト型(EmployeeType)であるコレクション型です。EmployeeListTypeは次のように作成されます。
CREATE TYPE EmployeeListType AS TABLE OF EmployeeType;
最後に示すdept1は、オブジェクト型の列がAddressType、コレクション型の列がEmployeeListTypeになっている表です。
CREATE TABLE dept1 ( deptno NUMBER, deptname VARCHAR2(20), deptaddr AddressType, emplist EmployeeListType ) NESTED TABLE emplist STORE AS emplist_table;
有効な値が表dept1に格納されるとします。問合せselect * from dept1では、XSUによって次のXML文書が生成されます。
<?xml version='1.0'?>
<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>
<EMPLIST>
<EMPLIST_ITEM num="1">
<EMPNO>7369</EMPNO>
<ENAME>John</ENAME>
<SALARY>10000</SALARY>
<EMPADDR>
<STREET>300 Embarcadero</STREET>
<CITY>Palo Alto</CITY>
<STATE>CA</STATE>
<ZIP>94056</ZIP>
</EMPADDR>
</EMPLIST_ITEM>
<!-- additional employee types within the employee list -->
</EMPLIST>
</ROW>
<!-- additional rows ... -->
</ROWSET>
前述の例と同様に、この例は正規のマッピングを示しています。<ROWSET>には<ROW>要素が含まれ、<ROW>要素には、列に対応した要素が含まれます。すでに述べたように、スカラー型の列に対応する要素には、列からのデータがそのまま含まれます。
複雑な型の列に対応する要素の場合、マッピングはより複雑になります。たとえば、<DEPTADDR>は、オブジェクト型ADDRESSのDEPTADDR列に対応しています。したがって、<DEPTADDR>には、ADDRESS型で指定された属性に対応するサブ要素が含まれます。これらのサブ要素は、対応する属性の型が単純か複雑かによって、それ自体がデータやサブ要素を含む場合があります。
データベースのコレクションに対応する要素を処理する場合も、マッピングの方法が異なります。特に、<EMPLIST>要素は、コレクション型EmployeeListTypeのEMPLIST列に対応しています。したがって、<EMPLIST>要素は、それぞれがコレクションの要素の1つに対応する<EMPLIST_ITEM>要素のリストを含みます。
前述のマッピングに関するその他の注意点は次のとおりです。
<ROW>要素は、カーディナリティ属性numを含みます。
特定の列または属性の値がNULLの場合、その行では、対応するXML要素がすべて省略されます。
最上位のスカラー列の名前がアットマーク(@)で始まる場合、その特定の列はXML要素ではなくXML属性にマップされます。
場合によっては、特定の構造を持つXMLを生成する必要があります。生成されたXML文書のデフォルトの構造が要求する構造と異なる場合があるため、このプロセスにはある程度の柔軟性が必要になります。次のいずれかの方法を使用して、生成されたXML文書の構造をカスタマイズできます。
ソースのカスタマイズは、問合せまたはデータベース・スキーマを変更することで行います。最も単純で強力なソースのカスタマイズは次のとおりです。
データベース・スキーマで、任意のXML文書構造にマップするオブジェクト・リレーショナル・ビューを作成します。
問合せで次のことを行います。
カーソル副問合せまたはキャスト多重集合構造を使用して、フラットなスキーマから取得したXML文書でネストを作成します。
列名および属性名に別名を付けて、任意のXML要素を取得します。
アットマーク(@)で始まる識別子を使用して、最上位のスカラー型の列に別名を付け、これらの列をXML要素ではなくXML属性にマップします。たとえばSELECT empno AS "@empno",... FROM empの場合、<ROW>要素が属性EMPNOを持つXML文書が生成されます。
XML SQL Utilityを使用すると、SQLデータをXMLに変換するために使用するマッピングを変更できます。SQLからXMLへのマッピングでは、次のように変更できます。
<ROWSET>タグを変更または省略します。
<ROW>タグを変更または省略します。
num属性を変更または省略します。これは<ROW>要素のカーディナリティ属性です。
生成されたXML要素名に大/小文字を指定します。
コレクションの要素に対応するXML要素が、カーディナリティ属性を持つように指定します。
XML文書の日付書式を指定します。
XML文書のnull値は、要素を省略せず、NULL属性を使用して表すように指定します。
XMLからSQLへのマッピングは、SQLからXMLへのマッピングの逆の操作です。
XMLからSQLへのマッピングとSQLからXMLへのマッピングを比較した場合の次の相違点を考慮してください。
XMLからSQLへの変換では、XML属性が無視されます。したがって、XML属性は実際にはSQLにマップされません。
SQLからXMLへの変換では、SQL問合せによって作成されたResultSetからXMLに対してマッピングが行われます。この場合、問合せは複数のデータベース表またはビューに対して実行できます。XMLに変換される単一のResultSetが作成されます。XMLからSQLに変換する場合は、次の点に注意してください。
1つのXML文書を複数の表またはビューに挿入するには、ターゲットのスキーマにオブジェクト・リレーショナル・ビューを作成する必要があります。
ビューが更新不可能な場合は、INSTEAD-OF-INSERTトリガーを使用できます。
XML文書がターゲットのデータベース・スキーマに完全にマップされない場合は、次の3つの方法で対処できます。
ターゲットを変更します。ターゲットのスキーマにオブジェクト・リレーショナル・ビューを作成し、そのビューを新しいターゲットにします。
XML文書を変更します。XSLTを使用してXML文書を変換します。XSLTをXSUに登録すると、マッピングを試行する前に、受信したXMLが自動的に変換されます。
XSUのXMLからSQLへのマッピングを変更します。XML要素とデータベースの列または属性の一致で大文字と小文字を区別するように、XSUに対して指示できます。
ROWのかわりに、データベースの行に対応する要素名を使用するようにXSUに対して指示できます。
XML文書の日付を解析するときに使用する日付書式をXSUで指定できます。
この項では、次のタスクを実行する場合のXSUの機能について説明します。
XSUによる生成は簡単です。SQL問合せを実行し、データベースからResultSetを取得します。ResultSetに関するメタデータを取得して分析します。「SQLからXMLへのデフォルトのマッピング」で説明したマッピングを使用すると、SQLの結果セットが処理され、XML文書に変換されます。
XSUでは特定の種類の問合せを処理できません。特に、LONG型またはLONG RAW型の列とSelect句のCURSOR()式が混在している場合、処理できません。LONGおよびLONG RAWは、JDBCがストリームとしてアクセスするデータ型の例で、今は使用されていません。これらの列をCLOBに移行すると、問合せは成功します。
特定の表またはビューにXML文書のコンテンツを挿入する場合、XSUは最初にターゲットの表またはビューのメタデータを取得します。XSUはこのメタデータに基づいて、SQL INSERT文を生成します。XML文書からデータを抽出して、適切な列または属性にそのデータをバインドします。最後に文を実行します。
たとえば、ターゲット表がdept1で、dept1からXML文書が生成されるとします。
XSUは、次のようなINSERT文を生成します。
INSERT INTO dept1 (deptno, deptname, deptaddr, emplist) VALUES (?,?,?,?)
次にXSUはXML文書を解析し、レコードごとに、適切な列または属性に適切な値をバインドします。
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処理を最適化して、バッチで挿入およびコミットできます。
更新および削除は、データベース表内の複数の行に影響するという点で挿入と異なります。挿入では、表にトリガーまたは制約がない場合は、XML文書の1つのROW要素の影響を受けるのは表内で最大1つの行のみです。
ただし、更新および削除では、一致する列が表内のキー列でない場合は、XML要素が複数の行と一致する場合があります。更新では、更新する行を識別するためにXSUが必要とするキー列のリストを用意する必要があります。たとえば、DEPTNAMEをSportsではなくSportsDeptに更新する場合のXML文書は次のようになります。
<ROWSET>
<ROW num="1">
<DEPTNO>100</DEPTNO>
<DEPTNAME>SportsDept</DEPTNAME>
</ROW>
</ROWSET>
キー列としてDEPTNOを指定します。次のUPDATE文が生成されます。
UPDATE dept1 SET deptname = ? WHERE deptno = ?
値を次のようにバインドします。
deptno <- 100 deptname <- SportsDept
更新の場合は、XML文書にあるすべての要素を更新するのではなく、列の集合のみを更新するように選択できます。
削除の場合は、削除の対象として行を識別するように、キー列の集合の指定を選択できます。キー列の集合を指定しないと、DELETE文は文書に指定されたすべての列を一致させようとします。次のようなXML文書があるとします。
<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はDELETE文(ROW要素ごとに1つ)を構築します。
DELETE FROM dept1 WHERE deptno = ? AND deptname = ? AND deptaddr = ?
バインドは次のとおりです。
deptno <- 100
deptname <- sports
deptaddr <- addresstype('100 redwood shores pkwy','redwood city','ca',
'94065')
XSUには、XMLをすぐに生成および挿入できる簡単なコマンドライン・フロントエンドが付属しています。
XSUのコマンドライン・オプションは、JavaクラスOracleXMLを介して利用できます。次のようにコールしてこのクラスを起動します。
java OracleXML
これにより、フロントエンド使用情報が出力されます。XSUのコマンドライン・フロントエンドを実行するには、最初に実行ファイルが置かれている場所を指定します。CLASSPATHに次のライブラリを追加します。
また、XSUはOracle XML ParserおよびJDBCドライバに依存するため、これらのコンポーネントの場所を認識させます。これを実行するには、CLASSPATHに次のライブラリの場所を含める必要があります。
Oracle XML Parser Javaライブラリ(xmlparserv2.jar)
JDBCライブラリ(xsu12.jarを使用する場合はclasses12.jar、xsu111.jarを使用する場合はclasses111.jar)
XMLTypeのJARファイル
XSUの生成機能では、XSUのgetXMLパラメータを使用します。たとえば、hrスキーマにあるemployees表に問合せを行ってXML文書を生成するには、次の構文を使用します。
java OracleXML getXML -user "hr/hr" "select * from employees"
これにより、次のタスクが実行されます。
現在のデフォルト・データベースへの接続
問合せselect * from employeesの実行
結果のXMLへの変換
結果の表示
getXMLパラメータは様々なオプションをサポートします。これらのオプションについては、次のセクションで説明します。
表7-1に、OracleXML getXMLオプションを示します。
表7-1 XSUのOracleXML getXMLオプション
| getXMLオプション | 説明 |
|---|---|
|
|
データベースに接続するためのユーザー名およびパスワードを指定します。このオプションを指定しないと、デフォルトで |
|
|
JDBCデータベースの接続文字列を指定します。デフォルトの接続文字列は" |
|
|
XML文書とともにDTDも生成するようにXSUに指示します。 |
|
|
XML文書とともにスキーマも生成するようにXSUに指示します。 |
|
|
|
|
|
|
|
|
|
|
-rowIdColumn |
問合せからのスカラー列の1つの値が、 |
|
|
XMLリスト要素の属性に名前を付け、リストの要素の数を追跡します(生成されるXMLリストは、カーソル問合せまたはコレクションのいずれかに対応します)。 |
|
|
属性 |
|
|
XML PI(処理命令)にスタイルシートを指定します。 |
|
|
XML PI(処理命令)にスタイルシートの型を指定します。 |
|
|
エラー・タグ(XMLにフォーマットされたエラー・メッセージを囲むタグ)を指定します。 |
|
|
行が戻されなかった場合に例外を発生させるようにXSUに命令します。 |
|
|
XMLに変換するために取得される行の最大数を指定します。 |
|
|
スキップされる行の数を指定します。 |
|
|
生成されるXMLのキャラクタ・セットのエンコーディングを指定します。 |
|
|
XML文書内の日付値用の書式を指定します。 |
|
| |
問合せを含むファイル名または問合せ自体を指定します。 |
|
|
列と要素タグの型名を使用します(デフォルトではXSUは |
|
|
XSLT外部実体参照を設定します。 |
|
| - |
小文字または大文字のタグ名をそれぞれ生成します。デフォルトでは、大/小文字は、タグ名の生成元のSQLオブジェクト名に一致します。 |
|
|
SQLオブジェクト名では有効であっても、XMLタグでは無効な文字があります。このオプションは、このような文字を検出した場合、例外を発生させるのではなくエスケープすることを意味します。 |
|
|
デフォルトでは、XSUがエラーを捕捉し、XMLエラーを発行します。これにより、発生したJava例外をXSUが実際にスローするように動作が変更されます。 |
hrスキーマのemployees表にXML文書を挿入するには、次の構文を使用します。
java OracleXML putXML -user "hr/hr" -fileName "/tmp/temp.xml" "employees"
これにより、次のタスクが実行されます。
現在のデータベースに接続
指定のファイルからのXML文書の読取り
タグと列名を一致させてXML文書を解析
employees表への値の適切な挿入
|
注意: XSUのコマンドライン・フロントエンドputXMLは、現在XSUの挿入機能のみをパブリッシュします。
|
表7-2に、putXMLオプションを示します。
表7-2 XSUのOracleXML putXMLオプション
| putXMLオプション | 説明 |
|---|---|
|
|
データベースに接続するためのユーザー名およびパスワードを指定します。このオプションを指定しないと、デフォルトで |
|
|
JDBCデータベースの接続文字列を指定します。デフォルトの接続文字列は" |
|
|
バッチ・サイズを指定します。これによって、バッチされ、一度にデータベースに挿入される行の数を制御し、パフォーマンスを改善できます。 |
|
|
コミットが実行される挿入レコードの数を指定します。自動コミットを |
|
|
|
|
|
XML文書内の日付値用の書式を指定します。 |
|
|
列名とタグ名を大/小文字を区別せずに一致させます(たとえば、ignoreCaseがオンになっている場合、 |
|
|
挿入するXML文書(ローカル・ファイル)を指定します。 |
|
|
文書をフェッチするURLを指定します。 |
|
|
コマンドライン上の文字列としてXML文書を指定します。 |
|
|
値を挿入する表の名前です。 |
|
|
文書の生成時にSQLからXMLへの名前のエスケープを使用すると、逆マッピングが有効になります。 |
|
|
挿入前にXML文書に適用するXSLTです。 |
|
|
XSLT外部実体参照を設定します。 |
OracleXMLQueryクラスは、XSUのJava APIのXML生成部分を構成します。図7-4に、OracleXMLQueryを使用してXMLを生成する場合に必要な基本手順を示します。
接続を作成します。
SQL文字列またはResultSetオブジェクトを指定することにより、OracleXMLQueryインスタンスを作成します。
結果をDOMツリーまたはXML文字列として取得します。
1. 接続の作成
XMLを生成する前に、データベースへの接続を作成する必要があります。JDBC接続文字列を指定して接続を取得できます。最初にOracle JDBCクラスを登録してから、次のように接続を作成します。
// import the Oracle driver..
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","hr");
ここでは、JDBC OCIドライバのデフォルト接続を使用しています。パスワードtigerを指定するscottスキーマに接続できます。
JDBCシン・ドライバを使用して、データベースに接続することもできます。シン・ドライバはPure Javaで作成されており、アプレットまたは他のすべてのJavaプログラムからコールできます。
|
関連資料: 詳細は、『Oracle Database Java開発者ガイド』を参照してください。 |
次に、JDBCシン・ドライバを使用して接続する例を示します。
// Create the connection.
Connection conn =
DriverManager.getConnection("jdbc:oracle:thin:@dlsun489:1521:ORCL",
"hr","hr");
シン・ドライバでは、ホスト名(dlsun489)、ポート番号(1521)、およびマシン上で特定のOracleインスタンスを識別するOracle SID(ORCL)を指定する必要があります。
サーバーで実行する場合、接続は必要ありません。サーバー側のJavaコードを記述する場合(サーバーで実行するコードを記述する場合)、サーバー側の内部ドライバがデフォルト・セッション内で実行されるため、ユーザー名とパスワードを使用して接続を確立する必要はなく、すでに接続されています。この場合、oracle.jdbc.driver.OracleDriver()クラスでdefaultConnection()をコールして、次のように現在の接続を取得します。
import oracle.jdbc.*; // Load the Oracle JDBC driver DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); Connection conn = new oracle.jdbc.OracleDriver().defaultConnection ();
これ以降は、クライアントからのOCI接続を使用しているか、またはすでに接続オブジェクトが作成されていると仮定して説明します。必要に応じて、適切な接続作成を使用します。
|
注意: oracle.xml.sql.dataset.OracleXMLDataSetExtJdbcはOracle JDBCにのみ使用し、oracle.xml.sql.dataset.OracleXMLDataSetGenJdbcはOracle以外のJDBCに使用します。
|
2. OracleXMLQueryクラス・インスタンスの作成
接続を登録したら、次のように実行するSQL問合せを指定してOracleXMLQueryクラス・インスタンスを作成します。
// import the query class in to your class import oracle.xml.sql.query.OracleXMLQuery; OracleXMLQuery qry = new OracleXMLQuery (conn, "select * from employees");
これで問合せクラスを使用する準備ができました。
3. DOMツリーまたはXML文字列としての結果の取得:
DOMオブジェクトの出力。文字列ではなく、DOMオブジェクトが必要な場合、次のようにDOM出力をリクエストできます。
org.w3c.DOM.Document domDoc = qry.getXMLDOM();
さらにDOM検索を使用します。
XMLの文字列出力。結果のXML文字列を取得できます。
String xmlString = qry.getXMLString();
次に、XML文字列を抽出(生成)するプログラムの詳細を示します。このプログラムは文字列を取得し、標準出力に出力します。
import oracle.jdbc.*;
import oracle.xml.sql.query.OracleXMLQuery;
import java.lang.*;
import java.sql.*;
// class to test the String generation!
class testXMLSQL {
public static void main(String[] argv)
{
try{
// create the connection
Connection conn = getConnection("hr","hr");
// Create the query class.
OracleXMLQuery qry = new OracleXMLQuery(conn, "select * from employees");
// Get the XML string
String str = qry.getXMLString();
// Print the XML output
System.out.println(" The XML output is:\n"+str);
// Always close the query to get rid of any resources..
qry.close();
}catch(SQLException e){
System.out.println(e.toString());
}
}
// Get the connection given the user name and 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;
}
}
DOMは、解析したツリー状のフォームでXML文書を表します。各XMLエンティティがDOMノードになります。したがって、XMLの要素と属性がDOMノードになり、その子が子ノードになります。XSUが生成したXMLからDOMツリーを生成するには、XSUにDOM文書を直接リクエストできます。この方法は、XML文書の文字列表現を作成するオーバーヘッドを伴わずに保存し、XML文書を解析してDOMツリーを生成します。
XSUは、パーサーをコールしてデータ値からDOMツリーを直接構築します。次の例では、DOMツリーの生成方法を示します。この例ではDOMツリー内を移動し、すべてのノードを1つずつ出力します。
import org.w3c.dom.*;
import oracle.xml.parser.v2.*;
import java.sql.*;
import oracle.xml.sql.query.OracleXMLQuery;
import java.io.*;
class domTest{
public static void main(String[] argv)
{
try{
// create the connection
Connection conn = getConnection("hr","hr");
// Create the query class.
OracleXMLQuery qry = new OracleXMLQuery(conn, "select * from employees");
// Get the XML DOM object. The actual type is the Oracle Parser's DOM
// representation. (XMLDocument)
XMLDocument domDoc = (XMLDocument)qry.getXMLDOM();
// Print the XML output directly from the DOM
domDoc.print(System.out);
// If you instead want to print it to a string buffer you can do this.
StringWriter s = new StringWriter(10000);
domDoc.print(new PrintWriter(s));
System.out.println(" The string version ---> "+s.toString());
qry.close(); // Allways close the query!!
}catch(Exception e){
System.out.println(e.toString());
}
}
// Get the connection given the user name and password..!
private static Connection getConnection(String user, String passwd)
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",user,passwd);
return conn;
}
}
これまでに示した例では、XML SQL Utility(XSU)はResultSetまたは問合せを取得して、問合せのすべての行から文書全体を生成しました。一度に100行を取得するには、最初の100行、次の100行などを取得する際に異なる問合せを発行する必要があります。また、問合せの最初の5行をスキップして結果を生成することはできません。
これらの結果を取得するには、XSUのskipRowsパラメータおよびmaxRowsパラメータの設定を使用します。
skipRowsパラメータを設定すると、結果を生成する前に必要な行数を強制的にスキップします。
maxRowsは、XMLに変換される行数を制限します。
たとえば、skipRowsの値を5に設定し、maxRowsの値を10に設定すると、XSUは最初の5行をスキップしてから次の10行のXMLを生成します。
Webのシナリオによっては、問合せオブジェクトをユーザーのセッション中オープンにしておくことが必要な場合があります。たとえば、ページ区切り形式でユーザーの検索結果を提供するWeb検索エンジンの場合について考えてみます。最初のページに10個の結果、次のページに次の10個のように結果が表示されます。
これを実行するには、一度に10行ずつ変換し、ResultSetをアクティブ状態にするようXSUにリクエストします。こうするとXSUに対して次に追加の結果を要求したときに、前回の生成が終了した箇所から生成を開始します。
行数または行内の列数が多すぎる場合もあります。この場合は、それぞれのサイズが小さい複数の文書を生成できます。maxRowsパラメータやkeepObjectOpen関数を使用して、これらのケースも処理できます。
通常、指定したSQL問合せ文字列で結果セットを作成した場合、すべての結果が生成されるとすぐに、OracleXMLQueryはResultSetを内部的にクローズします。OracleXMLQueryがこれ以上の結果を必要としないと想定するためです。ただし、前述のケースのように、その状態を維持するには、keepObjectOpenファンクションをコールしてカーソルをアクティブにする必要があります。次の例を参照してください。
この例では、XSU for Java APIを使用してXMLページを生成できる方法を示しています。
import oracle.sql.*;
import oracle.jdbc.*;
import oracle.xml.sql.*;
import oracle.xml.sql.query.*;
import oracle.xml.sql.dataset.*;
import oracle.xml.sql.docgen.*;
import java.sql.*;
import java.io.*;
public class b
{
public static void main(String[] args) throws Exception
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection"jdbc:oracle:oci:@", "hr", "hr"();
Statement stmt =
conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
String sCmd = "SELECT FIRST_NAME, LAST_NAME FROM HR.EMPLOYEES";
ResultSet rs = stmt.executeQuery(sCmd);
OracleXMLQuery xmlQry = new OracleXMLQuery(conn, rs);
xmlQry.keepObjectOpen(true);
//xmlQry.setRowIdAttrName("");
xmlQry.setRowsetTag("ROWSET");
xmlQry.setRowTag("ROW");
xmlQry.setMaxRows(20);
//rs.beforeFirst();
String sXML = xmlQry.getXMLString();
System.out.println(sXML);
}
}
SQL問合せを指定して、その結果をXMLとして取得できることはわかりました。前述の例では、ページで区切られた結果を取得しました。ただしWebの場合、結果の次のページのみではなく前のページを取得する必要がある場合もあります。このスクロール機能を可能にするには、スクロール可能なResultSetを使用できます。このResultSetオブジェクトを使用して結果セット内を移動し、移動するたびにXSUを使用してXMLを生成します。次の例では、この実行方法を示します。
この例では、JDBC ResultSetを使用してXMLを生成する方法を示します。ResultSetは、バッチ・サイズの設定や値のバインドなど、XSUで直接処理されない場合に使用する必要があることに注意してください。この例では、以前定義したpageTestクラスを拡張して任意のページを処理します。
public class pageTest
{
Connection conn;
OracleXMLQuery qry;
Statement stmt;
ResultSet rset;
int lastRow = 0;
public pageTest(String sqlQuery)
{
try{
conn = getConnection("hr","hr");
stmt = conn.createStatement();// create a scrollable Rset
ResultSet rset = stmt.executeQuery(sqlQuery); // get the result set.
qry = new OracleXMLQuery(conn,rset); // create an OracleXMLQuery
// instance
qry.keepCursorState(true); // Don't lose state after the first fetch
qry.setRaiseNoRowsException(true);
qry.setRaiseException(true);
}
catch (Exception e )
{
e.printStackTrace(System.out);
}
}
// Get the connection given the user name and password..!
private static Connection getConnection(String user, String passwd)
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",user,passwd);
return conn;
}
// Returns the next XML page..!
public String getResult(int startRow, int endRow)
{
qry.setMaxRows(endRow-startRow); // set the max # of rows to retrieve..!
return qry.getXMLString();
}
// Function to still perform the next page.
public String nextPage()
{
String result = getResult(lastRow,lastRow+10);
lastRow+= 10;
return result;
}
public void close() throws SQLException
{
stmt.close(); // close the statement..
conn.close(); // close the connection
qry.close(); // close the query..
}
public static void main(String[] argv)
{
String str;
try{
pageTest test = new pageTest("select * from employees");
int i = 0;
// Get the data one page at a time..!!!!!
while ((str = test.getResult(i,i+10))!= null)
{
System.out.println(str);
i+= 10;
}
test.close();
}
catch (Exception e )
{
e.printStackTrace(System.out);
}
}
}
OracleXMLQueryクラスは、問合せ文字列またはResultSetに対してのみXML変換を行います。しかし、PL/SQLプロシージャを使用し、このプロシージャがREFカーソルを戻す場合のアプリケーションでは、変換はどのように行われるのでしょうか。
この場合、前述のResultSet変換メカニズムを使用してタスクを実行できます。REFカーソルはPL/SQL内のカーソル・オブジェクトへの参照です。これらのカーソル・オブジェクトは、一連の値を取得するために繰り返し処理できる有効なSQL文です。これらのREFカーソルは、JavaではOracleResultSetオブジェクトに変換されます。
これらのプロシージャを実行し、OracleResultSetオブジェクトを取得したら、それをOracleXMLQueryオブジェクトに送信して必要なXMLを取得できます。
REFカーソルを定義してそれを戻す次のPL/SQLファンクションを考えてみます。
CREATE OR REPLACE PACKAGE BODY testRef IS
function testRefCur RETURN empREF is
a empREF;
begin
OPEN a FOR select * from hr.employees;
return a;
end;
end;
/
このファンクションをコールするたびに、select * from employees問合せに対してカーソル・オブジェクトをオープンし、そのカーソル・インスタンスを戻します。オブジェクトをXMLに変換するには、次のようにします。
import org.w3c.dom.*;
import oracle.xml.parser.v2.*;
import java.sql.*;
import oracle.jdbc.*;
import oracle.xml.sql.query.OracleXMLQuery;
import java.io.*;
public class REFCURtest
{
public static void main(String[] argv)
throws SQLException
{
String str;
Connection conn = getConnection("hr","hr"); // create connection
// Create a ResultSet object by calling the PL/SQL function
CallableStatement stmt =
conn.prepareCall("begin ? := testRef.testRefCur(); end;");
stmt.registerOutParameter(1,OracleTypes.CURSOR); // set the define type
stmt.execute(); // Execute the statement.
ResultSet rset = (ResultSet)stmt.getObject(1); // Get the ResultSet
OracleXMLQuery qry = new OracleXMLQuery(conn,rset); // prepare Query class
qry.setRaiseNoRowsException(true);
qry.setRaiseException(true);
qry.keepCursorState(true); // set options (keep the cursor active.
while ((str = qry.getXMLString())!= null)
System.out.println(str);
qry.close(); // close the query..!
// Note since we supplied the statement and resultset, closing the
// OracleXMLquery instance will not close these. We need to
// explicitly close this ourselves..!
stmt.close();
conn.close();
}
// Get the connection given the user name and password..!
private static Connection getConnection(String user, String passwd)
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",user,passwd);
return conn;
}
}
一方でスタイルシートを適用するには、applyStylesheet()コマンドを使用します。このコマンドを使用すると、出力を生成する前にスタイルシートを強制的に適用します。
XSUは、処理する行がない場合はNULL文字列のみを戻します。ただし、アプリケーションが例外ハンドラを使用して例外を処理できるように、行がなくなるたびに例外を発生させることが望ましい状態です。setRaiseNoRowsException()を設定すると、出力用に生成する行がなくなるたびに、XSUはoracle.xml.sql.OracleXMLSQLNoRowsExceptionを発生させます。これはランタイムの例外であり、不要であれば捕捉する必要はありません。
次のコードは、前述の例を拡張したもので、NULL文字列の確認ではなく、例外を使用しています。
public class pageTest {
.... // rest of the class definitions....
public static void main(String[] argv)
{
pageTest test = new pageTest("select * from employees");
test.qry.setRaiseNoRowsException(true); // ask it to generate exceptions
try
{
while(true)
System.out.println(test.nextPage());
}
catch(oracle.xml.sql.OracleXMLSQLNoRowsException e)
{
System.out.println(" END OF OUTPUT ");
try{
test.close();
}
catch ( Exception ae )
{
ae.printStackTrace(System.out);
}
}
}
}
|
注意: 終了を確認する条件が、結果がNULLかどうかの確認から、例外ハンドラに変更されたことに注意してください。
|
これまでに問合せをXMLに変換する方法を見てきました。ここではXSUを使用して、表またはビューにXMLを戻す方法を示します。oracle.xml.sql.dml.OracleXMLSaveクラスがこの機能を提供します。このクラスにはXMLを表に挿入して、既存の表をXML文書で更新し、XML要素値に基づいて表から行を削除するメソッドがあります。
どのような場合でも、指定したXML文書が解析され、要素を確認してターゲット表またはビューの列名にタグ名を一致させるようにします。要素はSQL型に変換され、適切な文にバインドされます。図7-6に、XSUを使用してXMLを格納するプロセスを示します。
ROW要素のリストを含むXML文書について見てみます。それぞれのROW要素が個別のDML操作(表またはビューに対するINSERT、UPDATEまたはDELETE)を構成します。
表またはビューに文書を挿入するには、表名またはビュー名と文書を指定します。XSUは文書(文字列が指定されている場合)を解析し、INSERT文を作成してこの文にすべての値をバインドします。デフォルトでは、XSUは値を表またはビューのすべての列に値を挿入します。存在しない要素はNULL値として処理されます。次の例では、employees表から生成したXML文書を比較的簡単に表に格納する方法を示します。
この例では、すべての列にXML値を挿入します。
// This program takes as an argument the file name, or a url to
// a properly formated XML document and inserts it into the HR.EMPLOYEES table.
import java.sql.*;
import oracle.xml.sql.dml.OracleXMLSave;
public class testInsert
{
public static void main(String argv[])
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@","hr","hr");
OracleXMLSave sav = new OracleXMLSave(conn, "employees");
sav.insertXML(sav.getURL(argv[0]));
sav.close();
}
}
次の形式のINSERT文が生成され、
INSERT INTO hr.employees (employee_id, last_name, job_id, manager_id,
hire_date, salary, department_id) VALUES(?,?,?,?,?,?,?);
列名と一致している入力XML文書内の要素タグが照合され、その値がバインドされます。
次のXML文書をファイルに格納し、
<?xml version='1.0'?>
<ROWSET>
<ROW num="1">
<EMPLOYEE_ID>7369</EMPLOYEE_ID>
<LAST_NAME>Smith</LAST_NAME>
<JOB_ID>CLERK</JOB_ID>
<MANAGER_ID>7902</MANAGER_ID>
<HIRE_DATE>12/17/1980 0:0:0</HIRE_DATE>
<SALARY>800</SALARY>
<DEPARTMENT_ID>20</DEPARTMENT_ID>
</ROW>
<!-- additional rows ... -->
</ROWSET>
そのファイルを前述のプログラムに指定すると、指定した値に対し、7369, Smith, CLERK, 7902, 12/17/1980,800,20の値を含むemployees表に新しい行が生成されます。行要素内に存在しない要素は、NULL値として扱われます。
すべての列に値を挿入する必要がない場合もあります。取得する値のグループが完全なセットではなく、残りの列にトリガーまたはデフォルト値を使用する必要がある場合が当てはまります。次のコードに、この実行方法を示します。
従業員番号、名前、仕事の値のみを取得して、給与、管理者、部署番号、入社日の各フィールドには自動的に値が入力されると想定します。最初にINSERT文を実行する列名のリストを作成して、そのリストをOracleXMLSaveインスタンスに渡します。
import java.sql.*;
import oracle.xml.sql.dml.OracleXMLSave;
public class testInsert
{
public static void main(String argv[])
throws SQLException
{
Connection conn = getConnection("hr","hr");
OracleXMLSave sav = new OracleXMLSave(conn, "hr.employees");
String [] colNames = new String[3];
colNames[0] = "EMPLOYEE_ID";
colNames[1] = "LAST_NAME";
colNames[2] = "JOB_ID";
sav.setUpdateColumnList(colNames); // set the columns to update..!
// Assume that the user passes in this document as the first argument!
sav.insertXML(sav.getURL(argv[0]));
sav.close();
}
// Get the connection given the user name and password..!
private static Connection getConnection(String user, String passwd)
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",user,passwd);
return conn;
}
}
INSERT文が生成されます。
INSERT INTO hr.employees (employee_id, last_name, job_id) VALUES (?, ?, ?);
前述の例では、挿入した文書に他の列の値(HIRE_DATEなど)が含まれていても、それらの値は無視されます。また、挿入操作は、入力に存在する各ROW要素に対して実行されます。これらの挿入はデフォルトでバッチされます。
XML文書から表への値の挿入方法を理解したところで、特定の値のみを更新する方法を見ていきます。XML文書では、従業員の給与と配属部署を更新する場合、次のようになります。
<ROWSET>
<ROW num="1">
<EMPLOYEE_ID>7369</EMPLOYEE_ID>
<SALARY>1800</SALARY>
<DEPARTMENT_ID>30</DEPARTMENT_ID>
</ROW>
<ROW>
<EMPLOYEE_ID>2290</EMPLOYEE_ID>
<SALARY>2000</SALARY>
<HIRE_DATE>12/31/1992</HIRE_DATE>
<!-- additional rows ... -->
</ROWSET>
XSUを使用して値を更新できます。更新の場合は、キー列名のリストでXSUを指定する必要があります。これらの列は、UPDATE文のWHERE句で構成されます。以前に示したemployees表では、従業員番号(employee_id)列がキーを構成します。このキーを使用して、更新を行います。
この例では、keyColumnsを使用してtableおよびempを更新します。
import java.sql.*;
import oracle.xml.sql.dml.OracleXMLSave;
public class testUpdate
{
public static void main(String argv[])
throws SQLException
{
Connection conn = getConnection("hr","hr");
OracleXMLSave sav = new OracleXMLSave(conn, "hr.employees");
String [] keyColNames = new String[1];
keyColNames[0] = "EMPLOYEE_ID";
sav.setKeyColumnList(keyColNames);
// Assume that the user passes in this document as the first argument!
sav.updateXML(sav.getURL(argv[0]));
sav.close();
}
// Get the connection given the user name and password..!
private static Connection getConnection(String user, String passwd)
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",user,passwd);
return conn;
}
}
この例では、2つのUPDATE文が生成されます。最初のROW要素には、UPDATE文が生成され、SALARYフィールドとHIRE_DATEフィールドが次のように更新されます。
UPDATE hr.employees SET salary = 2000 AND hire_date = 12/31/1992 WHERE employee_id = 2290;
2番目のrow要素の場合、次の文が生成されます。
UPDATE hr.employees SET salary = 2000 AND hire_date = 12/31/1992 WHERE employee_id = 2290;
更新する列のリストを指定できます。すべてのROW要素に同じUPDATE文を使用できるため、列リストを指定すると処理速度が向上します。また、XML文書内にある他のタグを無視できます。
|
注意: 更新する列のリストを指定すると、更新する列に対応する要素が存在しない場合は、その要素がNULLとして処理されます。
|
更新するすべての要素がXML文書内のすべてのROW要素と同じであることわかっていれば、setUpdateColumnNames()ファンクションを使用して、更新する列のリストを設定できます。
import java.sql.*;
import oracle.xml.sql.dml.OracleXMLSave;
public class testUpdate
{
public static void main(String argv[])
throws SQLException
{
Connection conn = getConnection("hr","hr");
OracleXMLSave sav = new OracleXMLSave(conn, "hr.employees");
String [] keyColNames = new String[1];
keyColNames[0] = "EMPLOYEE_ID";
sav.setKeyColumnList(keyColNames);
// you create the list of columns to update..!
// Note that if you do not supply this, then for each ROW element in the
// XML document, you would generate a new update statement to update all
// the tag values (other than the key columns)present in that element.
String[] updateColNames = new String[2];
updateColNames[0] = "SALARY";
updateColNames[1] = "JOB_ID";
sav.setUpdateColumnList(updateColNames); // set the columns to update..!
// Assume that the user passes in this document as the first argument!
sav.updateXML(sav.getURL(argv[0]));
sav.close();
}
// Get the connection given the user name and password..!
private static Connection getConnection(String user, String passwd)
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",user,passwd);
return conn;
}
}
XML文書からの削除の場合は、キー列のリストを指定できます。これらの列は、DELETE文のWHERE句で使用されます。キー列名を指定しない場合、新しいDELETE文がXML文書のROW要素ごとに作成されます。DELETE文のWHERE句の列のリストは、ROW要素の列と一致します。
この削除の例を見てみます。
import java.sql.*;
import oracle.xml.sql.dml.OracleXMLSave;
public class testDelete
{
public static void main(String argv[])
throws SQLException
{
Connection conn = getConnection("hr","hr");
OracleXMLSave sav = new OracleXMLSave(conn, "hr.employees");
// Assume that the user passes in this document as the first argument!
sav.deleteXML(sav.getURL(argv[0]));
sav.close();
}
// Get the connection given the user name and password..!
private static Connection getConnection(String user, String passwd)
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",user,passwd);
return conn;
}
}
以前に示した更新の例と同じXML文書を使用して、2つのDELETE文を取得します。
DELETE FROM hr.employees WHERE employee_id=7369 AND salary=1800 AND department_id=30; DELETE FROM hr.employees WHERE employee_id=2200 AND salary=2000 AND hire_date=12/31/1992;
XML文書内の各ROW要素にあるタグ名に基づいてDELETE文が形成されました。
かわりにDELETE文の条件としてキー値のみを使用する場合は、setKeyColumnファンクションを使用して設定できます。
import java.sql.*;
import oracle.xml.sql.dml.OracleXMLSave;
public class testDelete
{
public static void main(String argv[])
throws SQLException
{
Connection conn = getConnection("hr","hr");
OracleXMLSave sav = new OracleXMLSave(conn, "hr.employees");
String [] keyColNames = new String[1];
keyColNames[0] = "EMPLOYEE_ID";
sav.setKeyColumnList(keyColNames);
// Assume that the user passes in this document as the first argument!
sav.deleteXML(sav.getURL(argv[0]));
sav.close();
}
// Get the connection given the user name and password..!
private static Connection getConnection(String user, String passwd)
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",user,passwd);
return conn;
}
}
次に、生成された単一のDELETE文を示します。
DELETE FROM hr.employees WHERE employee_id=?
次に、XSUの追加情報を示します。
次に例外の処理について説明します。
XSUは、処理中に発生したすべての例外を捕捉し、ランタイム例外であるoracle.xml.sql.OracleXMLSQLExceptionを発生させます。プログラムがこの例外を捕捉して適切な処置を実行できる場合、コールするプログラムはこの例外を捕捉する必要はありません。例外クラスには、エラー・メッセージおよび存在する場合は親である例外も取得するための関数があります。たとえば、後ほど示すプログラムでは、ランタイム例外を捕捉してから親である例外を取得します。
この例外は、setRaiseNoRowsExceptionが生成中にOracleXMLQueryクラスに設定されると生成されます。これはOracleXMLSQLExceptionクラスのサブクラスで、生成中に行処理を終了するインジケータとして使用できます。
import java.sql.*;
import oracle.xml.sql.query.OracleXMLQuery;
public class testException
{
public static void main(String argv[])
throws SQLException
{
Connection conn = getConnection("hr","hr");
// wrong query this will generate an exception
OracleXMLQuery qry = new OracleXMLQuery(conn, "select * from employees
where sd = 322323");
qry.setRaiseException(true); // ask it to raise exceptions..!
try{
String str = qry.getXMLString();
}catch(oracle.xml.sql.OracleXMLSQLException e)
{
// Get the original exception
Exception parent = e.getParentException();
if (parent instanceof java.sql.SQLException)
{
// perform some other stuff. Here you simply print it out..
System.out.println(" Caught SQL Exception:"+parent.getMessage());
}
else
System.out.println(" Exception caught..!"+e.getMessage());
}
}
// Get the connection given the user name and password..!
private static Connection getConnection(String user, String passwd)
throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:oci:@",user,passwd);
return conn;
}
}
この項では、XSUのヒントを示します。
customer.xmlファイルに次のXMLがある場合:
<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>
XSUでこのXMLを格納するためにはどのようなデータベース・スキーマ構造を使用できるでしょうか。
この例は複数のレベルの深さ(ネストした構造)であるため、オブジェクト・リレーショナル・スキーマを使用できます。前述のXMLは、このようなスキーマに正規マッピングされます。適切なデータベース・スキーマは次のとおりです。
CREATE TYPE address_type AS OBJECT ( street VARCHAR2(40), city VARCHAR2(20), state VARCHAR2(10), zip VARCHAR2(10) ); / CREATE TYPE customer_type AS OBJECT ( customerid NUMBER(10), firstname VARCHAR2(20), lastname VARCHAR2(20), homeaddress address_type ); / CREATE TABLE customer_tab ( customer customer_type);
XSUを使用してリレーショナル・スキーマにcustomer.xmlをロードする場合、リレーショナル・スキーマの最上位にビューのオブジェクトを作成することによりロードを実行できます。
たとえば、次のすべての情報を含むリレーショナル表があるとします。
CREATE TABLE 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;
最後に、XSLTを使用してXMLをフラット化し、このXMLをリレーショナル・スキーマに直接挿入できます。ただし、この方法は、あまりお薦めできません。
現在XML SQL Utility(XSU)は単一の表にのみデータを格納できます。任意の表またはビューにXML文書の正規の表示をマップします。ただし、XSUを使用して表にまたがってXMLを格納する方法があります。これはXSLTを使用して任意の文書を複数の文書に変換し、これらの文書を別々に挿入することで実行できます。また、(必要に応じてオブジェクト・ビューを使用して)複数の表にまたがるビューを定義してから、ビューに挿入する方法もあります。このビューが更新不可能(複雑な結合などのために)な場合は、ビューにまたがってIINSTEAD OFトリガーを使用して、挿入を実行できます。
XSLTを使用してXML文書を変換する必要があります。つまり、属性を要素に変更する必要があります。XSUがXMLからデータベース・スキーマに正規マッピングすることが前提です。これはやや柔軟性に欠けるため、XSLTを使用することになりますが、その反面、一般的にはマッピングを指定する負担がありません。
DTDには多くの短所があるため、データベース・スキーマを生成できません。XML SchemaのW3C勧告は確定していますが、XSUではまだこの機能を使用できません。
次に、JDBCシン・ドライバ接続文字列の例を示します。
jdbc:oracle:thin:user/password@hostname:portnumber:DBSID;
さらに、データベースにはアクティブなTCP/IPリスナーが必要です。有効なOCI接続文字列は次のとおりです。
jdbc:oracle:oci:user/password@hostname
XML SQL Utilityは挿入、削除または更新後にコミットしますか。エラーが発生した場合はどうなりますか。
デフォルトでは、XSUは一度に多くのINSERT文、DELETE文またはUPDATE文を実行します。バッチ処理で同時に実行される文の数は、setBatchSize機能でオーバーライドできます。
また、デフォルトでは、XSUは明示的なコミットを行いません。AUTOCOMMITが、JDBC接続のデフォルトであるオンになっている場合、文の各バッチを実行した後、コミットが実行されます。AUTOCOMMITをオフにし、setCommitBatch機能を使用して、コミット前に実行する文の数を指定することで、この動作をオーバーライドできます。
エラーが発生した場合は、XSUへの特定のコール前のターゲット表の状態、またはXSUへの現在のコール中に行われた前回のコミット直後の状態にロールバックします。
XSUリリース2.1.0から、特定の列または列のグループをXML要素ではなくXML属性にマップできるようになりました。これを達成するには、列名に別名を作成し、この別名の前にアットマーク(@)を付加します。次に例を示します。
* Create a file called select.sql with the following content :
SELECT empno "@EMPNO", ename, job, hiredate
FROM emp
ORDER BY empno
* Call the XML SQL Utility :
java OracleXML getXML -user "scott/tiger" \
-conn "jdbc:oracle:thin:@myhost:1521:ORCL" \
-fileName "select.sql"
* As a result, the XML document will look like :
<?xml version = '1.0'?>
<ROWSET>
<ROW num="1" EMPNO="7369">
<ENAME>SMITH</ENAME>
<JOB>CLERK</JOB>
<HIREDATE>12/17/1980 0:0:0</HIREDATE>
</ROW>
<ROW num="2" EMPNO="7499">
<ENAME>ALLEN</ENAME>
<JOB>SALESMAN</JOB>
<HIREDATE>2/20/1981 0:0:0</HIREDATE>
</ROW>
</ROWSET>
|
注意: すべてのXML属性の列を先にマップする必要があります。 |
XML文書はストリーム形式で作成されているため、次の問合せの場合、
SELECT ename, empno "@EMPNO", ...
予期した結果は生成されません。現時点で、属性に格納されたXMLデータをロードすることはできません。XSLT変換を使用して属性を要素に変更する必要があります。XSUがXMLからデータベース・スキーマに正規マッピングすることが前提です。