この章では、Oracle XML DBの使用方法の概要を説明します。この章の例では、発注書のXMLコンテンツへのアクセスおよび管理の方法を示します。発注書は高度に構造化されたXML文書であるため、XML発注書の形式およびデータはOracle XML DBの記憶域および処理方法に適しています。ただし、ここで説明する方法の多くは、非構造化データや半構造化データなど他のタイプのXML文書を管理する際にも使用できます。この章では、第1章「Oracle XML DBの概要」で紹介したOracle XML DBの概念についても詳しく説明します。
この章の内容は次のとおりです。
Oracle XML DBが導入される前は、次の2つの方法でXMLコンテンツをOracle Databaseに格納していました。
Oracle XML Developer's Kit(XDK)を使用してXML文書をOracle Database外部で解析し、抽出したXMLデータをデータベース内の1つ以上の表に行として格納します。
キャラクタ・ラージ・オブジェクト(CLOB)、バイナリ・ラージ・オブジェクト(BLOB)、バイナリ・ファイル(BFILE)またはVARCHAR列を使用して、XML文書をOracle Databaseに格納します。
いずれの場合も、Oracle DatabaseはXMLコンテンツを管理していることを認識しません。
Oracle XML DBおよびXMLTypeデータ型の導入によって、XMLコンテンツをデータベースに永続的かつ簡単に格納する方法が新たに提供されました。この方法には、XML文書をXMLType列または表、あるいはOracle XML DBリポジトリに格納する方法が含まれます。XMLをXMLType列または表として格納すると、Oracle DatabaseはコンテンツがXMLであることを認識します。これによって、データベースで次の処理が可能になります。
XMLコンテンツに対してXML固有の検証、操作および最適化を実行できます。
Oracle XML DBによるXMLコンテンツの効率的な処理を容易にします。
Oracle9i リリース1(9.0.1)では、新しいXMLTypeデータ型が導入され、データベース内のXMLデータのネイティブな処理が簡単になりました。
XMLTypeはデータベース内のXML文書を表すことができるため、SQLでのアクセスが可能です。
XMLTypeには、XMLコンテンツを操作する組込みメソッドが含まれています。たとえば、XMLTypeメソッドを使用して、Oracle Databaseに格納されたXMLデータの作成、抽出および索引付けを行うことができます。
XMLTypeの機能は、PL/SQLおよびJavaで提供される一連のApplication Program Interface(API)を介して使用することもできます。
XMLTypeは、PL/SQLストアド・プロシージャのパラメータ、戻り値および変数に使用できます。
XMLTypeを使用すると、SQL開発者は、XMLでの作業中にリレーショナル・データベースの機能を使用できます。XML開発者は、リレーショナル・データベースでの作業中にXML標準の機能を使用できます。
XMLTypeは、表の列およびビューのデータ型として使用できます。XMLType変数は、PL/SQLストアド・プロシージャのパラメータおよび戻り値として使用できます。また、XMLTypeは、SQL、PL/SQL、C、Java(JDBCを介して)およびOracle Data Provider for .NET(ODP.NET)でも使用できます。
XMLType APIによって、XMLコンテンツを操作する多くの有効なメソッドが提供されています。たとえば、メソッドextract()は、XMLTypeインスタンスから1つ以上のノードを抽出します。これらのXMLTypeメソッドの多くは、SQL関数としても提供されています。たとえば、SQL関数extractはXMLTypeメソッドextract()に相当します。
Oracle XML DBの機能は、関連するXML標準(XML Parser、XML DOM、XML Schema Validatorなど)のOracle XML Developer's KitのC実装に基づいています。
XMLTypeデータ型およびApplication Program Interface(API)は、XMLコンテンツに対するSQL操作およびSQLコンテンツに対するXML操作を可能にします。
汎用API: XMLTypeには、組込み関数、索引付けおよびナビゲーション・サポートが含まれるアプリケーション開発用の汎用APIが備わっています。
XMLTypeおよびSQL: XMLTypeは、SQL文で他のデータ型と組み合せて使用できます。たとえば、XMLType列を問い合せ、抽出の結果をリレーショナル列と結合できます。Oracle Databaseでは、このような問合せを実行するための最適な方法を判断します。
索引付け: 複数の種類の索引を作成して、XMLデータに対する問合せのパフォーマンスを向上できます。
XMLTypeデータの構造化記憶域の場合は、XMLType表および列の基礎となるBツリー索引をオブジェクト・リレーショナル表に作成できます。
XMLTypeデータの非構造化およびバイナリXML記憶域の場合は、XMLIndex索引を作成できます。これは、ドキュメントのXML構造を対象とした索引です。
XPath式に基づくファンクション索引を作成できます。これはすべてのXMLType記憶域モデルに適用されます。
XMLデータのテキスト・コンテンツの索引は、Oracle TextのCONTEXT索引を使用して作成でき、全文検索で使用できます。これはすべてのXMLType記憶域モデルに適用されます。
XMLTypeは、データベースをXMLデータの永続記憶域として使用する場合に使用します。XMLTypeには、次のような機能があります。
XML文書の一部または全体のSQL問合せ: SQL関数existsNodeおよびextractを使用すると、XML文書に必要なSQL問合せ関数を実行できます。
SQL関数existsNodeおよびextractを使用したXPathアクセス: XMLTypeは、組込みのC言語で書かれたXMLパーサーとプロセッサを使用するため、サーバー内部で使用される場合にはパフォーマンスおよび拡張性が向上します。
SQL文およびPL/SQL関数での厳密な型指定: XMLTypeを使用した厳密な型指定によって、渡される値が常にXML値であり、任意のテキスト文字列ではないことが保証されます。
XPath文書問合せの索引付け: XMLTypeには、検索を最適化するファンクション索引を作成するために使用できるメソッドがあります。
記憶域モデルとアプリケーションの分離: CLOB、オブジェクト・リレーショナルまたはバイナリXML記憶域を直接使用するかわりにXMLTypeを使用すると、アプリケーションでの問合せまたはDML文に影響することなく、後でアプリケーションが様々な代替の記憶域に効率的に移行できます。
将来的な最適化のサポート: XMLの新機能は、XMLTypeをサポートします。Oracle Databaseは、XMLTypeでXMLデータを格納できることをネイティブに認識するため、効率的な最適化および索引付けの方法を実現できます。XMLTypeを使用するアプリケーションを作成することによって、アプリケーションの再作成なしに、これらの最適化および拡張を将来のリリースで簡単に実現および保持できます。
次に、Oracle DatabaseでXMLコンテンツを管理するために、XMLType列および表を作成する例を示します。
XMLデータには独自の構造がありますが、XMLTypeのオブジェクト・リレーショナル記憶域を除き、データベース構造には直接反映されません。つまり、個別のXML要素および属性がデータベースの個別の列や表にマップされることはありません。
これは、個別の要素や属性の値に応じてXMLデータを制約する場合、リレーショナル・データに対する標準的な手法を適用できないことを意味します。このため、対象のXMLデータを表す仮想列を作成してから、その仮想列を使用して必要な制約を定義する必要があります。
この手法は、バイナリXML形式で格納されているXMLデータにのみ適用されます。未構造化記憶域を使用するXMLデータの場合、データベースはXML構造を認識せず、データは構造のないテキストとして処理されます。しかしバイナリXML記憶域の場合は、構造が認識されます。この構造に関する認識を利用して仮想列を作成すると、データベースはそれを制約の場合に使用することができます。
手順は次のとおりです。
対象のXMLデータに対応する仮想列を定義します。
その列を使用してXMLTypeデータを一括して制約します。
XMLTypeデータに対する仮想列の作成は、他の型のデータを使用した仮想列の作成と同様ですが、構文が多少異なります。特に、列定義に関連付けて制約を指定することができません。
XMLTypeは抽象データ型なので、XMLType表に対する仮想列を作成する場合、その列は非表示になり、DESCRIBE文などに表示されません。これにより、DESCRIBEなどの操作を使用するツールが、仮想列に惑わされずに正常に機能することができます。XMLType列を持つ表に仮想列を作成する場合、仮想列は仮想列でないすべての列とともに、DESCRIBE操作によりリストされます。
XML要素または属性に基づく仮想列を作成するには、その要素や属性を含むSQL式によってXML要素または属性を定義します。つまり、ファンクションに基づく列を作成します。ファンクションとしてはSQL関数extractValueを使用できます。
XMLコンテンツは、次の方法を使用してOracle XML DBにロードできます。
表ベースのロード:
パスベースのリポジトリのロード方法:
SQLまたはPL/SQLの簡単なINSERT操作を使用して、XML文書をデータベースにロードできます。文書は、XMLType列または表として格納する前に、XMLTypeコンストラクタの1つを使用してXMLTypeインスタンスに変換する必要があります。
|
関連項目:
|
XMLTypeコンストラクタを使用すると、VARCHAR、CLOBおよびBFILE値を含む様々なソースからXMLTypeインスタンスを作成できます。このコンストラクタは、XMLTypeの作成に関連する処理量を減らす追加の引数を受け入れます。たとえば、ソースのXML文書が有効だとわかっている場合には、有効かどうかわからない場合に実行される型チェックを無効にする引数をコンストラクタに指定できます。
さらに、ソース・データがデータベース・キャラクタ・セットでエンコードされていない場合、XMLTypeインスタンスはBFILE値またはBLOB値を使用して構成できます。ソース・データのエンコーディングは、コンストラクタのキャラクタ・セットID(csid)引数で指定されます。
必要なディレクトリを指すSQLディレクトリの作成
例3-3に、XMLコンテンツをXMLType表に挿入する方法を示します。この挿入を行う前に、処理するファイルが含まれたディレクトリを指すSQLディレクトリ・オブジェクトを作成する必要があります。作成するためには、CREATE ANY DIRECTORY権限が必要です。
|
関連項目: 『Oracle Database SQL言語リファレンス』の第18章のGRANTに関する項 |
CREATE DIRECTORY xmldir AS path_to_folder_containing_XML_file;
例3-4 Javaを使用したXMLType表へのXMLコンテンツの挿入
この例は、ドキュメント・オブジェクト・モデル(DOM)を指定して最初にJavaでXMLTypeインスタンスを作成することによって、XMLコンテンツをOracle XML DBにロードする方法を示しています。
public void doInsert(Connection conn, Document doc)
throws Exception
{
String SQLTEXT = "INSERT INTO purchaseorder VALUES (?)";
XMLType xml = null;
xml = XMLType.createXML(conn,doc);
OraclePreparedStatement sqlStatement = null;
sqlStatement = (OraclePreparedStatement) conn.prepareStatement(SQLTEXT);
sqlStatement.setObject(1,xml);
sqlStatement.execute();
}
1 row selected.
http://www.oracle.com/technology/sample_code/tech/xml/xmldb/content.htmlのOracle Technology Network(OTN)サイトで入手可能なSimple Bulk Loader Applicationには、Java Database Connectivity(JDBC)を使用してXMLファイルのディレクトリをOracle XML DBにロードする方法が示されています。JDBCは、Oracle Databaseに対する一連のJavaインタフェースです。
例3-5に、DOMを指定してXMLTypeインスタンスを作成することによって、CでXMLコンテンツをXMLType表に挿入する方法を示します。
例3-5 Cを使用したXMLType表へのXMLコンテンツの挿入
#include "stdio.h" #include <xml.h> #include <stdlib.h> #include <string.h> #include <ocixmldb.h> OCIEnv *envhp; OCIError *errhp; OCISvcCtx *svchp; OCIStmt *stmthp; OCIServer *srvhp; OCIDuration dur; OCISession *sesshp; oratext *username = "QUINE"; oratext *password = "************"; /* Replace with the real password. */ oratext *filename = "AMCEWEN-20021009123336171PDT.xml"; oratext *schemaloc = "http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd"; /*--------------------------------------------------------*/ /* Execute a SQL statement that binds XML data */ /*--------------------------------------------------------*/ sword exec_bind_xml(OCISvcCtx *svchp, OCIError *errhp, OCIStmt *stmthp, void *xml, OCIType *xmltdo, OraText *sqlstmt) { OCIBind *bndhp1 = (OCIBind *) 0; sword status = 0; OCIInd ind = OCI_IND_NOTNULL; OCIInd *indp = &ind; if(status = OCIStmtPrepare(stmthp, errhp, (OraText *)sqlstmt, (ub4)strlen((const 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; } /*--------------------------------------------------------*/ /* Initialize OCI handles, and connect */ /*--------------------------------------------------------*/ sword init_oci_connect() { . . . } /*--------------------------------------------------------*/ /* Free OCI handles, and disconnect */ /*--------------------------------------------------------*/ void free_oci() { . . . } void main() { OCIType *xmltdo; xmldocnode *doc; ocixmldbparam params[1]; xmlerr err; xmlctx *xctx; oratext *ins_stmt; sword status; xmlnode *root; oratext buf[10000]; /* Initialize envhp, svchp, errhp, dur, stmthp */ init_oci_connect(); /* Get an XML context */ params[0].name_ocixmldbparam = XCTXINIT_OCIDUR; params[0].value_ocixmldbparam = &dur; xctx = OCIXmlDbInitXmlCtx(envhp, svchp, errhp, params, 1); if (!(doc = XmlLoadDom(xctx, &err, "file", filename, "schema_location", schemaloc, NULL))) { printf("Parse failed.\n"); return; } else printf("Parse succeeded.\n"); root = XmlDomGetDocElem(xctx, doc); printf("The xml document is :\n"); XmlSaveDom(xctx, &err, (xmlnode *)doc, "buffer", buf, "buffer_length", 10000, NULL); printf("%s\n", buf); /* Insert the document into my_table */ ins_stmt = (oratext *)"insert into purchaseorder values (:1)"; status = OCITypeByName(envhp, errhp, svchp, (const text *) "SYS", (ub4) strlen((const char *)"SYS"), (const text *) "XMLTYPE", (ub4) strlen((const char *)"XMLTYPE"), (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, (OCIType **) &xmltdo); if (status == OCI_SUCCESS) { status = exec_bind_xml(svchp, errhp, stmthp, (void *)doc, xmltdo, ins_stmt); } if (status == OCI_SUCCESS) printf ("Insert successful\n"); else printf ("Insert failed\n"); /* Free XML instances */ if (doc) XmlFreeDocument((xmlctx *)xctx, (xmldocnode *)doc); /* Free XML CTX */ OCIXmlDbFreeXmlCtx(xctx); free_oci(); }
|
注意: この機能を簡単に説明するために、この例では、デプロイされたシステムで通常使用されるパスワード管理手法を実行していません。本番環境では、Oracle Databaseパスワード管理のガイドラインに従い、サンプル・アカウントをすべて無効化してください。パスワード管理のガイドラインおよびセキュリティに関するその他の推奨事項は、『Oracle Databaseセキュリティ・ガイド』を参照してください。 |
小規模なXML文書のコレクションで構成された大規模なXMLファイルをロードするときは、Simple API for XML(SAX)の解析機能を使用してファイルを一連の小規模な文書に分割してから文書を挿入すると、効率的にロードできます。SAXは、XML Parserがイベント・ベース・アプリケーション用に提供するXML標準インタフェースです。
SAXを使用して、ノードのコレクションから各文書を作成することによって、30MB以上の大規模なXMLファイルからデータベース表をロードできます。XMLファイルは、バルク・ロードすることもできます。
|
関連項目: この方法の例は、http://www.oracle.com/technology/sample_code/tech/xml/xmldb/content.htmlの「SAX Loader Application」を参照してください。 |
大量のXMLデータをOracle Databaseにロードするには、SQL*Loaderを使用します。SQL*Loaderは、従来型パスまたはダイレクト・パスのいずれかのモードでロードを実行します。表3-1に、2つのモードの比較を示します。
表3-1 SQL*Loaderの従来型パスおよびダイレクト・パスによるロード・モード
| 従来型パスによるロード・モード | ダイレクト・パスによるロード・モード |
|---|---|
|
SQLを使用してデータをOracle Databaseにロードします。これがデフォルトのモードです。 |
SQLをバイパスして、データを直接Oracle Databaseにロードします。 |
|
メリット: SQLセマンティクスに従います。たとえば、トリガーが起動され、制約がチェックされます。 |
メリット: 従来型パスによるロード・モードより高速にデータをロードできます。 |
|
デメリット: ダイレクト・パスによるロード・モードよりデータのロードが遅くなります。 |
デメリット: SQLセマンティクスに従いません。たとえば、トリガーは起動されず、制約もチェックされません。 |
SQL*Loaderのダイレクト・パス・モードでLOBをロードすると、多くのメモリーを使用できます。メッセージSQL*Loader 700 (out of memory)が表示された場合は、オペレーティング・システムおよびプロセス・メモリーで処理できる行より多くの行が各ロード・コールでバッチ処理されている可能性があります。これに対する回避策は、ROWSオプションを使用して、各データ保存で読み取られる行数を少なくすることです。
XML文書をOracle XML DBリポジトリに格納して、表ベースではなくパスベースの方法でその文書にアクセスすることも可能です。指定のパスのリポジトリにXML文書をロードするには、PL/SQLパッケージDBMS_XDBを使用します。この例を次に示します。
例3-6 PL/SQL DBMS_XDBを使用したリポジトリへのXMLコンテンツの挿入
DECLARE
res BOOLEAN;
BEGIN
res := DBMS_XDB.createResource('/home/QUINE/purchaseOrder.xml',
bfilename('XMLDIR', 'purchaseOrder.xml'),
nls_charset_id('AL32UTF8'));
END;/
Oracle XML DBを構成して使用するための多くの操作は、1つ以上のXML文書の処理に基づいています。たとえば、XML Schemaの登録や、XSL変換の実行などです。これらのXML文書をOracle Databaseで使用可能にする最も簡単な方法は、そのXML文書をOracle XML DBリポジトリにロードすることです。
Windows ExplorerなどWebDAVをサポートするツールからWebDAVプロトコルなどのプロトコルを使用して、ローカル・ファイル・システムからOracle XML DBリポジトリにXML文書をロードできます。図3-1に、SCOTTフォルダのコンテンツをローカル・ハード・ドライブからOracle XML DBリポジトリ内のフォルダpoSourceにコピーする簡単なドラッグ・アンド・ドロップ操作を示します。
コピーされたフォルダには、XML Schema文書、HTMLページおよびいくつかのXSLTスタイルシートが含まれていることがあります。
|
注意: Oracle XML DBリポジトリには、XML文書(XML Schemaに基づくXML文書およびXML Schemaに基づかないXML文書)と同様に、HTMLファイル、JPEGイメージ、Word文書など、XMLデータではないコンテンツも格納できます。 |
この項では、XML文書のキャラクタ・セットがどのように決定されるかを説明します。
|
注意: AL32UTF8は、XMLTypeデータに適切なOracle Databaseキャラクタ・セットです。これはIANAの登録済標準であるUTF-8エンコーディングと同等であり、すべての有効なXML文字をサポートします。
Oracle Databaseのデータベース・キャラクタ・セットUTF8(ハイフンなし)と、データベース・キャラクタ・セットAL32UTF8またはキャラクタ・エンコーディングUTF-8を混同しないでください。AL32UTF8は、データベース・キャラクタ・セットUTF8に置き換わったものです。XMLデータに対してUTF8を使用しないでください。UTF8でサポートされるのはUnicodeバージョン3.1以下のみで、すべての有効なXML文字がサポートされるわけではありません。AL32UTF8には、そのような制限はありません。 XMLデータにUTF8データベース・キャラクタ・セットを使用すると、システムが停止したり、セキュリティに悪影響を与えたりする場合があります。入力した文書要素の名前にデータベース・キャラクタ・セットでサポートされない文字が含まれている場合、その文字のかわりに置換文字(通常は「 |
各XML文書は、エンティティと呼ばれる単位で構成されます。XML文書内の各エンティティでは、異なるエンコーディングの文字が使用される場合があります。UTF-8またはUTF-16以外のエンコーディングで格納されるエンティティは、使用する文字コードを示すエンコーディング仕様が含まれたXML宣言で始まる必要があります。次に例を示します。
<?xml version='1.0' encoding='EUC-JP' ?>
UTF-16でエンコードされたエンティティは、「XML 1.0 Reference」の付録Fで説明されているバイト・オーダー・マーク(BOM)で始まる必要があります。たとえば、大規模なendianのプラットフォームで、UTF-16データ・ストリームに必要なBOMは#xFEFFです。
エンコーディング宣言およびBOMの両方が存在しない場合、XMLエンティティはUTF-8でエンコードされていると想定されます。ASCIIはUTF-8のサブセットであるため、ASCIIエンティティではエンコーディング宣言は必要ありません。
多くの場合、使用する文字コードの情報は、XMLデータ以外に外部ソースからも取得できます。たとえば、データのエンコーディングは、次に示すように、HTTP(S)リクエストのContent-Typeフィールドのcharsetパラメータから取得できます。
Content-Type: text/xml; charset=ISO-8859-4
Oracle Database 10gリリース1より前のリリースでは、すべてのXML文書は、文書のエンコーディング宣言に関係なく、データベース・キャラクタ・セットでエンコードされていると想定されていました。Oracle Database 10gリリース1では、文書をデータベースにロードするときに、その文書のエンコーディングがエンコーディング宣言から検出されます。
ただし、XMLデータがCLOB値またはVARCHAR値から取得される場合、エンコーディング宣言は無視されます。これは、これら2つのデータ型は常にデータベース・キャラクタ・セットでエンコードされているためです。
さらに、プログラムAPIまたは転送プロトコルのいずれかを介してデータをOracle XML DBにロードするときは、外部エンコーディングを指定して文書のエンコーディング宣言をオーバーライドできます。XML Schemaに基づくXML文書に指定のエンコーディングに対して不適切な文字が含まれている場合、その文書をロードしようとするとエラーが発生します。
次の各例で、外部エンコーディングを指定するいくつかの方法を示します。
PL/SQL関数DBMS_XDB.CreateResourceを使用してBFILEからリソースを作成する場合は、CSID引数を使用してファイル・エンコーディングを指定できます。CSIDに0(ゼロ)を指定すると、ファイル・エンコーディングは文書のエンコーディング宣言から自動的に検出されます。
CREATE DIRECTORY xmldir AS '/private/xmldir';
CREATE OR REPLACE PROCEDURE loadXML(filename VARCHAR2, file_csid NUMBER) IS
xbfile BFILE;
RET BOOLEAN;
BEGIN
xbfile := bfilename('XMLDIR', filename);
ret := DBMS_XDB.createResource('/public/mypurchaseorder.xml',
xbfile,
file_csid);
END;/
FTPプロトコルを使用して、文書をOracle XML DBにロードします。quote set_charset FTPコマンドを使用して、ロードするファイルのエンコーディングを指定します。
ftp> quote set_charset Shift_JIS ftp> put mypurchaseorder.xml
HTTP(S)プロトコルを使用して、文書をOracle XML DBにロードします。Oracle XML DBに転送するデータのエンコーディングは、リクエスト・ヘッダー内に指定します。
Content-Type: text/xml; charset= EUC-JP
Oracle XML DBに格納されたXML文書は、SQLクライアント、プログラムAPIまたは転送プロトコルを使用して取り出すことができます。取り出すデータのエンコーディングを指定できます(ただし、Oracle Database 10gより前のリリースでは、XMLデータはデータベース・キャラクタ・セットでのみ取り出されるため、エンコーディングを指定できません)。
XMLデータをCLOBまたはVARCHAR2値として格納すると、エンコーディング宣言がある場合、その宣言は、格納と同様に取出しでも常に無視されます。つまり、取り出す文書のエンコーディングは、その文書で明示的に宣言されているエンコーディングとは異なる場合があります。
データベースから取り出されるXML文書のキャラクタ・セットは、次の方法で決定されます。
SQLクライアント: XMLの取出しに(SQL*Plusなどの)SQLクライアントが使用される場合、キャラクタ・セットはクライアント側の環境変数NLS_LANGによって決定されます。特に、XMLデータ自体にキャラクタ・セットが明示的に宣言されていても、この設定のほうが優先されます。
たとえば、クライアント側のNLS_LANG変数をAMERICAN_AMERICA.AL32UTF8に設定した後、宣言<?xml version="1.0" encoding="EUC-JP"?>によって指定されたエンコーディングEUC_JPでXML文書を取り出した場合、取り出される文書のキャラクタ・セットは、EUC_JPではなくAL32UTF8となります。
|
関連項目: NLS_LANGの詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください。 |
PL/SQLおよびAPI: PL/SQLまたはプログラムAPIを使用すると、XMLデータをVARCHAR、CLOBまたはXMLTypeデータ型で取り出すことができます。SQLクライアントの場合、NLS_LANGを設定することにより、取り出すデータのエンコーディングを制御できます。
また、XMLTypeおよびURITypeメソッドを使用して、XMLデータをBLOB値で取り出すこともできます。これらのメソッドを使用すると、戻されるBLOB値のキャラクタ・セットを指定できます。次に例を示します。
CREATE OR REPLACE FUNCTION getXML(pathname VARCHAR2, charset VARCHAR2)
RETURN BLOB IS
xblob BLOB;
BEGIN
SELECT e.RES.getBLOBVal(nls_charset_id(charset)) INTO xblob
FROM RESOURCE_VIEW e WHERE equals_path(e.RES, pathname) = 1;
RETURN xblob;
END;/
FTP: FTP quote set_nls_localeコマンドを使用して、キャラクタ・セットを設定できます。
ftp> quote set_nls_locale EUC-JP ftp> get mypurchaseorder.xml
HTTP(S): HTTP(S)リクエストでAccept-Charsetパラメータを使用できます。
/httptest/mypurchaseorder.xml 1.1 HTTP/Host: localhost:2345 Accept: text/* Accept-Charset: iso-8859-1, utf-8
W3CのXML Schema勧告では、一連のXML文書の構造、コンテンツおよび特定のセマンティクスを指定するための標準化された言語が定義されています。XML Schemaは、XML文書のクラスを示すメタデータとみなすことができます。XML Schemaの勧告については、http://www.w3.org/TR/xmlschema-0/を参照してください。
指定のXML Schemaに準拠する文書は、そのXML Schemaで定義されたクラスのメンバーまたはインスタンスとみなすことができます。したがって、「インスタンス・ドキュメント」という用語は、多くの場合、指定されたスキーマに準拠するXML文書を示すために使用されます。XML Schemaの最も一般的な用途は、指定されたインスタンス・ドキュメントがXML Schemaで定義されたルールに準拠していることを確認することです。
W3CのSchemaワーキング・グループは「Schema for Schemas」と呼ばれるXML Schemaを公開しています。このXML Schemaによって、XML Schema言語の定義またはボキャブラリが提供されます。有効なすべてのXML Schemaは、そのXML Schemaで定義されたクラスのメンバーとみなすことができます。つまり、XML Schemaは、(http://www.w3.org/2001/XMLSchemaで公開されている)XML Schemaで定義されたクラスに準拠するXML文書であることを意味します。
XML Schemaは、次のいずれかを使用して作成および編集できます。
emacsやviなどの簡単なテキスト・エディタ
Oracle JDeveloperに付属のXMLエディタなど、XML Schemaを認識するエディタ
Altova社のXMLSpyなどの明示的なXML Schema作成ツール
XML Schema言語は、47のスカラー・データ型を定義します。これによって、要素と属性の厳密な型指定が可能になります。W3CのXML Schema勧告では、継承や拡張などのオブジェクト指向の技法もサポートしているため、XML Schema言語で定義された基本データ型から複合的なオブジェクトを持つXML Schemaを設計できます。ボキャブラリには、定義および順序付けの構造体、デフォルト値、必須コンテンツ、ネスト、セットの繰返しおよび再定義が含まれます。Oracle XML DBは、再定義を除くすべての構造体をサポートします。
次のpurchaseOrder.xsdの例は、XML Schemaのサンプルです。XML形式で書かれており、このXML Schema自体がXML文書です。
例3-7 発注書XML Schema、purchaseOrder.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
<xs:element name="PurchaseOrder" type="PurchaseOrderType"/>
<xs:complexType name="PurchaseOrderType">
<xs:sequence>
<xs:element name="Reference" type="ReferenceType"/>
<xs:element name="Actions" type="ActionsType"/>
<xs:element name="Reject" type="RejectionType" minOccurs="0"/>
<xs:element name="Requestor" type="RequestorType"/>
<xs:element name="User" type="UserType"/>
<xs:element name="CostCenter" type="CostCenterType"/>
<xs:element name="ShippingInstructions" type="ShippingInstructionsType"/>
<xs:element name="SpecialInstructions" type="SpecialInstructionsType"/>
<xs:element name="LineItems" type="LineItemsType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="LineItemsType">
<xs:sequence>
<xs:element name="LineItem" type="LineItemType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="LineItemType">
<xs:sequence>
<xs:element name="Description" type="DescriptionType"/>
<xs:element name="Part" type="PartType"/>
</xs:sequence>
<xs:attribute name="ItemNumber" type="xs:integer"/>
</xs:complexType>
<xs:complexType name="PartType">
<xs:attribute name="Id">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="10"/>
<xs:maxLength value="14"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="Quantity" type="moneyType"/>
<xs:attribute name="UnitPrice" type="quantityType"/>
</xs:complexType>
<xs:simpleType name="ReferenceType">
<xs:restriction base="xs:string">
<xs:minLength value="18"/>
<xs:maxLength value="30"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="ActionsType">
<xs:sequence>
<xs:element name="Action" maxOccurs="4">
<xs:complexType>
<xs:sequence>
<xs:element name="User" type="UserType"/>
<xs:element name="Date" type="DateType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RejectionType">
<xs:all>
<xs:element name="User" type="UserType" minOccurs="0"/>
<xs:element name="Date" type="DateType" minOccurs="0"/>
<xs:element name="Comments" type="CommentsType" minOccurs="0"/>
</xs:all>
</xs:complexType>
<xs:complexType name="ShippingInstructionsType">
<xs:sequence>
<xs:element name="name" type="NameType" minOccurs="0"/>
<xs:element name="address" type="AddressType" minOccurs="0"/>
<xs:element name="telephone" type="TelephoneType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="moneyType">
<xs:restriction base="xs:decimal">
<xs:fractionDigits value="2"/>
<xs:totalDigits value="12"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="quantityType">
<xs:restriction base="xs:decimal">
<xs:fractionDigits value="4"/>
<xs:totalDigits value="8"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="UserType">
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="10"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="RequestorType">
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="128"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="CostCenterType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="4"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="VendorType">
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="PurchaseOrderNumberType">
<xs:restriction base="xs:integer"/>
</xs:simpleType>
<xs:simpleType name="SpecialInstructionsType">
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="2048"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="NameType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="AddressType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="256"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="TelephoneType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="24"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="DateType">
<xs:restriction base="xs:date"/>
</xs:simpleType>
<xs:simpleType name="CommentsType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="2048"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="DescriptionType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="256"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
図3-2に、XMLSpyを使用して表示した発注書XML Schemaを示します。XMLSpyは、Altova社のグラフィカルでわかりやすいツールで、XML SchemaおよびXML文書を作成および編集するために使用します。詳細は、http://www.altova.comを参照してください。XMLSpyは、WebDAVおよびFTPプロトコルもサポートしているため、Oracle XML DBリポジトリに格納されているコンテンツに直接アクセスして編集できます。
図3-2 XML Schema PurchaseOrderのXMLSpyによるグラフィカル表現

XML Schema PurchaseOrderは、通常のXML文書の主要な機能を示す簡単なXML Schemaです。
グローバル要素PurchaseOrderは、complexType PurchaseOrderTypeのインスタンスです。
PurchaseOrderTypeでは、PurchaseOrder要素を構成する一連のノードが定義されます。
LineItem要素は、LineItems要素のコレクションで構成されます。
各LineItem要素は、2つの要素(DescriptionおよびPart)で構成されます。
Part要素には、属性Id、QuantityおよびUnitPriceがあります。
この項では、Oracle XML DBでのXML Schemaの使用について説明します。
次に、XML SchemaをOracle XML DBとともに使用する主な理由を説明します。
XML Schemaの最も一般的な用途は、インスタンス・ドキュメントが指定のXML Schemaに準拠していることを確認するメカニズムとして使用することです。XMLTypeデータ型のメソッドisSchemaValid()およびschemaValidate()によって、Oracle XML DBは、XMLTypeに格納されたインスタンス・ドキュメントのコンテンツをXML Schemaと照合して検証できます。
XML Schemaは、XMLTypeの表または列の作成時に制約としても使用できます。たとえば、XMLTypeは、XML Schemaで定義されたいずれかのグローバル要素に準拠するXML文書の格納用に制限されます。
Oracle XML DBでは、XML Schemaを、XMLTypeインスタンスのコンテンツをデータベース内に格納する方法を定義するメカニズムとしても使用します。バイナリXML、構造化、非構造化およびハイブリッド(構造化と非構造化の組合せ)のすべての記憶域モデルで、XML Schemaの使用をサポートしています。XMLTypeに使用可能な記憶域モデルの詳細は、「XMLType記憶域モデル」を参照してください。
XML文書の構造化記憶域には、文書のコンテンツが一連のSQLオブジェクトに分解されて格納されます。これらのSQLオブジェクトは、SQL 1999タイプのフレームワークに基づいています。XML SchemaがOracle XML DBに登録されると、必要なSQL型定義がXML Schemaから自動的に生成されます。
SQL型定義は、XML Schemaで定義された各complexTypeから生成されます。complexTypeで定義された各要素または属性は、対応するSQL型のSQL属性になります。Oracle XML DBは、XML Schema勧告で定義された47のスカラー・データ型を、SQLでサポートされている19のスカラー・データ型に自動的にマップします。VARRAY型は要素ごとに生成され、複数回、生成される場合があります。
生成されたSQL型によって、XML Schemaに準拠したXMLコンテンツは分解され、一連のオブジェクトとしてデータベースに格納されるため、情報の消失はありません。文書が収集されると、XML Schemaで定義された構造体は同等のSQL型に直接マップされます。これによって、Oracle XML DBでは、XMLを管理するときにOracle Databaseのすべての機能を使用でき、文書の格納に必要な領域を大幅に削減できます。また、XMLコンテンツの問合せおよび更新に必要なメモリー量も削減できます。
W3CのXML Schema勧告では、ベンダー固有の情報をXML Schemaに追加できる注釈メカニズムが定義されています。Oracle XML DBでは、このメカニズムを使用して、XML Schemaとデータベース・オプションの間のマッピングを制御します。
XML Schema注釈を使用すると、次の操作を実行できます。
XMLデータを格納するデータベース表の指定
XML Schemaデータ型と、バイナリXMLエンコーディング型、またはSQLデータ型(構造化記憶域の場合)の間のデフォルト・マッピングの上書き
XMLデータを格納するために作成されるデータベース・オブジェクトおよび属性の命名(構造化記憶域の場合)
オブジェクト・リレーショナルに格納されるデータのXML Schemaを登録し、登録パラメータGENTABLESをTRUEに設定する場合、関連付けられたXMLインスタンス・ドキュメントを格納するためにデフォルト表が自動的に作成されます。
格納されたときのXMLコレクション要素の順序が維持されます。結果はOrdered Collectionです。脚注1 データは、次の方法でOrdered Collectionに格納できます。
表内のVARRAY。コレクション内の各要素は、SQLオブジェクトにマップされます。SQLオブジェクトのコレクションは、Ordered Collection Table(OCT)と呼ばれる表に、一連の行として格納されます。デフォルトでは、すべてのコレクションがOCTに格納されます。これはXML Schema注釈xdb:storeVarrayAsTable = "true"に対応します(デフォルト値)。
LOB内のVARRAY。コレクション内の各要素は、SQLオブジェクトにマップされます。SQLオブジェクトのコレクション全体が、VARRAYとしてシリアライズされてLOB列に格納されます。指定されたコレクションをLOB内のVARRAYとして格納右するには、XML Schema注釈xdb:storeVarrayAsTable = "false"を使用します。
Ordered Collectionでは表外への格納を使用することもできます。これはXML Schema注釈SQLInline = "false"に対応しており、コレクション表またはLOB内のREFのVARRAYが、表外に格納されたコレクションの内容に追随していることを意味します。
使用する前に、XML Schemaに注釈を付ける必要はありません。XML Schemaに注釈が付いていない場合、Oracle XML DBは一連のデフォルトの前提を使用してXML Schemaを処理します。
この項で取り上げた注釈のいずれも付けなかった場合、Oracle XML DBはコレクションをヒープに基づくOCTとして格納します。OCTを強制的に索引構成表(IOT)として格納するには、DBMS_XMLSCHEMA.registerschemaのOPTIONSパラメータでREGISTER_NT_AS_IOTを渡します。
|
注意: オラクル社によりIOTの使用を明示的に指示された場合以外は、IOTでなく、ヒープに基づくOCTを使用してください。IOTの記憶域には、次のような大きな制限があります。
XMLデータでのOracle Textの使用方法の詳細は、第11章「XMLデータの全文検索」を参照してください。 |
|
注意: Oracle Database 11gリリース1より前のリリースの場合:
|
XML Schemaに注釈を付けるには、最初にOracle XML DB名前空間を宣言する必要があります。Oracle XML DB名前空間は、次のように宣言します。
http://xmlns.oracle.com/xdb
名前空間をXML Schemaで宣言するには、次のような名前空間宣言をXML Schemaのルート要素に追加します。
xmlns:xdb="http://xmlns.oracle.com/xdb"
名前空間接頭辞(xdb)が使用されていることに注意してください。名前空間接頭辞を使用すると、注釈を追加するときに名前空間をxdbに省略できます。
例3-8に、注釈付きのXML Schema PurchaseOrderの最初の部分を示します。完全なXML Schemaのコードは、例A-1を参照してください。
例3-8 注釈付きの発注書XML Schema、purchaseOrder.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb"
version="1.0"
xdb:storeVarrayAsTable="true">
<xs:element name="PurchaseOrder" type="PurchaseOrderType" xdb:defaultTable="PURCHASEORDER"/>
<xs:complexType name="PurchaseOrderType" xdb:SQLType="PURCHASEORDER_T">
<xs:sequence>
<xs:element name="Reference" type="ReferenceType" minOccurs="1" xdb:SQLName="REFERENCE"/>
<xs:element name="Actions" type="ActionsType" xdb:SQLName="ACTIONS"/>
<xs:element name="Reject" type="RejectionType" minOccurs="0" xdb:SQLName="REJECTION"/>
<xs:element name="Requestor" type="RequestorType" xdb:SQLName="REQUESTOR"/>
<xs:element name="User" type="UserType" minOccurs="1" xdb:SQLName="USERID"/>
<xs:element name="CostCenter" type="CostCenterType" xdb:SQLName="COST_CENTER"/>
<xs:element name="ShippingInstructions" type="ShippingInstructionsType"
xdb:SQLName="SHIPPING_INSTRUCTIONS"/>
<xs:element name="SpecialInstructions" type="SpecialInstructionsType"
xdb:SQLName="SPECIAL_INSTRUCTIONS"/>
<xs:element name="LineItems" type="LineItemsType" xdb:SQLName="LINEITEMS"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="LineItemsType" xdb:SQLType="LINEITEMS_T">
<xs:sequence>
<xs:element name="LineItem" type="LineItemType" maxOccurs="unbounded"
xdb:SQLName="LINEITEM" xdb:SQLCollType="LINEITEM_V"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="LineItemType" xdb:SQLType="LINEITEM_T">
<xs:sequence>
<xs:element name="Description" type="DescriptionType"
xdb:SQLName="DESCRIPTION"/>
<xs:element name="Part" type="PartType" xdb:SQLName="PART"/>
</xs:sequence>
<xs:attribute name="ItemNumber" type="xs:integer" xdb:SQLName="ITEMNUMBER"
xdb:SQLType="NUMBER"/>
</xs:complexType>
<xs:complexType name="PartType" xdb:SQLType="PART_T">
<xs:attribute name="Id" xdb:SQLName="PART_NUMBER" xdb:SQLType="VARCHAR2">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="10"/>
<xs:maxLength value="14"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="Quantity" type="moneyType" xdb:SQLName="QUANTITY"/>
<xs:attribute name="UnitPrice" type="quantityType" xdb:SQLName="UNITPRICE"/>
</xs:complexType>
<xs:simpleType name="ReferenceType">
<xs:restriction base="xs:string">
<xs:minLength value="18"/>
<xs:maxLength value="30"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="ActionsType" xdb:SQLType="ACTIONS_T">
<xs:sequence>
<xs:element name="Action" maxOccurs="4" xdb:SQLName="ACTION" xdb:SQLCollType="ACTION_V">
<xs:complexType xdb:SQLType="ACTION_T">
<xs:sequence>
<xs:element name="User" type="UserType" xdb:SQLName="ACTIONED_BY"/>
<xs:element name="Date" type="DateType" minOccurs="0" xdb:SQLName="DATE_ACTIONED"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RejectionType" xdb:SQLType="REJECTION_T">
<xs:all>
<xs:element name="User" type="UserType" minOccurs="0" xdb:SQLName="REJECTED_BY"/>
<xs:element name="Date" type="DateType" minOccurs="0" xdb:SQLName="DATE_REJECTED"/>
<xs:element name="Comments" type="CommentsType" minOccurs="0" xdb:SQLName="REASON_REJECTED"/>
</xs:all>
</xs:complexType>
<xs:complexType name="ShippingInstructionsType" xdb:SQLType="SHIPPING_INSTRUCTIONS_T">
<xs:sequence>
<xs:element name="name" type="NameType" minOccurs="0" xdb:SQLName="SHIP_TO_NAME"/>
<xs:element name="address" type="AddressType" minOccurs="0" xdb:SQLName="SHIP_TO_ADDRESS"/>
<xs:element name="telephone" type="TelephoneType" minOccurs="0" xdb:SQLName="SHIP_TO_PHONE"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="moneyType">
<xs:restriction base="xs:decimal">
<xs:fractionDigits value="2"/>
<xs:totalDigits value="12"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="quantityType">
<xs:restriction base="xs:decimal">
<xs:fractionDigits value="4"/>
<xs:totalDigits value="8"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="UserType">
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="10"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="RequestorType">
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="128"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="CostCenterType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="4"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="VendorType">
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="PurchaseOrderNumberType">
<xs:restriction base="xs:integer"/>
</xs:simpleType>
<xs:simpleType name="SpecialInstructionsType">
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="2048"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="NameType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="AddressType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="256"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="TelephoneType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="24"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="DateType">
<xs:restriction base="xs:date"/>
</xs:simpleType>
<xs:simpleType name="CommentsType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="2048"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="DescriptionType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="256"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
このXML Schema PurchaseOrderは、次の2つの名前空間を定義します。
http://www.w3c.org/2001/XMLSchema。これは、W3CによってSchema for Schemasのために予約されています。
http://xmlns.oracle.com/xdb。これは、オラクル社によってOracle XML DBのスキーマ注釈用に予約されています。
また、このPurchaseOrderXML Schemaは、次の注釈を含むいくつかの注釈を使用します。
PurchaseOrder要素内のdefaultTable注釈。このXML Schemaに準拠するXML文書をpurchaseorderというデータベース表に格納することを指定します。
SQLType注釈。
SQLTypeが最初に出現したとき、complexType要素PurchaseOrderTypeから生成されたSQL型の名前をpurchaseorder_tと指定します。
SQLTypeが2番目に出現したとき、complexType要素LineItemTypeから生成されたSQL型の名前をlineitem_tと指定し、LineItem要素のコレクションを管理するSQL型の名前をlineitem_vと指定します。
SQLName注釈。purchaseorder_tの各SQL属性の明示的な名前を提供します。
図3-3に、XMLSpyのOracleタブを示します。このタブを使用すると、グラフィカル・エディタでの作業中にOracle XML DBのスキーマ注釈をXML Schemaに容易に追加できます。
XML SchemaをOracle XML DBで使用するには、最初にそのXML SchemaをOracle XML DBに登録する必要があります。XML Schemaを登録した後は、XML文書を検証し、そのXML SchemaにバインドするXMLType表および列を作成できます。
XML SchemaをOracle XML DBに登録するには、次の2つの項目が必要です。
XML Schema文書。
Oracle Databaseに登録後、XML Schemaの一意の識別子として使用できる文字列。この一意の識別子は、XML Schemaで定義されたクラスのメンバーとしてインスタンス・ドキュメントを識別するために使用されます。通常、識別子はURLの形式を取り、多くの場合、スキーマの場所を示すヒントまたは文書の場所を示すヒントとして参照されます。
XML Schemaを登録するには、PL/SQLプロシージャDBMS_XMLSCHEMA.register_schema()を使用します。例3-9を参照してください。デフォルトでは、XML Schemaが登録されると、Oracle XML DBは、インスタンス・ドキュメントの管理に必要なすべてのSQLオブジェクト型とXMLType表を自動的に生成します。
XML Schemaは、グローバルまたはローカルとして登録できます。
|
関連項目:
|
例3-9 DBMS_XMLSCHEMA.registerSchemaを使用したXML Schemaの登録
BEGIN
DBMS_XMLSCHEMA.registerSchema(
'http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd',
XDBURIType('/source/schemas/poSource/xsd/purchaseOrder.xsd').getCLOB(),
TRUE,
TRUE,
FALSE,
TRUE);
END;
/
この例では、XML Schemaの一意の識別子は次のとおりです。
http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd
XML Schema文書は、すでにOracle XML DBリポジトリ(/source/schemas/poSource/xsd/purchaseOrder.xsd)にロードされています。
XML Schemaの登録時に、XDBURITypeは、リポジトリ内のXML Schema文書の場所に基づいてXML Schema文書のコンテンツにアクセスします。プロシージャregisterSchemaに渡されるフラグによって、XML Schemaをローカル・スキーマとして登録する必要があること、およびSQLオブジェクトと表を登録プロセスで生成する必要があることが指定されます。
プロシージャDBMS_XMLSCHEMA.registerSchemaは、次の操作を実行します。
XML Schemaの解析および検証
XML Schemaを記述するOracleデータ・ディクショナリ内の一連のエントリの作成
XML Schemaで定義されたcomplexType要素に基づく一連のSQLオブジェクト定義の作成
XML Schemaで定義された各グローバル要素のXMLType表の作成
例3-10では、XML SchemaをOracle XML DBに登録するときに、オブジェクト型を作成します。
例3-10 XML Schemaの登録時のオブジェクトの作成
DESCRIBE purchaseorder_t purchaseorder_t is NOT FINAL Name Null? Type ----------------------------------------- -------- ---------------------------- SYS_XDBPD$ XDB.XDB$RAW_LIST_T REFERENCE VARCHAR2(30 CHAR) ACTIONS ACTIONS_T REJECTION REJECTION_T REQUESTOR VARCHAR2(128 CHAR) USERID VARCHAR2(10 CHAR) COST_CENTER VARCHAR2(4 CHAR) SHIPPING_INSTRUCTIONS SHIPPING_INSTRUCTIONS_T SPECIAL_INSTRUCTIONS VARCHAR2(2048 CHAR) LINEITEMS LINEITEMS_T DESCRIBE lineitems_t lineitems_t is NOT FINAL Name Null? Type ----------------------------------------- -------- ---------------------------- SYS_XDBPD$ XDB.XDB$RAW_LIST_T LINEITEM LINEITEM_V DESCRIBE lineitem_v lineitem_v VARRAY(2147483647) OF LINEITEM_T LINEITEM_T is NOT FINAL Name Null? Type ----------------------------------------- -------- ---------------------------- SYS_XDBPD$ XDB.XDB$RAW_LIST_T ITEMNUMBER NUMBER(38) DESCRIPTION VARCHAR2(256 CHAR) PART PART_T
この例では、XML SchemaがOracle XML DBに登録されたときに、SQL型定義が作成されています。次のSQL型定義が含まれます。
purchaseorder_t: この型を使用して、PurchaseOrder要素から生成されたSQLオブジェクトを永続的に保持します。PurchaseOrder要素を含むXML文書をOracle XML DBに格納すると、その文書は分割され、文書のコンテンツはpurchaseorder_tのインスタンスとして格納されます。
lineitems_t、lineitem_vおよびlineitem_t: これらの型を使用して、PurchaseOrder文書に存在するLineItem要素のコレクションを管理します。型lineitems_tは、型lineitem_vのインスタンスとして定義された単一の属性lineitemで構成されます。型lineitem_vは、linteitem_tオブジェクトのVARRAYとして定義されます。文書内のLineItem要素ごとにlineitem_tオブジェクトのインスタンスが1つずつあります。
大規模で複雑なXML Schemaを操作する場合、いくつかの問題が発生することがあります。場合により、XML Schemaを登録する際、またはXML Schemaによって定義されたグローバル要素に基づく表を作成する際に、次のいずれかのエラーが発生することがあります。
ORA-01792: 表またはビューに指定できる最大列数は1000です。
ORA-04031: 共有メモリーのstringバイトを割当てできません("string","string","string","string")
このエラーは、グローバル要素に基づいてXMLType表または列を作成するとき、そのグローバル要素が多数の要素と属性の定義を含むcomplexTypeとして定義されている場合に発生します。このエラーが発生するのは、オブジェクト・リレーショナル記憶域を使用するXMLType表または列を作成する場合のみです。この場合、表または列はSQL型を使用して永続的に保持され、SQL型によって定義された各オブジェクト属性は基礎となる表の1つの列とみなされます。SQL型に別のSQL型に基づくオブジェクト属性が含まれる場合も、その型によって定義された属性は基礎となる表の列とみなされます。
すべてのSQL型に含まれるオブジェクト属性の合計数がOracle Databaseの上限の1000列(1つの表で)を超えると、記憶域表は作成できません。complexTypeによって定義された要素と属性の総数が1000に達すると、その型のインスタンスがデータベースに格納される場合、生成されるSQLオブジェクトを管理できる単一の表を作成することはできません。
エラーORA-01792は、1000列の制限を超過したことを報告するものです。エラーORA-04031は、記憶装置が大量の要素と属性の定義処理時に不足することを報告するものです。要素と属性の定義が多すぎるというこの問題を解決するには、記憶域表の作成に使用されるSQL型のオブジェクト属性の総数を削減する必要があります。
問題を早期に解決するには、プロシージャDBMS_XMLSCHEMA.registerSchemaのOPTIONSパラメータで、REGISTER_AUTO_OOLを使用してXML Schemaを登録することができます。その場合、Oracle XML DBは自動的に巨大な型を表外に移動し、エラーの発生確率を低下させます。このオプションを使用する場合、登録パラメータGENTABLESをTRUEに設定する必要もあります。
ただしこのオプションは応急処置であることに注意してください。万能の対処ではありません。これにより、通常XML Schemaの登録が可能になります。それによって、自動的に生成された表を確認して記憶域表の作成に使用するオブジェクト属性の数を削減し、用途に適した結果に到達することができます。
削減を成功させるには、次の2つの方法があります。
XML文書を管理する複数のXMLType表を使用したトップダウン方法を使用します。この方法は、指定した記憶域表について、SQL型階層内のSQL属性の数を減らします。いずれの表も管理するオブジェクト属性が1000を超えないかぎり、この問題は解決します。
SQL型階層内のSQL属性の数を減らすボトムアップ方法を使用します。XML Schemaで定義された一部の要素と属性が縮小されて、単一のCLOB値として格納されます。
いずれの方法とも、XML Schemaに注釈を付けて、特定のcomplexTypeをデータベースに格納する方法を定義します。
トップダウン方法の場合は、SQLInline = "false"およびdefaultTableという注釈によって、XML文書内の一部のサブ要素が別のXMLType表に行として強制的に格納されます。Oracle XML DBは、XMLTypeのREFを使用して2つの表の間の関係を保持します。この手法の適切な候補は、次のいずれかを実行するXML Schemaです。
含まれる各要素がcomplexTypeとして定義される「選択」を定義します。
多数の要素および属性の定義を含むcomplexTypeに基づいて要素を定義します。
ボトムアップ方法では、下位レベルの一部のcomplexType要素をオブジェクトとしてではなくCLOB値として格納することによって、SQLオブジェクト型の属性の数を減らします。これを行うには、complexTypeに注釈を付けるか、SQLType = "CLOB"を指定したcomplexTypeを使用します。
いずれの方法を使用するかは、アプリケーション、およびデータに対して実行される問合せと更新のタイプによって決まります。
デフォルトでは、XML Schemaをデータベースに登録するときに、Oracle XML DBは、そのXML Schemaで定義された各グローバル要素に対してデフォルト表を生成します。
xdb:defaultTable属性を使用して、特定のグローバル要素に対するデフォルト表の名前を指定できます。指定するxdb:defaultTable属性はそれぞれ、特定のデータベース・ユーザーが登録したすべてのスキーマ間で一意である必要があります。一部の要素に対して空でないデフォルト表名を指定しない場合、一意の名前が自動的に提供されます。
しかし実際には、ほとんどの場合、グローバル要素に対してデフォルト表を作成する必要はありません。XMLインスタンス・ドキュメントのルート要素として機能しない要素には、デフォルト表が使用されることはないため、デフォルト表は必要ありません。特に、XML Schemaに多数のグローバル要素定義が含まれている場合は、すべてのグローバル要素に対してデフォルト表を作成すると、プロセッサ時間に大量のオーバーヘッドが発生し、多くの領域が使用される可能性があります。
このため、一般に、どの文書内でもルート要素として使用されないことがわかっているグローバル要素(または表外に格納されたローカル要素)に対しては、デフォルト表が作成されないようにすることができます。これを行うには、次のいずれかの方法を実行します。
XMLインスタンス・ドキュメントのルート要素として表示されない各グローバル要素の定義に、注釈xdb:defaultTable = ""(空の文字列)を追加します。この方法を使用すると、通常はデフォルト表を自動的に作成し、必要な場合にxdb:defaultTable = ""を使用して明示的にデフォルト表の自動作成を禁止できます。
XML Schemaの登録時にGENTABLESパラメータをfalseに設定し、インスタンス・ドキュメントのルート要素として正当に表示できる各グローバル要素に対してデフォルト表を手動で作成します。この方法を使用すると、デフォルト表の自動作成は行われません。必要な表のみを手動で作成します。
XML SchemaをOracle XML DBに登録した後は、XMLType列を含む表を定義する場合、またはXMLType表を作成する場合に、そのXML Schemaを参照できます。
例3-11に、PurchaseOrder要素のデフォルト表である表purchaseorderを手動で作成する方法を示します。
例3-11 XML Schemaに準拠したXMLType表の作成
CREATE TABLE purchaseorder OF XMLType
XMLSCHEMA "http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd"
ELEMENT "PurchaseOrder"
VARRAY "XMLDATA"."ACTIONS"."ACTION"
STORE AS TABLE action_table
((PRIMARY KEY (NESTED_TABLE_ID, SYS_NC_ARRAY_INDEX$)))
VARRAY "XMLDATA"."LINEITEMS"."LINEITEM"
STORE AS TABLE lineitem_table
((PRIMARY KEY (NESTED_TABLE_ID, SYS_NC_ARRAY_INDEX$)));
また、Action要素のコレクションを管理するVARRAYの各メンバーは、Ordered Collection Table、action_tableに格納されます。LineItem要素のコレクションを管理するVARRAYの各メンバーが、Ordered Collection Table、lineitem_tableに行として格納されます。Ordered Collection Tableはヒープに基づいています。PRIMARY KEY指定のため、表には擬似列NESTED_TABLE_IDおよび列SYS_NC_ARRAY_INDEX$が自動的に含まれます。これらの列は、親の列に逆リンクするために必要です。
このCREATE TABLE文は、XML Schema登録の際、パラメータGENTABLESをTRUEに設定すると、Oracle XML DBにより自動生成されるCREATE TABLE文と同等です。デフォルトでは、XML Schema注釈storeVarrayAsTableの値はtrueで、XML Schema登録時に、コレクションに対してOrdered Collection Tables(OCT)を自動生成します。このOCTにはシステムが生成した、覚えにくい名前が付けられます。SQL文RENAME TABLEを使用して、わかりやすい名前を付けることができます。
例3-11のCREATE TABLE文は、単一レベルのネストが行われている発注書に対応しています。LineItem要素のコレクションを管理するVARRAYは、Ordered Collection Table、lineitem_tableです。ここで、別のXML Schemaを想定し、Shipment要素のコレクションがShipments要素内にあり、この要素がLineItem要素内にあるとします。この場合は、例3-12に示すように、表を手動で作成できます。
例3-12 ネストしたコレクションのXMLType表の作成
CREATE TABLE purchaseorder OF XMLType
XMLSCHEMA "http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd"
ELEMENT "PurchaseOrder"
VARRAY "XMLDATA"."ACTIONS"."ACTION"
STORE AS TABLE action_table
((PRIMARY KEY (NESTED_TABLE_ID, SYS_NC_ARRAY_INDEX$)))
VARRAY "XMLDATA"."LINEITEMS"."LINEITEM"
STORE AS TABLE lineitem_table
((PRIMARY KEY (NESTED_TABLE_ID, SYS_NC_ARRAY_INDEX$))
VARRAY "SHIPMENTS"."SHIPMENT"
STORE AS TABLE shipments_table
((PRIMARY KEY (NESTED_TABLE_ID,
SYS_NC_ARRAY_INDEX$))));
例3-13 XML Schemaに基づくXMLType表に対するDESCRIBEの使用
SQL*PlusのDESCRIBE文(DESCに省略可能)を使用すると、XMLType表に関する情報を表示できます。
DESCRIBE purchaseorder Name Null? Type ----------------------------------------- -------- ---------------------------- TABLE of SYS.XMLTYPE(XMLSchema "http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd" Element "PurchaseOrder") STORAGE Object-relational TYPE "PURCHASEORDER_T"
DESCRIBE文の出力には、PurchaseOrder表に関する次の情報が表示されます。
表はXMLType表です。
表は、XML Schema PurchaseOrderで定義されたPurchaseOrder文書の格納用に制限されます。
この表の行は、データベースに一連のオブジェクトとして格納されます。
SQL型purchaseorder_tは、この表のベース・オブジェクトです。
例3-11のXML Schemaでは、PurchaseOrder表がPurchaseOrder要素のデフォルト表であることが指定されています。XML Schemaに準拠するXML文書を、プロトコルまたはPL/SQLを使用してOracle XML DBリポジトリに挿入すると、そのXML文書のコンテンツはpurchaseorder表に行として格納されます。
XML Schemaをグローバル・スキーマとして登録した場合は、デフォルト表に対する適切なアクセス権をデータベースのすべてのユーザーに付与する必要があります。これによって、ユーザーは、グローバルに登録したXML Schemaに準拠するインスタンス・ドキュメントを操作できるようになります。
XML文書をXML Schemaに基づくXMLType表または列に挿入する前に、関連付けられているXML Schemaを識別する必要があります。識別するには、次の2つの方法があります。
XMLTypeの作成時に明示的にXML Schemaを識別します。これを行うには、XML Schemaの名前をXMLTypeコンストラクタに渡すか、またはXMLTypeのcreateSchemaBasedXML()メソッドを起動します。
XMLSchema-instanceメカニズムを使用して、必要な情報をXML文書に明示的に提供します。このオプションはOracle XML DBを操作する場合に使用できます。
XMLSchema-instanceメカニズムのメリットは、Oracle XML DBリポジトリに挿入されたXML文書が登録済のXML SchemaのインスタンスであることをOracle XML DBプロトコル・サーバーが認識できることです。インスタンス・ドキュメントのコンテンツは、そのXML Schemaで指定されたデフォルト表に自動的に格納されます。
XMLSchema-instanceメカニズムは、W3CのXML Schemaワーキング・グループで定義されています。このメカニズムの基本は、ターゲットのXML Schemaを識別する属性をインスタンス・ドキュメントのルート要素に追加することです。追加された属性は、XMLSchema-instance名前空間で定義されます。
インスタンス・ドキュメントを特定のXML Schemaで定義されたクラスのメンバーとして識別するには、名前空間宣言をインスタンス・ドキュメントのルート要素に追加して、XMLSchema-instance名前空間を宣言する必要があります。次に例を示します。
xmlns:xsi = http://www.w3.org/2001/XMLSchema-instance
XMLSchema-instance名前空間が宣言され、名前空間接頭辞が指定されると、XML Schemaを識別する属性をインスタンス・ドキュメントのルート要素に追加できます。前述の例では、XMLSchema-instance名前空間の名前空間接頭辞がxsiと定義されています。この接頭辞は、XMLSchema-instanceの属性をインスタンス・ドキュメントのルート要素に追加する際に使用できます。
追加する属性は、多くの要因によって決定します。noNamespaceSchemaLocationおよびschemaLocationに、その可能性があります。インスタンス・ドキュメントが関連付けられているXML Schemaを識別するには、XML Schemaに応じて、1つまたは両方の属性が必要です。
ターゲットのXML Schemaでターゲットの名前空間が宣言されていない場合は、noNamespaceSchemaLocation属性を使用してXML Schemaを識別します。この属性の値は、スキーマの場所を示すヒントです。この値は、XML Schemaをデータベースに登録するときにPL/SQLプロシージャDBMS_XMLSCHEMA.registerSchemaに渡される一意の識別子です。
XML Schema purchaseOrder.xsdの場合、インスタンス・ドキュメントのルート要素の正しい定義は次のとおりです。
<PurchaseOrder
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:noNamespaceSchemaLocation=
"http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd">
ターゲットのXML Schemaでターゲットの名前空間が宣言されている場合は、schemaLocation属性を使用してXML Schemaを識別します。この属性の値は2つの値の組合せで、空白によって区切られています。
XML Schemaで宣言されたターゲットの名前空間の値
XML Schemaをデータベースに登録するときにプロシージャ DBMS_XMLSCHEMA.registerSchemaに渡される一意の識別子である、スキーマの場所を示すヒント
たとえば、XML Schema PurchaseOrderにターゲットの名前空間宣言が含まれているとします。この場合、スキーマのルート要素は次のようになります。
<xs:schema targetNamespace="http://demo.oracle.com/xdb/purchaseOrder"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb"
version="1.0" xdb:storeVarrayAsTable="true">
<xs:element name="PurchaseOrder" type="PurchaseOrderType"
xdb:defaultTable="PURCHASEORDER"/>
この場合、インスタンス・ドキュメントのルート要素の正しい形式は次のとおりです。
<PurchaseOrder
xnlns="http://demo.oracle.com/xdb/purchaseOrder"
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=
"http://demo.oracle.com/xdb/purchaseOrder
http://mdrake-lap:8080/source/schemas/poSource/xsd/purchaseOrder.xsd">
Oracle XML DBを使用してXMLコンテンツを管理するメリットの1つは、SQLを使用してXML Schemaで提供される機能を補完できることです。SQLおよびXMLの機能と、ルールを規定するデータベースの機能を組み合せることによって、XMLコンテンツを管理する強力なフレームワークとしてデータベースを使用できます。
XMLType表または列に格納できるのは、整形式のXML文書のみです。整形式のXML文書とは、XML宣言で宣言されたXMLバージョンの構文に準拠しているXML文書です。これには、ルート要素が単一か、タグが適切にネストされているかなどが含まれます。さらに、XMLType表または列がXML Schemaに制限される場合、その表または列に格納できるのはXML Schemaに準拠する文書のみです。これ以外のXML文書をXML Schemaに基づくXMLTypeに格納または挿入しようとすると、エラーが発生します。例3-14に、これを示します。
例3-14 不適切なXML文書を挿入しようとした場合に発生するエラー
INSERT INTO purchaseorder
VALUES (XMLType(bfilename('XMLDIR', 'Invoice.xml'), nls_charset_id('AL32UTF8')))
VALUES (XMLType(bfilename('XMLDIR', 'Invoice.xml'), nls_charset_id('AL32UTF8')))
*
ERROR at line 2:
ORA-19007: Schema - does not match expected
http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd.
このようなエラーが発生するのは、コンテンツがXMLType表に直接挿入された場合のみです。これは、Oracle XML DBが、XML Schemaで定義されたクラスのメンバーとして文書を認識していないことを示します。XML Schemaで定義されたクラスのメンバーとして認識される文書は、次の条件を満たしている必要があります。
XML文書のルート要素の名前が、XMLType表または列の定義で使用するグローバル要素の名前と一致する必要があります。
XML文書にXMLSchema-instance名前空間の適切な属性が含まれているか、またはXMLTypeコンストラクタかcreateSchemaBasedXML()メソッドを使用してXML文書がXML Schemaに明示的に関連付けられている必要があります。
制限されているXML SchemaでtargetNamespaceが宣言されている場合、インスタンス・ドキュメントには、XML Schemaで定義されたtargetNamespaceに文書のルート要素を配置するための適切な名前空間宣言が含まれている必要があります。
|
注意: XMLによる制限は、個々のXML文書内で適用されます。データベース(SQL)による制限は、一連のXML文書にわたって適用されます。 |
この項では、XML文書をデータベースに挿入するときに使用する、XML Schemaの部分検証と全体検証の違いについて説明します。
バイナリXML記憶域では、XML文書をXML Schemaに基づくXMLType表または列に挿入するたびに、Oracle XML DBはその文書の全体検証を実行します。他のすべてのXML記憶域モデルでは、Oracle XML DBは文書の部分検証のみを実行します。これは、バイナリXML記憶域を除き、XML Schemaの完全な検証はパフォーマンスの面で非常にコストが高くなるためです。
部分検証では、文書内に必須の要素および属性がすべて存在すること、および予期しない要素または属性のないことが確認されるのみです。つまり、XML文書の構造がXML Schemaから導出されたSQLデータ型定義に準拠していることのみが確認されます。部分検証では、インスタンス・ドキュメントがXML Schemaに完全に準拠しているかどうかは確認されません。例3-15に、オブジェクト・リレーショナル形式で格納されている表PurchaseOrderにXML文書を挿入する間に部分検証が失敗した例を示します。
例3-15 不適切なXML文書の挿入時に発生するエラー(部分検証)
INSERT INTO purchaseorder
VALUES(XMLType(bfilename('XMLDIR', 'InvalidElement.xml'),
nls_charset_id('AL32UTF8')));
VALUES(XMLType(bfilename('XMLDIR', 'InvalidElement.xml'),
*
ERROR at line 2:
ORA-30937: No schema definition for 'UserName' (namespace '##local') in parent
'/PurchaseOrder'
XMLデータをXML Schemaに基づくバイナリXML記憶域にロードすると、ターゲットXML Schemaに対する全体検証が行われます。これ以外の場合は、記憶域モデルと無関係に、次のいずれかの方法を使用して、XML Schemaに対するXMLインスタンス・ドキュメントの全体検証をいつでも強制的に実行できます。
表レベルのCHECK制約
PL/SQLのBEFORE INSERTトリガー
どちらの方法でも、妥当なXML文書のみがXMLType表に格納されることが保証されます。
TABLE CHECK制約を使用する方法のメリットは、コーディングが簡単なことです。この方法のデメリットは、この方法がSQL関数XMLisValidに基づいているため、XML文書が妥当であるかどうかしか示されないことです。この方法では、XML文書が妥当でない場合にその理由についての情報が提供されません。
BEFORE INSERTトリガーの場合は、必要なコーディングが表レベルの制約よりわずかに多くなります。このトリガーでは、XMLTypeのschemaValidate()メソッドを起動してXML文書を検証します。schemaValidate()を使用するメリットは、例外が発生した場合にそのインスタンス・ドキュメントの問題点に関する追加情報が提供されることです。また、BEFORE INSERTトリガーを使用すると、無効な文書が存在する場合に適切な処置を行うことができます。
バイナリXML記憶域を使用していない場合は、XML Schemaの全体検証を実行すると、多くの処理時間とメモリーが消費されます。このため、XML Schemaの全体検証は、必要なときにのみ実行してください。XML文書を検証するアプリケーションを使用する場合は、全体検証に関連するオーバーヘッドを回避することによって、バイナリ以外のXML記憶域での全体のスループットを向上させることができます。受信するXML文書の妥当性について確認できない場合は、スキーマに対して妥当なXML文書のみがXMLType表または列に含まれていることをデータベースで確認できます。
例3-16に、CHECK制約をXMLType表に追加してXML Schemaの全体検証を実施する方法を示します。例3-16に示すXML文書のInvalidReferenceは、XML Schemaに従った妥当なXML文書ではありません。XML Schemaでは、Reference要素に関連付けられたテキスト・ノードの最小長を18文字とすることが定義されています。この例に示す文書では、ノードの値はSBELL-20021009で、14文字の長さしかありませんが、部分検証ではこのエラーを把握できません。制約またはトリガーがないかぎり、この文書をデータベースに挿入することが可能です。
例3-16 CHECK制約を使用したXML Schemaの全体検証の実施
この例では、CHECK制約がPurchaseOrder表に追加されています。無効な文書を表に挿入しようとすると、失敗します。
ALTER TABLE purchaseorder
ADD CONSTRAINT validate_purchaseorder
CHECK (XMLIsValid(OBJECT_VALUE) = 1);
Table altered.
INSERT INTO purchaseorder
VALUES (XMLType(bfilename('XMLDIR', 'InvalidReference.xml'),
nls_charset_id('AL32UTF8')));
INSERT INTO purchaseorder
*
ERROR at line 1:
ORA-02290: check constraint (QUINE.VALIDATE_PURCHASEORDER) violated
疑似列名OBJECT_VALUEを使用すると、トリガー内からXMLType表のコンテンツにアクセスできます。
例3-17 BEFORE INSERTトリガーを使用したXML Schemaの全体検証の実施
この例は、BEFORE INSERTトリガーを使用して、XMLType表に挿入されるデータが、指定されたXML Schemaに準拠していることを検証する方法を示しています。
CREATE OR REPLACE TRIGGER validate_purchaseorder
BEFORE INSERT ON purchaseorder
FOR EACH ROW
BEGIN
IF (:new.OBJECT_VALUE IS NOT NULL) THEN :new.OBJECT_VALUE.schemavalidate();
END IF;
END;
/
Trigger created.
INSERT INTO purchaseorder VALUES (XMLType(bfilename('XMLDIR', 'InvalidReference.xml'),
nls_charset_id('AL32UTF8')));
VALUES (XMLType( bfilename('XMLDIR', 'InvalidReference.xml'),
*
ERROR at line 2:
ORA-31154: invalid XML document
ORA-19202: Error occurred in XML processing
LSX-00221: "SBELL-20021009" is too short (minimum length is 18)
ORA-06512: at "SYS.XMLTYPE", line 354
ORA-06512: at "QUINE.VALIDATE_PURCHASEORDER", line 3
ORA-04088: error during execution of trigger 'QUINE.VALIDATE_PURCHASEORDER'
W3CのXML Schema勧告では、XML文書のコンテンツを定義するための強力な言語が定義されています。ただし、現在はW3CのXML Schema勧告で扱われていない簡単なデータ管理の概念がいくつかあります。たとえば、要素または属性の値が次のいずれかのプロパティを持っているかを確認できることなどです。
XML文書のセット間で一意であること(UNIQUE制約)
現在の文書以外の特定のデータ・ソース内に存在していること(FOREIGN KEY制約)
ただし、Oracle XML DBでは、そうした制約を強制的に適用できます。XMLデータで整合性を規定するために使用するメカニズムは、リレーショナル・データで整合性を規定するためのメカニズムと同じです。一意性と外部キーの関係などの簡単なルールは、制約を指定することによって規定できます。複雑なルールは、データベース・トリガーを指定して規定できます。
Oracle XML DBを使用すると、XML Schema構造体を使用して指定できるルールに加え、データベースを使用して、ビジネス・ルールもXMLコンテンツに実施することができます。データベースでは、XMLが表に直接挿入されているか、Oracle XML DBリポジトリでサポートされているプロトコルの1つを使用してアップロードされているかに関係なく、これらのビジネス・ルールを規定します。
例3-18、例3-19および例3-20は、SQL制約を使用して参照整合性を規定する方法を説明しています。例3-18は、バイナリXMLとして格納されているXMLType表における一意性制約を定義しています。仮想列は、発注書のReference要素を使用して定義されます。一意性制約reference_is_uniqueは、ノード/PurchaseOrder/Reference/text()の値が、表に格納されているすべての文書を通じて一意であることを保証します。
例3-18 バイナリXML形式で格納されているXMLType表の仮想列使用による制約
CREATE TABLE po_binaryxml OF XMLType XMLTYPE STORE AS BINARY XML VIRTUAL COLUMNS (c_reference AS (extractValue(OBJECT_VALUE, '/PurchaseOrder/Reference'))); INSERT INTO po_binaryxml SELECT OBJECT_VALUE FROM OE.purchaseorder; 132 rows created. ALTER TABLE po_binaryxml ADD CONSTRAINT reference_is_unique UNIQUE (c_reference); INSERT INTO po_binaryxml VALUES (XMLType(bfilename('XMLDIR', 'DuplicateReference.xml'), nls_charset_id('AL32UTF8'))); INSERT INTO po_binaryxml * ERROR at line 1: ORA-00001: unique constraint (OE.REFERENCE_IS_UNIQUE) violated
例3-19は、データベース・スキーマOEのXMLType表purchaseorderにおける類似の一意性制約を定義しています。さらに、各発注書のUser要素が、標準データベース表HR.employeesに存在する従業員の電子メール・アドレスであることを要求する外部キー制約を定義しています。OE.purchaseorder表の場合のように、オブジェクト・リレーショナル形式で格納されているXMLデータの場合、制約は、XMLコンテンツを管理するために使用されるSQLデータ型のオブジェクト属性によって指定される必要があります。
例3-19 オブジェクト・リレーショナルに格納されているXMLType表のデータベース整合性制約とトリガー
ALTER TABLE purchaseorder ADD CONSTRAINT reference_is_unique UNIQUE (XMLDATA."REFERENCE"); Table altered. ALTER TABLE purchaseorder ADD CONSTRAINT user_is_valid FOREIGN KEY (XMLDATA."USERID") REFERENCES hr.employees(email); Table altered. INSERT INTO purchaseorder VALUES (XMLType(bfilename('XMLDIR', 'purchaseOrder.xml'), nls_charset_id('AL32UTF8'))); 1 row created. INSERT INTO purchaseorder VALUES (XMLType(bfilename('XMLDIR', 'DuplicateReference.xml'), nls_charset_id('AL32UTF8'))); INSERT INTO purchaseorder * ERROR at line 1: ORA-00001: unique constraint (QUINE.REFERENCE_IS_UNIQUE) violated INSERT INTO purchaseorder VALUES (XMLType(bfilename('XMLDIR', 'InvalidUser.xml'), nls_charset_id('AL32UTF8'))); INSERT INTO purchaseorder * ERROR at line 1: ORA-02291: integrity constraint (QUINE.USER_IS_VALID) violated - parent key not found
例3-18と同様に、ここでは一意性制約reference_is_uniqueが発注書Reference要素の、表に格納されたすべてのドキュメントを通じての一意性を保証しています。外部キー制約user_is_validは、ここで要素Userの値がemployees表のemail列の値に対応することを保証しています。
XML文書DuplicateRefernce.xmlのReference要素に関連付けられたテキスト・ノードに、XML文書PurchaseOrder.xml内の対応するノードと同じ値が含まれています。したがって、両方の文書をOracle XML DBに格納しようとすると、制約reference_is_uniqueに違反します。
また、XML文書InvalidUser.xmlのUser要素に関連付けられたテキスト・ノードには、値HACKERが含まれています。employees表には、email列の値がHACKERのエントリはありません。この文書をOracle XML DBに格納しようとすると、制約user_is_validに違反します。
XML Schemaに基づくXMLコンテンツがOracle XML DBリポジトリにロードされると、制約とトリガーを使用して定義された整合性ルールも規定されます。
例3-20は、FTPなどのプロトコルを使用してXML Schemaに基づくXMLコンテンツがOracle XML DBリポジトリにアップロードされた場合に、データベース整合性も規定される例を示しています。
例3-20 FTPを使用してXMLをロードしたときのデータベース整合性の規定
$ ftp localhost 2100
Connected to localhost.
220 mdrake-sun FTP Server (Oracle XML DB/Oracle Database 10g Enterprise Edition
Release 10.1.0.0.0 - Beta) ready.
Name (localhost:oracle10): QUINE
331 Password required for QUINE
Password: password
230 QUINE logged in
ftp> cd /source/schemas
250 CWD Command successful
ftp> put InvalidReference.xml
200 PORT Command successful
150 ASCII Data Connection
550- Error Response
ORA-00604: error occurred at recursive SQL level 1
ORA-31154: invalid XML document
ORA-19202: Error occurred in XML processing
LSX-00221: "SBELL-20021009" is too short (minimum length is 18)
ORA-06512: at "SYS.XMLTYPE", line 333
ORA-06512: at "QUINE.VALIDATE_PURCHASEORDER", line 3
ORA-04088: error during execution of trigger 'QUINE.VALIDATE_PURCHASEORDER'
550 End Error Response
ftp> put InvalidElement.xml
200 PORT Command successful
150 ASCII Data Connection
550- Error Response
ORA-30937: No schema definition for 'UserName' (namespace '##local') in parent
'PurchaseOrder'
550 End Error Response
ftp> put DuplicateReference.xml
200 PORT Command successful
150 ASCII Data Connection
550- Error Response
ORA-00604: error occurred at recursive SQL level 1
ORA-00001: unique constraint (QUINE.REFERENCE_IS_UNIQUE) violated
550 End Error Response
ftp> put InvalidUser.xml
200 PORT Command successful
150 ASCII Data Connection
550- Error Response
ORA-00604: error occurred at recursive SQL level 1
ORA-02291: integrity constraint (QUINE.USER_IS_VALID) violated - parent key not
found
550 End Error Response
完全なSQLエラー・トレース
プロトコルを使用して文書をアップロードしているときにエラーが発生すると、Oracle XML DBはクライアントに対して完全なSQLエラー・トレースを提供します。エラーの解析とレポートの方法は、クライアント・アプリケーションに組み込まれたエラー処理によって決まります。たとえば、コマンドラインFTPツールなどのクライアントはOracle XML DBから戻されたエラーをレポートし、Microsoft Windows Explorerなどのクライアントは単に汎用エラー・メッセージをレポートします。
Oracle XML DBを使用してXMLコンテンツを管理するもう1つの主なメリットは、Oracle Databaseの機能を使用してXMLコンテンツの問合せと更新を行う強力で柔軟な機能が提供されることです。次の機能が含まれます。
XML文書内のノードとフラグメントの取出し
XML文書内のノードとフラグメントの更新
XML文書内の特定ノード上での索引の作成
XML文書のコンテンツ全体の索引付け
XML文書に特定のノードが含まれるかどうかの判別
Oracle XML DBには、XMLTypeメソッドおよびXML固有のSQL関数が含まれています。それらのメソッドとSQL関数を使用すると、Oracle Databaseに格納されているXMLコンテンツを問合せおよび更新できます。これらのメソッドとSQL関数では、1つまたは複数の必須ノードを識別するために、W3CのXPath勧告が使用されています。XML文書の各ノードは、XPath式によって一意に識別できます。
XPath式は、スラッシュ記号で区切った要素名、属性名およびXPath関数のリストで構成されます。XPath式には、ターゲット・ノードの判別時に検索するツリーのブランチを決定する位置および条件を含めることができます。
XPathを使用したメソッドと関数がサポートされているため、XMLプログラマはOracle XML DBを使用し、標準に準拠した一般的な方法でXML文書を問合せおよび更新できます。
|
注意: Oracle SQL関数およびXMLTypeメソッドは、W3CのXPath勧告に準拠しています。これは、XPath式をXMLデータに適用する際にXPath式がどのノードもターゲットにしていない場合、空のシーケンスが戻される必要がある、つまり、エラーが発生してはいけないことを規定したものです。
XPath式をXMLデータに適用するOracle SQL関数または |
この項では、Oracle XML DBの問合せ方法およびXMLコンテンツの取出し方法について説明します。この項の内容は次のとおりです。
この項では、次のXML文書PurchaseOrderを使用した例を示します。
例3-21 XMLインスタンス・ドキュメントPurchaseOrder
<PurchaseOrder
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation=
"http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd">
<Reference>SBELL-2002100912333601PDT</Reference>
<Actions>
<Action>
<User>SVOLLMAN</User>
</Action>
</Actions>
<Reject/>
<Requestor>Sarah J. Bell</Requestor>
<User>SBELL</User>
<CostCenter>S30</CostCenter>
<ShippingInstructions>
<name>Sarah J. Bell</name>
<address>400 Oracle Parkway
Redwood Shores
CA
94065
USA</address>
<telephone>650 506 7400</telephone>
</ShippingInstructions>
<SpecialInstructions>Air Mail</SpecialInstructions>
<LineItems>
<LineItem ItemNumber="1">
<Description>A Night to Remember</Description>
<Part Id="715515009058" UnitPrice="39.95" Quantity="2"/>
</LineItem>
<LineItem ItemNumber="2">
<Description>The Unbearable Lightness Of Being</Description>
<Part Id="37429140222" UnitPrice="29.95" Quantity="2"/>
</LineItem>
<LineItem ItemNumber="3">
<Description>Sisters</Description>
<Part Id="715515011020" UnitPrice="29.95" Quantity="4"/>
</LineItem>
</LineItems>
</PurchaseOrder>
OBJECT_VALUE擬似列は、オブジェクト表の値の別名として使用できます。XMLTypeの単一列からなるXMLType表の場合、XML文書全体が取り出されます。(OBJECT_VALUEは、Oracle Database 10gリリース1より前のリリースで使用されていたvalue(x)およびSYS_NC_ROWINFO$別名に換わるものです。)
例3-22 OBJECT_VALUEを使用したXML文書全体の取出し
この例では、文書全体が改行なしで正しく出力されるように、SQL*Plus設定のPAGESIZEおよびLONGを使用しています。(読みやすいように、フォーマット出力で示しています。)
SET LONG 10000
SET PAGESIZE 100
SELECT OBJECT_VALUE FROM purchaseorder;
OBJECT_VALUE
-----------------------------------------------------------------------
<PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://localhost:8080/source/schemas
/poSource/xsd/purchaseOrder.xsd">
<Reference>SBELL-2002100912333601PDT</Reference>
<Actions>
<Action>
<User>SVOLLMAN</User>
</Action>
</Actions>
<Reject/>
<Requestor>Sarah J. Bell</Requestor>
<User>SBELL</User>
<CostCenter>S30</CostCenter>
<ShippingInstructions>
<name>Sarah J. Bell</name>
<address>400 Oracle Parkway
Redwood Shores
CA
94065
USA</address>
<telephone>650 506 7400</telephone>
</ShippingInstructions>
<SpecialInstructions>Air Mail</SpecialInstructions>
<LineItems>
<LineItem ItemNumber="1">
<Description>A Night to Remember</Description>
<Part Id="715515009058" UnitPrice="39.95" Quantity="2"/>
</LineItem>
<LineItem ItemNumber="2">
<Description>The Unbearable Lightness Of Being</Description>
<Part Id="37429140222" UnitPrice="29.95" Quantity="2"/>
</LineItem>
<LineItem ItemNumber="3">
<Description>Sisters</Description>
<Part Id="715515011020" UnitPrice="29.95" Quantity="4"/>
</LineItem>
</LineItems>
</PurchaseOrder>
1 row selected.
SQL関数extractは、XPath式と一致するノードを戻します。ノードは、XMLTypeの1つのインスタンスとして戻されます。extractの結果は、完全な文書またはXMLフラグメントになります。SQL関数extractの機能は、XMLTypeメソッドextract()を介して使用することもできます。
例3-23 EXTRACTを使用したXMLフラグメントへのアクセス
この問合せは、XPath式と一致するReference要素を含むXMLType値を戻します。
SELECT extract(OBJECT_VALUE, '/PurchaseOrder/Reference') FROM purchaseorder; EXTRACT(OBJECT_VALUE, '/PURCHASEORDER/REFERENCE') ------------------------------------------------- <Reference>SBELL-2002100912333601PDT</Reference> 1 row selected.
この問合せは、LineItemコレクション内の最初のLineItems要素を含むXMLType値を戻します。
SELECT extract(OBJECT_VALUE, '/PurchaseOrder/LineItems/LineItem[1]') FROM purchaseorder; EXTRACT(OBJECT_VALUE, '/PURCHASEORDER/LINEITEMS/LINEITEM[1]') ------------------------------------------------------------- <LineItem ItemNumber="1"> <Description>A Night to Remember</Description> <Part Id="715515009058" UnitPrice="39.95" Quantity="2"/> </LineItem> 1 row selected.
次の問合せは、XPath式と一致する3つのDescription要素を含むXMLTypeインスタンスを戻します。これらの要素は単一のXMLType内のノードとして戻されるため、XMLType値は単一のルート・ノードを持ちません。XMLフラグメントとして処理されます。
SELECT extract(OBJECT_VALUE, '/PurchaseOrder/LineItems/LineItem/Description') FROM purchaseorder; EXTRACT(OBJECT_VALUE, '/PURCHASEORDER/LINEITEMS/LINEITEM/DESCRIPTION') ---------------------------------------------------------------------- <Description>A Night to Remember</Description> <Description>The Unbearable Lightness Of Being</Description> <Description>Sisters</Description> 1 row selected.
テキスト・ノードおよび属性値には、SQL/XML標準関数XMLQueryおよびXMLCastを使用してアクセスできます。このためには、XMLQueryに渡されるXPath式は、文書内の単一のテキスト・ノードまたは属性値(リーフ・ノード)を一意に識別する必要があります。
例3-24 XMLCASTを使用したテキスト・ノード値へのアクセス
この問合せは、XPath式と一致するReference要素に関連付けられたテキスト・ノードの値を戻します。値は、VARCHAR2値として戻されます。
SELECT XMLCast(XMLQuery('$p/PurchaseOrder/Reference/text()'
PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
AS VARCHAR2(30))
FROM purchaseorder;
XMLCAST(XMLQUERY('$P/PURCHASEO
------------------------------
SBELL-2002100912333601PDT
1 row selected.
次の問合せは、LineItem要素に含まれるDescription要素に関連付けられたテキスト・ノードの値を戻します。特定のLineItem要素は、そのId属性値によって指定されます。LineItem要素を識別する述語は、[Part/@Id="715515011020"]です。アットマーク(@)は、Idが要素でなく属性であることを指定します。値は、VARCHAR2値として戻されます。
SELECT XMLCast(
XMLQuery('$p/PurchaseOrder/LineItems/LineItem[Part/@Id="715515011020"]/Description/text()'
PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
AS VARCHAR2(30))
FROM purchaseorder;
XMLCAST(XMLQUERY('$P/PURCHASEO
------------------------------
Sisters
1 row selected.
次の問合せは、最初のLineItem要素に含まれるDescription要素に関連付けられたテキスト・ノードの値を戻します。最初のLineItem要素は、位置述語[1]で示されます。
SELECT XMLCast(XMLQuery('$p/PurchaseOrder/LineItems/LineItem[1]/Description'
PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
AS VARCHAR2(4000))
FROM purchaseorder;
XMLCAST(XMLQUERY('$P/PURCHASEORDER/LINEITEMS/LINEITEM[1]/DESCRIPTION'PASSINGOBJECT_VALUEAS"P"
---------------------------------------------------------------------------------------------
A Night to Remember
1 row selected.
|
関連項目:
|
例3-23は、SQL関数extractが、XPath式と一致した1つ以上のノードを含むXMLTypeインスタンスを戻す方法を示しています。指定されたXPath式と一致するノードが文書に複数含まれている場合、extractは、一致するすべてのノードが含まれるXMLフラグメントを戻します。XML文書と異なり、XMLフラグメントには、ルート要素である単一の要素はありません。
このような結果は、次の場合に一般的です。
extractを使用して、コレクションに含まれている一連の要素を取り出す場合。この場合、フラグメント内のすべてのノードは同じタイプです(例3-25を参照)。
XPath式がワイルドカードで終わる場合。この場合、フラグメント内のノードは異なるタイプになることがあります(例3-27を参照)。
SQL/XML標準関数XMLTableを使用すると、XMLTypeインスタンスに含まれているXMLフラグメントを分割し、コレクション/要素データを新規の仮想表に挿入できます。この表は、結合式などでSQLを使用して問い合せることができます。特に、XMLフラグメントを仮想表に変換することで、複数のノードを戻すextract式の結果の処理が容易になります。
例3-25 XMLTABLEを使用したDescriptionノードへのアクセス
この例は、PurchaseOrder文書のDescription要素ごとにテキスト・ノードにアクセスする方法を示しています。
最初に、SQL関数extractValueを使用してみます。文書内に複数のDescription要素が存在するため、この関数は失敗します。
SELECT extractValue(OBJECT_VALUE,
'/PurchaseOrder/LineItems/LineItem/Description')
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
SELECT extractValue(OBJECT_VALUE,
'/PurchaseOrder/LineItems/LineItem/Description')
*
ERROR at line 1:
ORA-01427: single-row subquery returns more than one row
2番目に、SQL関数extractを使用して必要な値にアクセスしてみます。これによって、一連のDescriptionノードが単一のXMLTypeオブジェクトとして戻されます。このオブジェクトには、3つのDescriptionノードで構成される単一のフラグメントが含まれています。この方法は前述の例よりも効率的ですが、SQLを使用してテキスト・ノードの値を追加処理できるようにすることが目的のため、あまり便利ではありません。
SELECT extract(OBJECT_VALUE, '/PurchaseOrder/LineItems/LineItem/Description')
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
EXTRACT(OBJECT_VALUE,'/PURCHASEORDER/LINEITEMS/LINEITEM/DESCRIPTION')
---------------------------------------------------------------------
<Description>A Night to Remember</Description>
<Description>The Unbearable Lightness Of Being</Description>
<Description>Sisters</Description>
1 row selected.
SQLを使用してテキスト・ノードのコンテンツを処理するために、SQL/XML関数XMLTableを使用してDescriptionノードのコレクションを仮想表に変換します。この仮想表には3つの行があり、単一のDescription要素を持つ単一のXMLTypeインスタンスが各行に含まれています。
SELECT des.COLUMN_VALUE
FROM purchaseorder p,
XMLTable('/PurchaseOrder/LineItems/LineItem/Description'
PASSING p.OBJECT_VALUE) des
WHERE existsNode(p.OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
COLUMN_VALUE
------------------------------------------------------------
<Description>A Night to Remember</Description>
<Description>The Unbearable Lightness Of Being</Description>
<Description>Sisters</Description>
3 rows selected.
関数XMLTableには、目的のDescription要素を対象とするXPath式が渡されます。PASSING句により、XMLTableでは、XPath式を評価するためのコンテキストとして、XMLType表purchaseorderのコンテンツ(OBJECT_VALUE)を使用します。
つまり、XMLTable式はpurchaseorder表に依存します。これは、左側結合です。この相関結合によって、アクセスされるpurchaseorder行と、XMLTableによってその行から生成される行は、1対多(1:N)の関係であることが保証されます。この相関結合により、purchaseorder表は、FROMリストのXMLTable式よりも前に記述する必要があります。これは、PASSING句が表の列を参照する場合に一般的な要件です。
仮想表の各XMLTypeインスタンスには、それぞれ1つのDescription要素が含まれるため、SQL関数extractValueを使用して、各Description要素に関連付けられたテキスト・ノードの値にアクセスできます。
SELECT extractValue(des.COLUMN_VALUE, '/Description') FROM purchaseorder p, XMLTable('/PurchaseOrder/LineItems/LineItem/Description' PASSING p.OBJECT_VALUE) des WHERE existsNode(p.OBJECT_VALUE, '/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1; EXTRACTVALUE(DES.COLUMN_VALUE,'/DESCRIPTION') --------------------------------------------- A Night to Remember The Unbearable Lightness Of Being Sisters 3 rows selected.
XMLTableのCOLUMNS句を使用してDescription要素をdescriptionという列に分割すると、extractValueを使用せずにこれと同等の機能を実行でき、問合せが読みやすくなります。
SELECT des.description FROM purchaseorder p, XMLTable('/PurchaseOrder/LineItems/LineItem' PASSING p.OBJECT_VALUE COLUMNS description VARCHAR2(256) PATH 'Description') des WHERE existsNode(p.OBJECT_VALUE, '/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1; DESCRIPTION --------------------------------- A Night to Remember The Unbearable Lightness Of Being Sisters 3 rows selected.
このCOLUMNS句により、XMLTableでは、XPath式'Description'の対象のデータを、SQLデータ型VARCHAR2(256)のdescriptionという列に分割します。この列を定義している'Description'式は、コンテキストXPath式'/PurchaseOrder/LineItems/LineItem'に相対的です。
この例では、単一の列(description)のみを使用しているため、読みやすさはあまり変わりません。しかし、XMLTypeインスタンスの複数の部分へのアクセスに複数のXPath式を使用する場合は、extractValueではなくCOLUMNS句を使用すると、読みやすさが大幅に向上します。この例は、例3-32を参照してください。
COLUMNS句を使用すると、問合せが読みやすくなるのに加え、SQLデータ型をより詳しく指定できるため、静的型チェックがより便利になります。
XMLType表に複数レベルで含まれているデータをリレーショナル・ビューの個別の行として公開する必要がある場合は、分割してリレーショナル列に格納する必要がある各文書レベルにXMLTableを適用します。この例は、例3-32を参照してください。
例3-26 XMLTABLEを使用したコレクション内の要素数のカウント
この例では、コレクション内の要素数をカウントします。また、ORDER BYやGROUP BYなどのSQLキーワードをSQL関数XMLTableによって作成された仮想表データに適用する方法も示しています。
この例の問合せでは、最初に、SQL関数existsNodeへのXPath引数と一致する一連のXML文書が検索されます。次に、選択された文書ごとに、一連のLineItemノードが含まれる仮想表が生成されます。最後に、PurchaseOrder文書ごとにLineItemノードの数がカウントされます。相関結合によって、GROUP BYはLineItem要素が属するPurchaseOrder要素を正しく判別できます。
SELECT extractValue(p.OBJECT_VALUE, '/PurchaseOrder/Reference'), count(*)
FROM purchaseorder p,
XMLTable('/PurchaseOrder/LineItems/LineItem' PASSING p.OBJECT_VALUE)
WHERE existsNode(p.OBJECT_VALUE, '/PurchaseOrder[User="SBELL"]') = 1
GROUP BY extractValue(p.OBJECT_VALUE, '/PurchaseOrder/Reference')
ORDER BY extractValue(p.OBJECT_VALUE, '/PurchaseOrder/Reference');
EXTRACTVALUE(P.OBJECT_VALUE,'/ COUNT(*)
------------------------------ --------
SBELL-20021009123335280PDT 20
SBELL-20021009123335771PDT 21
SBELL-2002100912333601PDT 3
SBELL-20021009123336231PDT 25
SBELL-20021009123336331PDT 10
SBELL-20021009123336362PDT 15
SBELL-20021009123336532PDT 14
SBELL-20021009123337353PDT 10
SBELL-2002100912333763PDT 21
SBELL-20021009123337673PDT 10
SBELL-20021009123338204PDT 14
SBELL-20021009123338304PDT 24
SBELL-20021009123338505PDT 20
13 rows selected.
例3-27 XMLTABLEを使用した要素内の子要素数のカウント
この例では、SQL関数XMLTableを使用して、指定された要素の子要素の数をカウントする方法を示します。XMLTableに渡されるXPath式には、PurchaseOrder要素の直接の子孫である全要素と一致するワイルド・カード(*)が含まれます。XMLTableで作成された仮想表の各行には、XPath式と一致するノードが含まれます。仮想表内の行数をカウントすることによって、要素PurchaseOrderの子要素の数が判明します。
SELECT count(*)
FROM purchaseorder p, XMLTable('/PurchaseOrder/*' PASSING p.OBJECT_VALUE)
WHERE existsNode(p.OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
COUNT(*)
----------
9
1 row selected.
SQL/XML標準関数XMLExistsは、指定された文書にW3CのXPath式と一致するノードが含まれているかどうかを評価します。関数XMLExistsは、関数に指定されたXPath式によって指定されたノードが文書に含まれている場合はブール値のtrueを、そうでない場合はfalseの値を戻します。XPath式には述語を含めることができるため、XMLExistsは、指定されたノードが文書内に存在するかどうか、および指定された値を持つノードが文書内に存在するかどうかを判断できます。また、SQL/XML関数XMLExistsによって提供される機能に類似した機能は、Oracle SQL関数existsNodeおよびXMLTypeメソッドexistsNode()を介しても使用できます。
例3-28 XMLExistsを使用したXMLコンテンツの検索
この問合せでは、SQL/XML関数XMLExistsを使用して、ルート要素PurchaseOrderの子であるReferenceという要素がXML文書に含まれているかどうかを確認します。
SELECT count(*) FROM purchaseorder
WHERE XMLExists('$p/PurchaseOrder/Reference' PASSING OBJECT_VALUE AS "p");
COUNT(*)
----------
132
1 row selected.
この問合せでは、Reference要素に関連付けられたテキスト・ノードの値がSBELL-2002100912333601PDTであるかどうかを確認します。
SELECT count(*) FROM purchaseorder
WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
PASSING OBJECT_VALUE AS "p");
COUNT(*)
----------
1
1 row selected.
この問合せでは、Reference要素に関連付けられたテキスト・ノードの値がSBELL-XXXXXXXXXXXXXXXXXXであるかどうかを確認します。
SELECT count(*) FROM purchaseorder
WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-XXXXXXXXXXXXXXXXXX"]'
PASSING OBJECT_VALUE AS "p");
COUNT(*)
----------
0
1 row selected.
この問合せでは、XML文書にルート要素PurchaseOrderが含まれているかどうかを確認します。このルート要素に含まれるLineItems要素にはLineItem要素が含まれ、さらにこの要素にはId属性を持つPart要素が含まれている必要があります。
SELECT count(*) FROM purchaseorder
WHERE XMLExists('$p/PurchaseOrder/LineItems/LineItem/Part/@Id'
PASSING OBJECT_VALUE AS "p");
COUNT(*)
----------
132
1 row selected.
この問合せでは、XML文書にルート要素PurchaseOrderが含まれているかどうかを確認します。このルート要素に含まれるLineItems要素にはLineItem要素が含まれ、さらにこの要素にはId属性値が715515009058のPart要素が含まれている必要があります。
SELECT count(*) FROM purchaseorder
WHERE XMLExists('$p/PurchaseOrder/LineItems/LineItem/Part[@Id="715515009058"]'
PASSING OBJECT_VALUE AS "p");
COUNT(*)
----------
21
この問合せでは、XML文書にルート要素PurchaseOrderが含まれているかどうかを確認します。このルート要素に含まれるLineItems要素にはLineItem要素が含まれ、さらにこの要素の3番目のLineItem要素にはId属性値が715515009058のPart要素が含まれている必要があります。
SELECT count(*) FROM purchaseorder
WHERE XMLExists(
'$p/PurchaseOrder/LineItems/LineItem[3]/Part[@Id="715515009058"]'
PASSING OBJECT_VALUE AS "p");
COUNT(*)
----------
1
1 row selected.
この問合せは、User要素に関連付けられたテキスト・ノードが文字Sで始まる行のみをSELECT文の結果として戻します。XPath 1.0では、LIKEを使用した問合せをサポートしていません。
SELECT XMLCast(XMLQuery('$p/PurchaseOrder/Reference' PASSING OBJECT_VALUE AS "p"
RETURNING CONTENT)
AS VARCHAR2(30))
FROM purchaseorder
WHERE XMLCast(XMLQuery('$p/PurchaseOrder/User' PASSING OBJECT_VALUE AS "p"
RETURNING CONTENT)
AS VARCHAR2(30))
LIKE 'S%';
XMLCAST(XMLQUERY('$P/PURCHASEORDER
----------------------------------
SBELL-20021009123336231PDT
SBELL-20021009123336331PDT
SKING-20021009123336321PDT
...
36 rows selected.
この問合せは、XML文書内のノードの値と別の表のデータに基づいて結合を実行します。
SELECT XMLCast(XMLQuery('$p/PurchaseOrder/Reference' PASSING OBJECT_VALUE AS "p"
RETURNING CONTENT)
AS VARCHAR2(30))
FROM purchaseorder p, hr.employees e
WHERE XMLCast(XMLQuery('$p/PurchaseOrder/User' PASSING OBJECT_VALUE AS "p"
RETURNING CONTENT)
AS VARCHAR2(30)) = e.email
AND e.employee_id = 100;
XMLCAST(XMLQUERY('$P/PURCHASEOREDER
-----------------------------------
SKING-20021009123336321PDT
SKING-20021009123337153PDT
SKING-20021009123335560PDT
SKING-20021009123336952PDT
SKING-20021009123336622PDT
SKING-20021009123336822PDT
SKING-20021009123336131PDT
SKING-20021009123336392PDT
SKING-20021009123337974PDT
SKING-20021009123338294PDT
SKING-20021009123337703PDT
SKING-20021009123337383PDT
SKING-20021009123337503PDT
13 rows selected.
|
関連項目:
|
前の項の例では、SQL/XML関数XMLExistsをSELECTリスト内で使用して、XML文書に含まれる情報を戻す方法を示しました。XMLExistsをWHERE句で使用して、SELECT、UPDATEまたはDELETE文の結果セットに文書を含めるかどうかを決定することもできます。
例3-29では、XMLExistsを使用して、結果セットを、XPath式と一致するノードが含まれる文書に制限する方法を示します。
例3-29 WHERE句でXMLExistsを使用したSELECTの結果の制限
この問合せは、User要素に関連付けられたテキスト・ノードに値SBELLが含まれる行のみをSELECT文の結果として戻します。
SELECT XMLCast(XMLQuery('$p/PurchaseOrder/Reference' PASSING OBJECT_VALUE AS "p"
RETURNING CONTENT)
AS VARCHAR2(30)) "Reference"
FROM purchaseorder
WHERE XMLExists('$p/PurchaseOrder[User="SBELL"]' PASSING OBJECT_VALUE AS "p");
Reference
------------------------------
SBELL-20021009123336231PDT
SBELL-20021009123336331PDT
SBELL-20021009123337353PDT
SBELL-20021009123338304PDT
SBELL-20021009123338505PDT
SBELL-20021009123335771PDT
SBELL-20021009123335280PDT
SBELL-2002100912333763PDT
SBELL-2002100912333601PDT
SBELL-20021009123336362PDT
SBELL-20021009123336532PDT
SBELL-20021009123338204PDT
SBELL-20021009123337673PDT
13 rows selected.
例3-30 XMLQueryとXMLExistsを使用したPurchaseOrderのReferenceの検索
この例では、SQL/XML関数XMLQueryとXMLExistsを使用して、最初のLineItem要素にId 715515009058の品目の発注が含まれるPurchaseOrder要素についてReferenceを検索します。関数XMLExistsをWHERE句で使用して、選択する行を決定します。さらに、XMLQueryをSELECTリスト内で使用して、選択した文書のどの部分を結果に表示するかを制御します。
SELECT XMLCast(XMLQuery('$p/PurchaseOrder/Reference' PASSING OBJECT_VALUE AS "p"
RETURNING CONTENT)
AS VARCHAR2(30)) "Reference"
FROM purchaseorder
WHERE XMLExists('$p/PurchaseOrder/LineItems/LineItem[1]/Part[@Id="715515009058"]'
PASSING OBJECT_VALUE AS "p");
Reference
-------------------------
SBELL-2002100912333601PDT
1 row selected.
|
関連項目:
|
Oracle XML DBで提供されるXML固有の関数およびメソッドを使用すると、XMLコンテンツへのリレーショナル・アクセスを提供する従来のリレーショナル・ビューを作成できます。これによって、Oracle Databaseには対処していてもXMLには対処していないプログラマ、ツールおよびアプリケーションでも、データベースに格納されたXMLコンテンツを操作できます。
リレーショナル・ビューでは、XPath式とextractValueやXMLTableなどのSQL関数を使用して、ビュー内の列とXML文書内のノードとの間のマッピングを定義します。XML文書が、CLOBインスタンスとしてではなく、構造化(オブジェクト・リレーショナル)XML記憶域またはバイナリXML記憶域を使用して格納されている場合のみ、パフォーマンス上の理由からこの方法をお薦めします。
|
関連項目:
|
XMLType表内の各文書をリレーショナル・ビューの行として公開する必要がある場合は、次の方法を使用できます。
CREATE OR REPLACE VIEWを使用して、ビューを構成する一連の列を定義します。
XML文書内のノードを、ビューで定義されている列にマップします。このためには、SQL関数extractValueを適切なXPath式とともに使用して、ノードを抽出します。
この方法は、XMLType表内の文書とビュー内の行が1対1(1:1)関係の場合はいつでも使用できます。
例3-31 XMLコンテンツのリレーショナル・ビューの作成
この例では、XMLコンテンツを公開する簡単なリレーショナル・ビューの作成方法を示します。
CREATE OR REPLACE VIEW
purchaseorder_master_view(reference, requestor, userid, costcenter,
ship_to_name, ship_to_address, ship_to_phone,
instructions)
AS SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/Reference'),
extractValue(OBJECT_VALUE, '/PurchaseOrder/Requestor'),
extractValue(OBJECT_VALUE, '/PurchaseOrder/User'),
extractValue(OBJECT_VALUE, '/PurchaseOrder/CostCenter'),
extractValue(OBJECT_VALUE,
'/PurchaseOrder/ShippingInstructions/name'),
extractValue(OBJECT_VALUE,
'/PurchaseOrder/ShippingInstructions/address'),
extractValue(OBJECT_VALUE,
'/PurchaseOrder/ShippingInstructions/telephone'),
extractValue(OBJECT_VALUE, '/PurchaseOrder/SpecialInstructions')
FROM purchaseorder;
View created.
DESCRIBE purchaseorder_master_view
Name Null? Type
--------------------------------------------
REFERENCE VARCHAR2(30 CHAR)
REQUESTOR VARCHAR2(128 CHAR)
USERID VARCHAR2(10 CHAR)
COSTCENTER VARCHAR2(4 CHAR)
SHIP_TO_NAME VARCHAR2(20 CHAR)
SHIP_TO_ADDRESS VARCHAR2(256 CHAR)
SHIP_TO_PHONE VARCHAR2(24 CHAR)
INSTRUCTIONS VARCHAR2(2048 CHAR)
この例では、リレーショナル・ビューpurchaseorder_master_viewが作成されます。このビューには、表purchaseorderの行ごとに1つの行が含まれます。
XMLType表に複数レベルで含まれているデータをリレーショナル・ビューの個別の行として公開する必要がある場合は、単一レベルの分割と同じ一般的な方法を使用し、1)ビューを構成する列の定義、および、2)列へのXMLノードのマップを行います。ただし、この場合は、分割してリレーショナル列に格納する必要がある各文書レベルにSQL/XML標準関数XMLTableを適用することをお薦めします。
この方法は、XMLType表内の文書とビュー内の行が1対他(1:N)関係の場合はいつでも使用できます。
たとえば、各PurchaseOrder要素にLineItems要素が含まれていて、この要素に1つ以上のLineItem要素が含まれているとします。各LineItem要素には、DescriptionやItemNumber属性などの子要素があります。このような下位レベルのデータをリレーショナル値としてアクセス可能にするには、PurchaseOrder要素とLineItemコレクションの両方を分割する必要があります。この分割は、いずれもXMLTableを使用して行われます。要素PurchaseOrderを分割すると、LineItem要素は、XMLフラグメントが含まれている型XMLTypeのリレーショナル列にマップされます。この列は次に、XMLTypeへの2回目のコールに渡され、リレーショナル値の複数の行として複数の部分に分割されます。例3-32を参照してください。
例3-32 ビューを使用したコレクションの各メンバーへのアクセス
この例では、XMLType表purchaseorder内の文書とビューの行の間に1対多(1:N)関係がある場合の、SQL関数XMLTableの使用方法を示します。このビューは、コレクションの各メンバーへのアクセスを提供し、コレクションのメンバーを行セットとして公開します。
CREATE OR REPLACE VIEW purchaseorder_detail_view AS
SELECT po.reference, li.*
FROM purchaseorder p,
XMLTable('/PurchaseOrder' PASSING p.OBJECT_VALUE
COLUMNS
reference VARCHAR2(30) PATH 'Reference',
lineitem XMLType PATH 'LineItems/LineItem') po,
XMLTable('LineItem' PASSING po.lineitem
COLUMNS
itemno NUMBER(38) PATH '@ItemNumber',
description VARCHAR2(256) PATH 'Description',
partno VARCHAR2(14) PATH 'Part/@Id',
quantity NUMBER(12, 2) PATH 'Part/@Quantity',
unitprice NUMBER(8, 4) PATH 'Part/@UnitPrice') li;
View created.
DESCRIBE purchaseorder_detail_view
Name Null? Type
----------------------------
REFERENCE VARCHAR2(30 CHAR)
ITEMNO NUMBER(38)
DESCRIPTION VARCHAR2(256 CHAR)
PARTNO VARCHAR2(14 CHAR)
QUANTITY NUMBER(12,2)
UNITPRICE NUMBER(8,4)
ビューpurchaseorder_detail_viewの各行は、XMLType表purchaseorderに格納されているXML文書内の各LineItem要素に対応しています。
CREATE OR REPLACE VIEW文では、ビューを構成する一連の列を定義します。SELECT文は、コンテキストとしてpurchaseorder表を関数XMLTableに渡し、仮想表pを作成します。この表には、列referenceおよびlineitemがあります。これらの列には、発注書のReference要素およびLineItem要素がそれぞれ含まれます。
列lineitemにはLineItem要素のコレクションがXMLTypeインスタンスとして含まれ、各行が各LineItem要素に対応します。これらの行は次に、2つ目のXMLTable式に渡され、そのコンテキストとして機能します。この2つ目のXMLTable式により、明細/項目行の仮想表が作成され、各列が要素LineItemの様々な子孫ノードに対応します。これらの子孫の大半は属性(ItemNumberやPart/@Idなど)であり、そのうちの1つはDescription子要素です。
Reference要素は、ビューpurchaseorder_detail_viewに列referenceとして含まれます。この要素は、ビューpurchaseorder_detail_viewの行をビューpurchaseorder_master_viewの対応する行に結合する際に使用できる外部キーを提供します。CREATE VIEW文の相関結合によって、ビューにアクセスするたびに、Reference要素と関連するLineItem要素との間の1対多(1:N)関係が保持されます。
この項の例では、XMLデータのリレーショナル問合せについて説明します。これらの例では、XMLType表および列に対してリレーショナル・ビューを作成するメリットをいくつか示します。
例3-33 ビューを使用したXMLコンテンツでのSQL問合せ
この例では、マスター・ビューに対する簡単な問合せを使用します。従来のSELECT文により、userid列がSで始まる行を選択します。
SELECT reference, costcenter, ship_to_name FROM purchaseorder_master_view WHERE userid LIKE 'S%'; REFERENCE COST SHIP_TO_NAME ------------------------------ ---- -------------- SBELL-20021009123336231PDT S30 Sarah J. Bell SBELL-20021009123336331PDT S30 Sarah J. Bell SKING-20021009123336321PDT A10 Steven A. King ... 36 rows selected.
次の問合せは、マスター・ビューと詳細ビューの結合に基づいています。従来のSELECT文により、itemno列の値が1で、対応するpurchaseorder_master_viewの行に値が SBELLのuserid列が含まれているpurchaseorder_detail_viewの行を検索します。
SELECT d.reference, d.itemno, d.partno, d.description
FROM purchaseorder_detail_view d, purchaseorder_master_view m
WHERE m.reference = d.reference
AND m.userid = 'SBELL'
AND d.itemno = 1;
REFERENCE ITEMNO PARTNO DESCRIPTION
------------------------------ ------------------------------------------------
SBELL-20021009123336231PDT 1 37429165829 Juliet of the Spirits
SBELL-20021009123336331PDT 1 715515009225 Salo
SBELL-20021009123337353PDT 1 37429141625 The Third Man
SBELL-20021009123338304PDT 1 715515009829 Nanook of the North
SBELL-20021009123338505PDT 1 37429122228 The 400 Blows
SBELL-20021009123335771PDT 1 37429139028 And the Ship Sails on
SBELL-20021009123335280PDT 1 715515011426 All That Heaven Allows
SBELL-2002100912333763PDT 1 715515010320 Life of Brian - Python
SBELL-2002100912333601PDT 1 715515009058 A Night to Remember
SBELL-20021009123336362PDT 1 715515012928 In the Mood for Love
SBELL-20021009123336532PDT 1 37429162422 Wild Strawberries
SBELL-20021009123338204PDT 1 37429168820 Red Beard
SBELL-20021009123337673PDT 1 37429156322 Cries and Whispers
13 rows selected.
ビューの外観と動作は標準のリレーショナル・ビューと同様であるため、標準のリレーショナル構文を使用してビューを問合せできます。問合せまたは生成される結果セットでは、XML固有の構文は必要ありません。
XMLコンテンツをリレーショナル・データとして公開することによって、Oracle XML DBでは、ビジネス・インテリジェンスや分析機能などの高度なデータベース機能をXMLコンテンツに適用できます。ビジネス・インテリジェンス機能自体はXMLを認識しませんが、Oracle XML DBで提供されるXMLとSQLの双対性によって、これらの機能をXMLコンテンツに適用できます。
例3-34 XMLコンテンツのビューを使用したXMLの問合せ
この例では、XMLコンテンツのリレーショナル・ビューを使用して、XML文書のビジネス・インテリジェンス問合せを実行する方法を示します。この問合せは、タイトルがUPCコード715515009058および715515009126で識別される発注を含むPurchaseOrder文書を選択します。
SELECT partno, count(*) "No of Orders", quantity "No of Copies"
FROM purchaseorder_detail_view
WHERE partno IN (715515009126, 715515009058)
GROUP BY rollup(partno, quantity);
PARTNO No of Orders No of Copies
-------------- ------------ ------------
715515009058 7 1
715515009058 9 2
715515009058 5 3
715515009058 2 4
715515009058 23
715515009126 4 1
715515009126 7 3
715515009126 11
34
9 rows selected.
この問合せは、PurchaseOrder文書ごとに、発注された各タイトルのコピー数を判別します。部品番号715515009126には、発注された品目のコピー数が1のPurchaseOrder文書は4つあり、発注された品目のコピー数が3のPurchaseOrder文書は7つあります。
Oracle XML DBでは、XMLコンテンツに対する更新操作を実行できます。更新操作では、文書のコンテンツ全体を置換することも、文書の一部を置換することもできます。XML文書を部分的に更新する機能は非常に強力で、特に大規模な文書に対して小規模な更新を行う場合に役立ちます。この機能によって、更新の実行に必要なネットワーク通信量とディスク入出力を大幅に削減できます。
SQL関数updateXMLを使用すると、XMLTypeインスタンスとして格納されたXML文書の部分更新を実行できます。これによって、1回の操作で、文書に対する複数の変更を実行できます。各変更は、更新するノードを識別するXPath式とそのノードの新しい値で構成されます。
例3-35 UPDATEXMLを使用したXMLコンテンツの更新
この例では、SQL関数updateXMLを使用して、User要素に関連付けられたテキスト・ノードの値を更新します。
SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/User')
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
EXTRACTVAL
----------
SBELL
1 row selected.
UPDATE purchaseorder
SET OBJECT_VALUE =
updateXML(OBJECT_VALUE, '/PurchaseOrder/User/text()','SKING')
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
1 row updated.
SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/User')
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
EXTRACTVAL
----------
SKING
1 row selected.
例3-36 UPDATEXMLを使用した要素全体の置換
この例では、SQL関数updateXMLを使用して、XML文書内の要素全体を置換します。XPath式によって要素が参照され、置換値はXMLTypeオブジェクトとして渡されます。
SELECT extract(OBJECT_VALUE, '/PurchaseOrder/LineItems/LineItem[1]')
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
EXTRACT(OBJECT_VALUE,'/PURCHASEORDER/LINEITEMS/LINEITEM[1]')
------------------------------------------------------------
<LineItem ItemNumber="1">
<Description>A Night to Remember</Description>
<Part Id="715515009058" UnitPrice="39.95" Quantity="2"/>
</LineItem>
1 row selected.
UPDATE purchaseorder
SET OBJECT_VALUE =
updateXML(
OBJECT_VALUE,
'/PurchaseOrder/LineItems/LineItem[1]',
XMLType('<LineItem ItemNumber="1">
<Description>The Lady Vanishes</Description>
<Part Id="37429122129" UnitPrice="39.95" Quantity="1"/>
</LineItem>'))
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
1 row updated.
SELECT extract(OBJECT_VALUE, '/PurchaseOrder/LineItems/LineItem[1]')
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
EXTRACT(OBJECT_VALUE, '/PURCHASEORDER/LINEITEMS/LINEITEM[1]')
-------------------------------------------------------------
<LineItem ItemNumber="1">
<Description>The Lady Vanishes</Description>
<Part Id="37429122129" UnitPrice="39.95" Quantity="1"/>
</LineItem>
1 row selected.
例3-37 コレクション内で複数回出現するノードの間違った更新
この例では、コレクション内で複数回出現するノードを、SQL関数updateXMLを使用して更新する際に発生する一般的なエラーを示します。UPDATE文を使用して、Description要素のテキスト・ノードの値を"The Wizard of Oz"に設定します。テキスト・ノードの現在の値は"Sisters"です。この文のWHERE句にはexistsNode式が含まれ、更新する一連のノードを識別します。
SELECT extractValue(des.COLUMN_VALUE, '/Description')
FROM purchaseorder p,
XMLTable('/PurchaseOrder/LineItems/LineItem/Description'
PASSING p.OBJECT_VALUE) des
WHERE existsNode(p.OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
EXTRACTVALUE(DES.COLUMN_VALUE,'/DESCRIPTION')
---------------------------------------------
The Lady Vanishes
The Unbearable Lightness Of Being
Sisters
3 rows selected.
UPDATE purchaseorder p
SET p.OBJECT_VALUE =
updateXML(p.OBJECT_VALUE,
'/PurchaseOrder/LineItems/LineItem/Description/text()',
'The Wizard of Oz')
WHERE existsNode(p.OBJECT_VALUE,
'/PurchaseOrder/LineItems/LineItem[Description="Sisters"]')
= 1
AND existsNode(p.OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
1 row updated.
SELECT extractValue(des.COLUMN_VALUE, '/Description')
FROM purchaseorder p,
XMLTable('/PurchaseOrder/LineItems/LineItem/Description'
PASSING p.OBJECT_VALUE) des
WHERE existsNode(p.OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
EXTRACTVALUE(DES.COLUMN_VALUE,'/DESCRIPTION')
---------------------------------------------
The Wizard of Oz
The Wizard of Oz
The Wizard of Oz
3 rows selected.
SQL関数updateXMLは、必要なノードを更新するのではなく、Description要素に属するすべてのテキスト・ノードの値を更新します。これは正しい動作ですが、意図していたものではありません。WHERE句は、更新が必要な文書を識別するためにのみ使用でき、その文書内で更新が必要なノードの識別には使用できません。
文書が選択されると、updateXMLに渡されるXPath式によって、文書内で更新が必要なノードが判別されます。この例では、XPath式によって3つすべてのDescriptionノードが識別されるため、関連する3つのテキスト・ノードすべてが更新されています。ノードの正しい更新方法は、例3-38を参照してください。
例3-38 コレクション内で複数回出現するノードの正しい更新
SQL関数updateXMLを正しく使用してコレクション内で複数回出現するノードを更新するには、updateXMLに渡されるXPath式を使用して、XML文書内の更新対象のノードを識別します。XPath式に適切な述語を設定することによって、文書内の更新対象のノードを限定できます。この例では、コレクション内の1つのノードを更新する正しい方法を示します。
SELECT extractValue(des.COLUMN_VALUE, '/Description')
FROM purchaseorder p,
XMLTable('/PurchaseOrder/LineItems/LineItem/Description'
PASSING p.OBJECT_VALUE) des
WHERE existsNode(p.OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
EXTRACTVALUE(P.OBJECT_VALUE,'/DESCRIPTION')
-------------------------------------------
A Night to Remember
The Unbearable Lightness Of Being
Sisters
3 rows selected.
UPDATE purchaseorder p
SET p.OBJECT_VALUE =
updateXML(
p.OBJECT_VALUE,
'/PurchaseOrder/LineItems/LineItem/Description[text()="Sisters"]/text()',
'The Wizard of Oz')
WHERE existsNode(p.OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')
= 1;
1 row updated.
SELECT extractValue(des.COLUMN_VALUE, '/Description')
FROM purchaseorder p,
XMLTable('/PurchaseOrder/LineItems/LineItem/Description'
PASSING p.OBJECT_VALUE) des
WHERE existsNode(p.OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;
EXTRACTVALUE(DES.COLUMN_VALUE,'/DESCRIPTION')
---------------------------------------------
A Night to Remember
The Unbearable Lightness Of Being
The Wizard of Oz
3 rows selected.
例3-39 UPDATEXMLを使用したテキスト・ノード値の変更
SQL関数updateXMLを使用すると、文書に対する複数の変更を1つの文で実行できます。この例では、User要素およびSpecialInstructions要素に属するテキスト・ノードの値を1つの文で変更する方法を示します。
SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/CostCenter') "Cost Center",
extractValue(OBJECT_VALUE,
'/PurchaseOrder/SpecialInstructions') "Instructions"
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;
Cost Center Instructions
------------ ------------
S30 Air Mail
1 row selected.
この単一のUPDATE SQL文により、User要素およびSpecialInstructions要素のテキスト・ノード値が変更されます。
UPDATE purchaseorder
SET OBJECT_VALUE =
updateXML(OBJECT_VALUE,
'/PurchaseOrder/CostCenter/text()',
'B40',
'/PurchaseOrder/SpecialInstructions/text()',
'Priority Overnight Service')
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;
1 row updated.
SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/CostCenter') "Cost Center",
extractValue(OBJECT_VALUE,
'/PurchaseOrder/SpecialInstructions') "Instructions"
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE,
'/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;
Cost Center Instructions
------------ --------------------------
B40 Priority Overnight Service
1 row selected.
updateXMLなどのSQL関数がXML文書を変更する方法は、XML文書の格納方法と、XML Schemaに基づいているかどうかにより異なります。
CLOB値で格納されたXML文書: CLOBとして格納されたXML Schemaに基づくXML文書または基づかないXML文書をupdateXMLなどのSQL関数で更新すると、Oracle XML DBは、その文書からドキュメント・オブジェクト・モデル(DOM)を作成し、DOM APIメソッドを使用して適切なXMLデータを更新することで、更新を実行します。更新後、更新されたDOMは基礎となるCLOB値に戻されます。
オブジェクト・リレーショナル形式で格納されたXML文書: オブジェクト・リレーショナル形式で格納されたXML Schemaに基づくXML文書をupdateXMLなどのSQL関数で更新すると、Oracle XML DBはXPathリライトを使用して、基礎となるオブジェクトのインプレース更新を実行できます。これは部分更新で、SQL関数へのXPath引数が同等のSQL操作に変換されます。すると、SQL操作によって基礎となるオブジェクトの属性が直接更新されます。このような部分更新は、DOMベースの更新よりもはるかに短時間で実行できます。このため、updateXMLなどのSQL関数を多数の文書に適用するSQLコードを実行すると、処理速度を大幅に改善できる場合があります。
バイナリXMLとして格納されたXML文書: SQL関数updateXMLをバイナリXML列で使用すると、Oracle XML DBは、通常、DOMを構築する必要はありません。文書中で更新が必要とされる正確な部分は、ストリーミングやXMLIndexなどの問合せ評価方法を使用して計算されます。更新されたデータは、最初の変更の発生箇所以降のみが、ディスクに書き込まれます。それ以前の変更はすべて変更されません。また、データの格納にSECUREFILE LOBが使用される場合、変更はスライド方式で適用され、残りのLOBのリライトは行われません。つまり、バイナリXMLデータのSECUREFILE LOB記憶域では、実際に変更されたデータのみが更新されます。この方法では、非構造化記憶域と比較して、パフォーマンスを大幅に向上できます。これらの最適化は、XML Schemaに基づかないデータと基づくデータの両方に適用されます。
名前空間のサポートは、W3CのXML勧告の主要な特徴です。Oracle XML DBでは、W3Cの名前空間勧告を完全にサポートしています。XMLTypeメソッドおよびXML固有のSQL関数はすべて、名前空間接頭辞を含むXPath式で使用できます。XPath式で使用する名前空間接頭辞を正しく解決するために、すべてのメソッドおよび関数は、名前空間宣言を指定するオプションのnamespace引数を受け入れます。指定されたXPath式に名前空間接頭辞が含まれている場合は、常にnamespaceパラメータが必要です。パラメータnamespaceが指定されている場合は、デフォルトの名前空間がnoNamespace名前空間でないかぎり、このパラメータでデフォルトの名前空間と接頭辞付き名前空間を明示的に宣言する必要があります。パラメータnamespaceが指定されていない場合、Oracle XML DBでは、XPath式に関して次のことを前提とします。
XMLTypeインスタンスのコンテンツが登録済のXML Schemaに基づいていない場合、名前空間接頭辞を含むXPath式内の要素はすべて、noNamespace名前空間に存在すると想定されます。
XMLTypeのコンテンツが登録済のXML Schemaに基づいている場合、名前空間接頭辞を含まないXPath式内の要素はすべて、XML Schemaで宣言されたtargetNamespaceがあれば、その名前空間に存在すると想定されます。XML Schemaでtargetnamespaceが宣言されていない場合は、名前noNamespaceが使用されます。
XPath式の解決に必要な名前空間を正しく定義しないと、XPathを使用した操作が予測どおりに機能しません。名前空間宣言が不適切または欠落している場合、操作の結果はエラーではなくNULLになります。混同を避けるため、noNamespace以外の名前空間がXPath式またはターゲットのXML文書に存在する場合は、常に、デフォルトの名前空間の宣言を含む一連の名前空間宣言をすべて渡してください。
Oracle XML DBは、DOMベースまたはSQLベースの方法を使用して、extract、extractValue、existsNodeなどのSQL関数、およびそれらと同等のXMLTypeメソッドを処理します。
DOMベースのXMLType処理: Oracle XML DBは、XMLTypeオブジェクトのコンテンツからDOMを構成して必要な処理を実行します。また、DOM APIによって提供されるメソッドを使用して、DOMで必要な操作を実行します。DOMツリーの更新を含む操作を実行する場合は、操作の完了時にXML文書全体をディスクに再書込みする必要があります。XMLTypeデータに対してDOMベースの操作を使用する処理は、機能上の評価と呼ばれます。
機能上の評価のメリットは、記憶域モデル(構造化、バイナリまたは非構造化)に関係なく、XMLTypeインスタンスに使用できることです。機能上の評価のデメリットは、XPathのリライトに比べてコストがかかるため、多数のXML文書間でのスケーラビリティがないことです。
SQLベースのXMLType処理: Oracle XML DBは、関数またはメソッドの完了に必要な処理を実行するSQL文を構成します。SQL文は、XML Schemaに基づくXMLTypeの基礎となるオブジェクト・リレーショナル・データ構造に対して直接機能します。このプロセスは、XPathリライトと呼ばれます。第7章「XPathリライト」を参照してください。
XPathのリライトのメリットは、Oracle XML DBによって、XPathを使用したSQL関数およびメソッドをリレーショナルSQL文とほぼ同じ速度で評価できることです。これによって、操作では多数のXML文書の間でスケーラビリティを持つことができます。XPathのリライトのデメリットは、XML文書を格納するために使用するオブジェクトに直接アクセスして更新するため、XPathのリライトを使用できるのは、XML Schemaに基づくオブジェクト・リレーショナル記憶域を使用してXMLTypeインスタンスを格納した場合のみであることです。
バイナリXMLデータのストリーム式の評価: バイナリXMLを記憶域モデルとして使用する場合、XMLQuery、XMLTable、XMLExists、XMLCast、extract、extractValueなどのSQL関数で使用されるXPath式は、DOMの構築に依存せずに、ストリーム方式で評価されます。
XPathリライトによって、XPathを使用した関数が従来のリレーショナルSQL文に変換されるため、その関数が含まれるSQL文のパフォーマンスが向上します。これにより、データベース・オプティマイザがXPath表記法やXMLデータ・モデルを認識する必要がなくなります。データベース・オプティマイザは、リライトされたSQL文を他のSQL文と同じ方法で処理します。このように、データベース・オプティマイザは従来の関係代数に基づいて実行計画を導出できます。その結果、XPathを使用した関数を含むSQL文がリレーショナルSQL文とほぼ同じパフォーマンスで実行されます。
XPathのリライトを実行するには、次の条件を満たす必要があります。
XMLType列または表は、構造化(オブジェクト・リレーショナル)記憶域を使用して格納されていること
XML文書を含むXMLType列または表が登録済のXML Schemaに基づいていること
XPath式で参照されるノードを、基礎となるSQLオブジェクト・モデルの属性にマップできること
十分なレベルのスケーラビリティとパフォーマンスを実現するOracle XML DBアプリケーションを開発するには、XPathのリライトの概念、およびXPathのリライトを実行するための条件を理解することが重要です。
XPathリライトそれ自体が、アプリケーションのスケーラビリティやパフォーマンスを保証するわけではありません。XPathのリライトによって生成されるSQL文のパフォーマンスは、最終的には使用可能な索引およびディスクへのデータの格納方法によって決まります。また、他のSQLアプリケーションと同様に、アプリケーションが正常に実行されている場合、DBAはデータベースを監視して記憶域および索引を最適化する必要があります。
DBAにとって、ここで説明する内容は新しいことではありません。XMLアプリケーションのチューニングに必要な能力は、他のデータベース・アプリケーションの場合と同様です。データベース管理者が、通常、SQLベースのアプリケーションで使用するツールはすべて、Oracle XML DB関数を使用するXMLベースのアプリケーションにも適用できます。
例3-40 EXPLAIN PLANを使用した発注書の選択の分析
この例は、EXPLAIN PLANを使用して、ユーザーSBELLが作成した一連の発注書を選択するための実行計画を参照する方法を示しています。
EXPLAIN PLAN FOR
SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/Reference') "Reference"
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[User="SBELL"]') = 1;
Explained.
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------
Plan hash value: 713050960
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| PURCHASEORDER | 1 | 24 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | PURCHASEORDER_USER_INDEX | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("PURCHASEORDER"."SYS_NC00022$"='SBELL')
Note
-----
- dynamic sampling used for this statement
18 rows selected.
Oracle XML DBでは、次の種類の索引をXMLコンテンツに対して作成できます。
XMLIndex索引(未構造化記憶域およびXML記憶域のみ)
ファンクション索引以外のBツリー索引(構造化記憶域のみ)
ファンクション索引
Oracle Text索引(CONTEXT)
XMLIndex索引は、CLOBインスタンスに格納されているXMLフラグメントに対して、残りのXML文書がオブジェクト・リレーショナル形式で格納されていても、作成できます(これは、ハイブリッド記憶域とも呼ばれます)。XMLIndex索引では、問合せで使用するXPath式を事前に把握しておく必要はありません。XPathリライトは構造化記憶域にのみ適用され、XMLIndexは構造化記憶域には適用されません。
XMLType表または列の構造化記憶域では、基礎となるSQL型に対してBツリー索引を作成できます。Oracle Text索引およびファンクション索引は、すべてのXMLType表または列に対して、その格納方法に関係なく作成できます。
構造化記憶域では、XPathリライト分析により、CREATE INDEX文で使用するXPath式で参照するノードを、基礎となるSQLデータ型のオブジェクト属性にマップできるかどうかが判断されます。可能な場合は、基礎となるSQLオブジェクトに対してBツリー索引が作成されます。不可能な場合は、ファンクション索引が作成されます。ファンクション索引は、通常はSQL関数extractValueに基づきますが、existsNodeなどの他の関数に基づく場合もあります。
例3-41 テキスト・ノードでの索引の作成
この例では、User要素のテキスト・ノードの値に対して索引purchaseorder_user_indexを作成する方法を示します。標準データベース・スキーマOEの表purchaseorderはオブジェクト・リレーショナルに格納されます。
CREATE INDEX purchaseorder_user_index ON purchaseorder (extractValue(OBJECT_VALUE, '/PurchaseOrder/User'));
この索引は、ファンクション索引(関数extractValueに基づく索引)のように見えます。しかし、索引を作成するXMLType表はオブジェクト・リレーショナル形式で格納されるため、XPathリライト分析によって、基礎となるSQLデータ型に対してBツリー索引を作成できるかどうかが判断されます。この例では、索引はpurchaseorder_tオブジェクトのuserid属性に対して作成されます。
例3-42は、例3-41のようにして索引が作成された後に例3-40で使用された問合せを実行して生成されたEXPLAIN PLANを示しています。問合せ計画は新しく作成されたBツリー索引を利用しており、例3-40の問合せ計画よりはるかにスケーラブルです。
例3-42 Bツリー索引の使用を示すEXPLAIN PLAN
EXPLAIN PLAN FOR
SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/Reference') "Reference"
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[User="SBELL"]') = 1;
Explained.
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------
Plan hash value: 713050960
--------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| PURCHASEORDER | 1 | 24 | 3 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | PURCHASEORDER_USER_INDEX | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("PURCHASEORDER"."SYS_NC00022$"='SBELL')
18 rows selected.
多くのXML文書には、繰返し使用する要素のコレクションが含まれています。Oracle XML DBでコレクションのメンバーを効率的に処理するためには、コレクションを管理する記憶域モデルに、コレクションの各メンバーへの効率的なアクセス方法を用意することが重要です。使用する記憶域モデルにより、コレクション内の各要素に索引を作成し、それらの要素に対して直接操作を実行できるかどうかが決まります。
Ordered Collection TableまたはXMLTypeインスタンスとしてコレクションが格納されている場合は、コレクションのメンバーに直接アクセスできます。コレクションの各メンバーは表内の行になるため、SQLで直接アクセスできます。
コレクションがLOBとして格納されている場合は、コレクションのメンバーに直接アクセスできません。コレクションがCLOB値でXMLテキストとして格納されている場合、コレクションに対する操作では、CLOBコンテンツを解析してから、機能上の評価を使用して必要な操作を実行する必要があります。これは、パフォーマンスの面でコストが高くなります。
LOBにシリアライズされた一連のSQLオブジェクトにコレクションを変換すると、解析のコストが発生しなくなります。ただし、この場合も、各コレクション・メンバーに対する操作を実行する前に、コレクションをメモリーにロードする必要があります。
例3-43では、部品番号717951002372(Id属性の値が717951002372のPart要素)の発注を含む文書からReference要素を検索する問合せの実行計画を示します。LineItem要素のコレクションは、Ordered Collection Table、lineitem_tableに行として格納されています。
例3-43 一部のコレクション要素に対するEXPLAIN PLAN
EXPLAIN PLAN FOR
SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/Reference') "Reference"
FROM purchaseorder
WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder/LineItems/LineItem/Part[@Id="717951002372"]') = 1;
Explained.
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------
Plan hash value: 28173485
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 21 | 966 | 20 (10)| 00:00:01 |
|* 1 | HASH JOIN RIGHT SEMI | | 21 | 966 | 20 (10)| 00:00:01 |
| 2 | TABLE ACCESS FULL | PURCHASEORDER | 132 | 3564 | 5 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | LINEITEM_TABLE | 22 | 418 | 14 (8)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("NESTED_TABLE_ID"="PURCHASEORDER"."SYS_NC0003400035$")
3 - filter("SYS_NC00011$"='717951002372')
Note
-----
- dynamic sampling used for this statement
20 rows selected.
実行計画は、Ordered Collection Table、lineitem_tableの全体スキャンを示しています。この計画は、purchaseorder表内の文書の数が数百しかなければ許容されますが、表内に数千または数百万の文書がある場合は許容されません。
このような問合せのパフォーマンスを改善するには、属性Idの値を指定した擬似列NESTED_TABLE_IDに直接アクセスできる索引を作成します。しかし、Oracle XML DBでは、XPath式を直接使用してコレクションに対する索引を作成することはできません。索引を作成するには、LineItem要素の管理に使用するSQLオブジェクトの構造を理解する必要があります。その情報に基づいて、従来のオブジェクト・リレーショナルSQLを使用して必要な索引を作成できます。
ここでは、要素LineItemはオブジェクト・タイプlineitem_tのインスタンスとして格納されています。また、要素PartはSQLデータ型part_tのインスタンスとして格納されています。XML属性Idは、オブジェクト属性part_numberにマップされています。これらの情報に基づいて、例3-44に示すように、属性part_numberおよび擬似列NESTED_TABLE_IDに対するコンポジット索引を作成できます。この索引によって、必要な部品を参照するLineItem要素が含まれた発注書に直接アクセスできます。
例3-44 Ordered Collection Tableに直接アクセスするための索引の作成
CREATE INDEX lineitem_part_index ON lineitem_table l (l.part.part_number, l.NESTED_TABLE_ID); Index created. EXPLAIN PLAN FOR SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/Reference') "Reference" FROM purchaseorder WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder/LineItems/LineItem/Part[@Id="717951002372"]') = 1; Explained. PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------------------------------- Plan hash value: 1849679771 ------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 22 | 1012 | 4 (25)| 00:00:01 | | 1 | NESTED LOOPS | | | | | | | 2 | NESTED LOOPS | | 22 | 1012 | 4 (25)| 00:00:01 | | 3 | SORT UNIQUE | | 22 | 418 | 2 (0)| 00:00:01 | |* 4 | INDEX RANGE SCAN | LINEITEM_PART_INDEX | 22 | 418 | 2 (0)| 00:00:01 | |* 6 | INDEX UNIQUE SCAN | LINEITEM_TABLE_MEMBERS | 1 | | 0 (0)| 00:00:01 | |* 7 | TABLE ACCESS BY INDEX ROWID| PURCHASEORDER | 1 | 530 | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("SYS_NC00011$"='717951002372') 5 - access("NESTED_TABLE_ID"="PURCHASEORDER"."SYS_NC0003400035$") 19 rows selected.
EXPLAIN PLANの出力には、例3-44と同じ問合せが今度は新規に作成された索引を使用することを示しています。この問合せは、索引lineitem_part_indexを使用して、関数existsNodeへのXPath式の引数で指定された条件を満たすpurchaseorder表の文書を判別することで解決されます。
この問合せでは、その構文を変更することなく、スケーラビリティが大幅に向上しています。XPathリライトによって、オプティマイザによる問合せの分析が可能です。この分析により、索引purchaseorder_user_indexおよびlineitem_part_indexで問合せが効率的に解決されているか判別されます。
PL/SQLプロシージャDBMS_XMLSCHEMA.register_schemaのコール結果として作成されたXMLType表に対する問合せのEXPLAIN PLAN出力には、次のようなフィルタが含まれます。
3 - filter(SYS_CHECKACL("ACLOID","OWNERID",xmltype(''<privilege xmlns="http://xmlns.oracle.com/xdb/acl.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/xdb/acl.xsd http://xmlns.oracle.com/xdb/acl.xsd DAV:http://xmlns.oracle.com/xdb/dav.xsd"> <read-properties/><read-contents/></privilege>''))=1)
この出力は、この表に対してACLベースのセキュリティが実装されていることを示しています。この例のフィルタは、SQL問合せを実行するユーザーに、アクセスする各文書に対するread-contents権限があることを確認します。
Oracle XML DBリポジトリでは、XMLコンテンツへのアクセスを単に表ごとではなく文書ごとに制御できる、ACLベースのセキュリティ・メカニズムが使用されます。SQL文を使用してXMLコンテンツにアクセスすると、sys_checkACLへのコールが自動的にWHERE句に追加されます。これによって、定義されたセキュリティがSQLレベルで適用されます。
ただし、ACLベースのセキュリティを適用すると、SQL問合せのオーバーヘッドが増加します。ACLベースのセキュリティが必要でない場合は、パッケージDBMS_XDBZ内のプロシージャdisable_hierarchyを使用して、ACLによる確認をオフにします。このプロシージャをコールした後は、sys_checkACLフィルタはEXPLAIN PLANで生成された出力に表示されなくなります。
|
関連項目: プロシージャDBMS_XDBZ.disable_hierarchyの詳細は、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。 |
例3-45では、Oracle XML DBでXPathのリライトを実行できない場合に生成されるEXPLAIN PLANの出力の種類を示します。出力(行3)内に、関数existsNodeがあります。これは、この問合せがリライトされないことを示します。
例3-45 XPathリライトを実行しない場合に生成されるEXPLAIN PLAN
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("NESTED_TABLE_ID"=:B1)
2 - access("NESTED_TABLE_ID"=:B1)
3 - filter(EXISTSNODE(SYS_MAKEXML('C0A5497E8DCF110BE034080020E5CF39',
3044, "SYS_ALIAS_4". "XMLEXTRA",
"SYS_ALIAS_4"."XMLDATA"),
'/PurchaseOrder[User="SBELL"]')
=1)
5 - access("NESTED_TABLE_ID"=:B1)
6 - access("NESTED_TABLE_ID"=:B1)
この場合、Oracle XML DBは、問合せのWHERE句で指定された他の条件に基づいて、フィルタ済の結果セットを構成します。次に、この潜在的な結果セット内の行にフィルタを適用して、結果セットに属する行を判断します。フィルタ処理では、各文書でDOMが構成され、またDOM APIで定義されたメソッドを使用して機能上の評価が実行されて、各文書が結果セットのメンバーかどうかが判断されます。
潜在的な結果セットに多数の文書が存在する場合は、パフォーマンスが低下する可能性があります。ただし、WHERE句に他の述語を追加で使用することによって潜在的な結果セットに少数の文書しか発生しない場合は問題ありません。
XMLTypeとXPathの抽象的概念は、基礎となる格納テクノロジに依存しないアプリケーションを開発することを可能にします。従来のリレーショナル・アプリケーションと同様に、索引を作成または削除することによってアプリケーションのパフォーマンスをチューニングできるため、アプリケーションをリライトする必要はありません。
Oracle XML DBには、リレーショナル・データからXMLを生成するいくつかの方法が用意されています。最も強力で柔軟性の高い方法は、発展中のSQL/XML標準に基づいて生成する方法です。このANSI標準では、SELECT文から直接XMLを生成できる一連のSQL関数が定義されています。これらの関数を使用すると、問合せから、従来の表形式の結果セットではなく、1つ以上のXML文書を生成できます。SQL/XML標準関数を使用すると、ほとんどすべての形式のXMLデータを生成できます。次の関数が含まれます。
XMLElementは、要素を作成します。
XMLAttributesは、属性を要素に追加します。
XMLForestは、要素のフォレストを作成します。
XMLAggは、要素のコレクションから単一の要素を作成します。
例3-46 SQL/XML関数を使用したXMLの生成
この問合せは、表departments、locations、countries、employeesおよびjobsの情報を含むXML文書を生成します。
SELECT XMLElement(
"Department",
XMLAttributes(d.Department_id AS "DepartmentId"),
XMLForest(d.department_name AS "Name"),
XMLElement(
"Location",
XMLForest(street_address AS "Address",
city AS "City",
state_province AS "State",
postal_code AS "Zip",
country_name AS "Country")),
XMLElement(
"EmployeeList",
(SELECT XMLAgg(
XMLElement(
"Employee",
XMLAttributes(e.employee_id AS "employeeNumber"),
XMLForest(
e.first_name AS "FirstName",
e.last_name AS "LastName",
e.email AS "EmailAddress",
e.phone_number AS "PHONE_NUMBER",
e.hire_date AS "StartDate",
j.job_title AS "JobTitle",
e.salary AS "Salary",
m.first_name || ' ' || m.last_name AS "Manager"),
XMLElement("Commission", e.commission_pct)))
FROM hr.employees e, hr.employees m, hr.jobs j
WHERE e.department_id = d.department_id
AND j.job_id = e.job_id
AND m.employee_id = e.manager_id)))
AS XML
FROM hr.departments d, hr.countries c, hr.locations l
WHERE department_name = 'Executive'
AND d.location_id = l.location_id
AND l.country_id = c.country_id;
この問合せでは、次のXMLが戻されます。
XML -------------------------------------------------------------------------------- <Department DepartmentId="90"><Name>Executive</Name><Location><Address>2004 Charade Rd</Address><City>Seattle</City><State>Washingto n</State><Zip>98199</Zip><Country>United States of America</Country></Location><EmployeeList><Employee employeeNumber="101"><FirstNa me>Neena</FirstName><LastName>Kochhar</LastName><EmailAddress>NKOCHHAR</EmailAdd ess><PHONE_NUMBER>515.123.4568</PHONE_NUMBER><Start Date>1989-09-21</StartDate><JobTitle>Administration Vice President</JobTitle><Salary>17000</Salary><Manager>Steven King</Manager><Com mission></Commission></Employee><Employee employeeNumber="102"><FirstName>Lex</FirstName><LastName>De Haan</LastName><EmailAddress>L DEHAAN</EmailAddress><PHONE_NUMBER>515.123.4569</PHONE NUMBER><StartDate>1993-01-13</StartDate><JobTitle>Administration Vice Presiden t</JobTitle><Salary>17000</Salary><Manager>Steven King</Manager><Commission></Commission></Employee></EmployeeList></Department>
この問合せは、departments表の行ごとに要素Departmentを生成します。
各Department要素には、属性DepartmentIDが含まれます。DepartmentIDの値はdepartment_ed列から生成されます。このDepartment要素には、サブ要素のName、LocationおよびEmployeeListも含まれます。
Name要素に関連付けられたテキスト・ノードは、departments表のname列から生成されます。
Location要素には、子要素Address、City、State、ZipおよびCountryが含まれます。これらの要素は、locations表およびcountries表の列からフォレスト、つまり名前付き要素を作成することで構成されます。列内の値は、名前付き要素に対するテキスト・ノードになります。
EmployeeList要素には、Employee要素の集計が含まれます。EmployeeList要素のコンテンツは、現在の部門に対応するemployees表の一連の行を戻す副問合せによって作成されます。各Employee要素には、従業員に関する情報が含まれます。各Employee要素のコンテンツおよび属性は、表employeesおよびjobsから取得されます。
SQL/XML関数で生成される出力は、フォーマット出力ではありません。このため、これらの関数で必要な出力を生成するときに、完全なDOMが作成されるのを回避し、生成される文書のサイズを縮小することができます。ほとんどのアプリケーションでは、このようにSQL/XML関数でフォーマット出力が生成されなくても問題ありません。ただし、生成された出力を手動で検証することは困難になります。
例3-47 従来のリレーショナル表のXMLTypeビューの作成
CREATE OR REPLACE VIEW department_xml OF XMLType
WITH OBJECT ID (substr(extractValue(OBJECT_VALUE, '/Department/Name'), 1, 128))
AS
SELECT XMLElement(
"Department",
XMLAttributes(d.department_id AS "DepartmentId"),
XMLForest(d.department_name AS "Name"),
XMLElement("Location", XMLForest(street_address AS "Address",
city AS "City",
state_province AS "State",
postal_code AS "Zip",
country_name AS "Country")),
XMLElement(
"EmployeeList",
(SELECT XMLAgg(
XMLElement(
"Employee",
XMLAttributes (e.employee_id AS "employeeNumber" ),
XMLForest(e.first_name AS "FirstName",
e.last_name AS "LastName",
e.email AS "EmailAddress",
e.phone_number AS "PHONE_NUMBER",
e.hire_date AS "StartDate",
j.job_title AS "JobTitle",
e.salary AS "Salary",
m.first_name || ' ' ||
m.last_name AS "Manager"),
XMLElement("Commission", e.commission_pct)))
FROM hr.employees e, hr.employees m, hr.jobs j
WHERE e.department_id = d.department_id
AND j.job_id = e.job_id
AND m.employee_id = e.manager_id))).extract('/*')
AS XML
FROM hr.departments d, hr.countries c, hr.locations l
WHERE d.location_id = l.location_id
AND l.country_id = c.country_id;
View created.
XMLTypeビューによって、リレーショナル・データをXMLコンテンツとして永続的に保持できます。また、XMLTypeビューの行は、Oracle XML DBリポジトリに文書として永続的に保持できます。例3-48に示すように、XMLTypeビューのコンテンツは問合せが可能です。
例3-48 XMLTypeビューの問合せ
この例は、XMLTypeビューに対する簡単な問合せを示しています。SQL関数existsNodeに渡されるXPath式によって、結果セットは、Executive部門の情報が含まれたノードに制限されます。結果は、わかりやすくするためフォーマット出力しています。
SELECT OBJECT_VALUE FROM department_xml
WHERE existsNode(OBJECT_VALUE, '/Department[Name="Executive"]') = 1;
OBJECT_VALUE
------------------------------------------------
<Department DepartmentId="90">
<Name>Executive</Name>
<Location>
<Address>2004 Charade Rd</Address>
<City>Seattle</City>
<State>Washington</State>
<Zip>98199</Zip>
<Country>United States of America</Country>
</Location>
<EmployeeList>
<Employee employeeNumber="101">
<FirstName>Neena</FirstName>
<LastName>Kochhar</LastName>
<EmailAddress>NKOCHHAR</EmailAddress>
<PHONE_NUMBER>515.123.4568</PHONE_NUMBER>
<StartDate>1989-09-21</StartDate>
<JobTitle>Administration Vice President</JobTitle>
<Salary>17000</Salary>
<Manager>Steven King</Manager>
<Commission/>
</Employee>
<Employee employeeNumber="102">
<FirstName>Lex</FirstName>
<LastName>De Haan</LastName>
<EmailAddress>LDEHAAN</EmailAddress>
<PHONE_NUMBER>515.123.4569</PHONE_NUMBER>
<StartDate>1993-01-13</StartDate>
<JobTitle>Administration Vice President</JobTitle>
<Salary>17000</Salary>
<Manager>Steven King</Manager>
<Commission/>
</Employee>
</EmployeeList>
</Department>
1 row selected.
次のEXPLAIN PLANの出力に示すとおり、Oracle XML DBには、existsNode式のXPath式の引数を、基礎となるリレーショナル表のSELECT文に正しくリライトする機能があります。
EXPLAIN PLAN FOR
SELECT OBJECT_VALUE FROM department_xml
WHERE existsNode(OBJECT_VALUE, '/Department[Name="Executive"]') = 1;
Explained.
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------
Plan hash value: 2414180351
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 80 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 114 | | |
|* 2 | HASH JOIN | | 10 | 1140 | 7 (15)| 00:00:01 |
|* 3 | HASH JOIN | | 10 | 950 | 5 (20)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 10 | 680 | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 10 | | 1 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL | JOBS | 19 | 513 | 2 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL | EMPLOYEES | 107 | 2033 | 2 (0)| 00:00:01 |
| 8 | NESTED LOOPS | | 1 | 80 | 3 (0)| 00:00:01 |
| 9 | NESTED LOOPS | | 1 | 68 | 3 (0)| 00:00:01 |
|* 10 | TABLE ACCESS FULL | DEPARTMENTS | 1 | 19 | 2 (0)| 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID | LOCATIONS | 1 | 49 | 1 (0)| 00:00:01 |
|* 12 | INDEX UNIQUE SCAN | LOC_ID_PK | 1 | | 0 (0)| 00:00:01 |
|* 13 | INDEX UNIQUE SCAN | COUNTRY_C_ID_PK | 1 | 12 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("M"."EMPLOYEE_ID"="E"."MANAGER_ID")
3 - access("J"."JOB_ID"="E"."JOB_ID")
5 - access("E"."DEPARTMENT_ID"=:B1)
10 - filter("D"."DEPARTMENT_NAME"='Executive')
12 - access("D"."LOCATION_ID"="L"."LOCATION_ID")
13 - access("L"."COUNTRY_ID"="C"."COUNTRY_ID")
30 rows selected.
|
注意: XMLTypeビューを操作するXML式に対するXPathリライトがサポートされるのは、XPath式で参照するノードが、SQL関数XMLAggを使用して作成された要素の子孫でない場合のみです。 |
リレーショナル・データからXMLを生成するもう1つの方法は、SQL関数DBURITypeを使用することです。関数DBURITypeは、指定された表またはビューの1つ以上の行を単一のXML文書として公開します。ルート要素の名前は、表またはビューの名前から導出されます。ルート要素には、一連のROW要素が含まれます。表またはビュー内の行ごとにROW要素が1つずつあります。各ROW要素の子は、表またはビューの列から導出されます。各子要素には、指定された行の列の値を持つテキスト・ノードが含まれます。
例3-49 DBURITypeとgetXML()を使用した、DEPARTMENTS表のXMLコンテンツへのアクセス
この例は、SQL関数DBURITypeを使用して、スキーマhr内のdepartments表のコンテンツにアクセスする方法を示しています。この例では、メソッドgetXML()を使用して、結果の文書をXMLTypeインスタンスとして戻します。
SELECT DBURIType('/HR/DEPARTMENTS').getXML() FROM DUAL;
DBURITYPE('/HR/DEPARTMENTS').GETXML()
------------------------------------------------------
<?xml version="1.0"?>
<DEPARTMENTS>
<ROW>
<DEPARTMENT_ID>10</DEPARTMENT_ID>
<DEPARTMENT_NAME>Administration</DEPARTMENT_NAME>
<MANAGER_ID>200</MANAGER_ID>
<LOCATION_ID>1700</LOCATION_ID>
</ROW>
...
<ROW>
<DEPARTMENT_ID>20</DEPARTMENT_ID>
<DEPARTMENT_NAME>Marketing</DEPARTMENT_NAME>
<MANAGER_ID>201</MANAGER_ID>
<LOCATION_ID>1800</LOCATION_ID>
</ROW>
</DEPARTMENTS>
SQL関数DBURITypeを使用すると、DBURITypeを使用して表またはビューにアクセスするときに、XPath表記法を使用して、戻される表またはビュー内のデータ量を制御できます。また、XPath式の述語を使用して、生成される文書に含める表内の行を制御できます。
例3-50 XPath式の述語を使用した文書に含める行の制限
この例では、XPath式内に述語を使用して、生成されるXML文書に含める行を制限する方法を示します。ここでは、XPath式によって、値が10のDEPARTMENT_ID列のみにXML文書が制限されます。
SELECT DBURIType('/HR/DEPARTMENTS/ROW[DEPARTMENT_ID="10"]').getXML()
FROM DUAL;
DBURITYPE('/HR/DEPARTMENTS/ROW[DEPARTMENT_ID="10"]').GETXML()
------------------------------------------------------------------
<?xml version="1.0"?>
<ROW>
<DEPARTMENT_ID>10</DEPARTMENT_ID>
<DEPARTMENT_NAME>Administration</DEPARTMENT_NAME>
<MANAGER_ID>200</MANAGER_ID>
<LOCATION_ID>1700</LOCATION_ID>
</ROW>
1 row selected.
この項で示した各例からわかるように、SQL関数DBURITypeを使用すると、リレーショナル表の一部または全部の行を1つ以上のXML文書として簡単に公開できます。関数DBURITypeに渡されるURLを拡張してビューまたは表から単一列を戻すことができますが、その場合、URLには、ターゲットの表またはビューの単一行を識別する述語も含まれる必要があります。たとえば、次のURIは、department_id列に値10が含まれるdepartments行について、department_name列の値を戻します。
SELECT DBURIType(
'/HR/DEPARTMENTS/ROW[DEPARTMENT_ID="10"]/DEPARTMENT_NAME').getXML()
FROM DUAL;
DBURITYPE('/HR/DEPARTMENTS/ROW[DEPARTMENT_ID="10"]/DEPARTMENT_NAME').GETXML()
-----------------------------------------------------------------------------
<?xml version="1.0"?>
<DEPARTMENT_NAME>Administration</DEPARTMENT_NAME>
1 row selected.
SQL関数DBURITypeには、SQL/XML関数が持つ柔軟性はありません。DBURITypeでは、生成される文書の形式を制御できないためです。データは、単一の表またはビューからのみ生成できます。生成される文書は、1つ以上のROW要素で構成されます。各ROW要素には、ターゲット表の列ごとの子が含まれます。子要素の名前は、列の名前から導出されます。
XML要素の名前を制御する場合、複数の表からの列を含める場合、または生成される文書に含める表の列を制御する場合は、必要な列を単一行として公開するリレーショナル・ビューを作成してから、関数DBURITypeを使用して、そのビューのコンテンツからXML文書を生成します。
W3CのXSLT勧告は、XML文書の形式を別の形式に変換する方法を指定するためのXML言語を定義します。変換には、1つのXML Schemaから別のXML Schemaへのマッピング、またはXMLからHTMLやWMLなどの他の形式へのマッピングが含まれる場合があります。
XSL変換は、通常、必要なメモリー量および処理量の面からコストがかかります。文書の様々な部分へのランダムなアクセスが可能になるように、ソース・ドキュメントとスタイルシートの両方を解析してメモリー構造にロードする必要があります。ほとんどのXSLプロセッサは、DOMを使用して両方の文書のメモリー内表現を提供します。次に、XSLプロセッサは、スタイルシートをソース・ドキュメントに適用して、3番目の文書を生成します。
Oracle XML DBには、XSL変換をデータベース内部で実行できるXSLTプロセッサが含まれています。この方法で、Oracle XML DBは、XML固有のメモリーを最適化できます。これによって、変換の実行に必要なメモリー量が大幅に削減されます。また、文書の解析に関連するオーバーヘッドも削減できます。ただし、これらの最適化を使用できるのは、変換対象のソースがXML Schemaに基づくXML文書である場合のみです。
Oracle XMLでは、次の3つの方法でXSLプロセッサを起動できます。
SQL関数XMLtransform
XMLTypeメソッドtransform()
PL/SQLパッケージDBMS_XSLPROCESSOR
これらのXMLデータ変換方法のうちで、パフォーマンスが最も高いのはDBMS_XSLPROCESSORです。これは、スタイルシートの解析が1回のみ行われるためです。
これらの各XML変換方法では、ソースXML文書およびXSLスタイルシートを、XMLTypeインスタンスの形式で入力として受け取ります。SQL関数XMLtransformおよびXMLTypeメソッドtransform()では、変換の結果としてXML文書または非XML文書(HTMLなど)が発生します。しかし、PL/SQLパッケージDBMS_XSLPROCESSORでは、変換の結果は有効なXML文書であることが求められます。これは、パッケージDBMS_XSLPROCESSORを使用した変換によって生成されるHTMLは、XHTML(つまり、有効なXMLと有効なHTML)である必要があることを意味します。
例3-51 XSLTスタイルシートの例: PurchaseOrder.xsl
この例は、XSLTスタイルシートPurchaseOrder.xslの一部を示しています。完全なスタイルシートは、「XSLスタイルシートの例: PurchaseOrder.xsl」に記載されています。
<?xml version="1.0" encoding="WINDOWS-1252"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xdb="http://xmlns.oracle.com/xdb"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:template match="/">
<html>
<head/>
<body bgcolor="#003333" text="#FFFFCC" link="#FFCC00" vlink="#66CC99" alink="#669999">
<FONT FACE="Arial, Helvetica, sans-serif">
<xsl:for-each select="PurchaseOrder"/>
<xsl:for-each select="PurchaseOrder">
<center>
<span style="font-family:Arial; font-weight:bold">
<FONT COLOR="#FF0000">
<B>PurchaseOrder </B>
</FONT>
</span>
</center>
<br/>
<center>
<xsl:for-each select="Reference">
<span style="font-family:Arial; font-weight:bold">
<xsl:apply-templates/>
</span>
</xsl:for-each>
</center>
</xsl:for-each>
<P>
<xsl:for-each select="PurchaseOrder">
<br/>
</xsl:for-each>
<P/>
<P>
<xsl:for-each select="PurchaseOrder">
<br/>
</xsl:for-each>
</P>
</P>
<xsl:for-each select="PurchaseOrder"/>
<xsl:for-each select="PurchaseOrder">
<table border="0" width="100%" BGCOLOR="#000000">
<tbody>
<tr>
<td WIDTH="296">
<P>
<B>
<FONT SIZE="+1" COLOR="#FF0000" FACE="Arial, Helvetica, sans-serif">Internal</FONT>
</B>
</P>
...
</td>
<td width="93"/>
<td valign="top" WIDTH="340">
<B>
<FONT COLOR="#FF0000">
<FONT SIZE="+1">Ship To</FONT>
</FONT>
</B>
<xsl:for-each select="ShippingInstructions">
<xsl:if test="position()=1"/>
</xsl:for-each>
<xsl:for-each select="ShippingInstructions">
</xsl:for-each>
...
このスタイルシートに関して、Oracle XML DB固有のものはありません。スタイルシートは、XMLType表または列に格納でき、Oracle XML DBリポジトリ内にXML Schemaに基づかないXML文書としても格納できます。
変換をデータベース内部で実行することによって、Oracle XML DBでは、メモリー使用量、I/O操作およびネットワーク通信量などの機能を最適化できます。このような最適化は、変換をソース・ドキュメント内の小規模なノードのサブセットに実行する場合に特に効果的です。
従来のXSLプロセッサでは、XSL処理を開始する前に、ソース・ドキュメント全体を解析してメモリーにロードする必要があります。この処理には、多くのメモリーおよびプロセッサが必要です。この処理は、文書の小規模な部分を処理する場合にのみ非効率になります。
Oracle XML DBがXML Schemaに基づくXML文書に対してXSL変換を実行する場合、処理を開始する前に文書を解析する必要はありません。遅延ロードされた仮想DOMの場合は、ノードへのアクセス時にコンテンツをディスクから直接ロードするため、文書の解析が不要になります。また、遅延ロードでは、文書の処理対象部分のみがメモリーにロードされるため、変換の実行に必要なメモリーの量も削減されます。
例3-52 TRANSFORMを使用したスタイルシートの適用
この例では、SQL関数XMLtransformを使用して、XMLType表に格納された文書にXSLスタイルシートを適用し、HTMLコードを生成する方法を示します。SQL関数XDBURITypeは、XSLスタイルシートをOracle XML DBリポジトリから読み取ります。
簡略にするため、ここでは変換結果の一部のみを示しています。省略した部分は、省略記号(. . .)で示しています。図3-7に、変換された結果がWebブラウザでどのように表示されるかを示します。
SELECT XMLtransform( OBJECT_VALUE, XDBURIType('/source/schemas/poSource/xsl/purchaseOrder.xsl').getXML()) FROM purchaseorder WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]')=1; XMLTRANSFORM(OBJECT_VALUE, XDBURITYPE('/SOURCE/SCHEMAS/POSOURCE/XSL/PURCHASEORDER.XSL').GET --------------------------------------------------------------------------------------------- <html> <head/> <body bgcolor="#003333" text="#FFFFCC" link="#FFCC00" vlink="#66CC99" alink="#669999"> <FONT FACE="Arial, Helvetica, sans-serif"> <center> <span style="font-family:Arial; font-weight:bold"> <FONT COLOR="#FF0000"> <B>PurchaseOrder </B> </FONT> </span> </center> <br/> <center> <span style="font-family:Arial; font-weight:bold">SBELL-2002100912333601PDT</span> </center> <P> <br/> <P/> <P> <br/> </P> </P> <table border="0" width="100%" BGCOLOR="#000000"> <tbody> <tr> <td WIDTH="296"> <P> <B> <FONT SIZE="+1" COLOR="#FF0000" FACE="Arial, Helvetica, sans-serif">Internal</FONT> </B> </P> <table border="0" width="98%" BGCOLOR="#000099"> . . . </table> </td> <td width="93"/> <td valign="top" WIDTH="340"> <B> <FONT COLOR="#FF0000"> <FONT SIZE="+1">Ship To</FONT> </FONT> </B> <table border="0" BGCOLOR="#999900"> . . . </table> </td> </tr> </tbody> </table> <br/> <B> <FONT COLOR="#FF0000" SIZE="+1">Items:</FONT> </B> <br/> <br/> <table border="0"> . . . </table> </FONT> </body> </html> 1 row selected.
Oracle XML DBリポジトリを使用すると、XMLコンテンツをファイル/フォルダ隠喩を使用して編成できます。これによって、URLを使用して、データベースに格納されたXML文書を一意に識別できます。これまでURLやXPath式などの構造体を使用してコンテンツを識別してきたXML開発者は、この方法の使用を検討できます。
Oracle XML DBリポジトリは、DAV標準に基づいてモデル化されています。DAV標準では、WebDAVサーバーで管理されるファイルやフォルダを示すためにリソースという用語が使用されます。リソースは、メタデータとコンテンツの組合せで構成されます。DAV仕様には、リソースごとにWebDAVサーバーが管理する一連の(システム定義の)メタデータ・プロパティ、およびDAVサーバーやDAV対応クライアントでメタデータを交換するために使用する一連のXML文書が定義されています。
Oracle XML DBリポジトリでは、あらゆる種類のコンテンツを管理できますが、コンテンツがXMLであるリソースを管理するための特別な機能と最適化機能が用意されています。
Oracle XML DBリポジトリで管理されるすべてのメタデータおよびコンテンツは、一連の表を使用して、データベース・スキーマ(ユーザー・アカウント)XDBが所有するデータベース・スキーマに格納されます。ユーザーXDBはロックされたアカウントで、DBCAを使用するか、またはスクリプトcatqm.sqlを実行してインストールされます。スクリプトcatqm.sqlは、ディレクトリORACLE_HOME/rdbms/adminにあります。リポジトリは、DBCAを使用するか、またはスクリプトcatnoqm.sqlを実行して削除できます。catnoqm.sqlを実行すると、Oracle XML DBリポジトリに格納されたすべてのコンテンツが削除され、登録済のXML Schemaに関連するXMLType表または列が無効になるため、このスクリプトを実行するときは十分な注意が必要です。
|
関連項目: データベース・スキーマXDBの詳細は、『Oracle Database 2日でセキュリティ・ガイド』を参照してください。 |
リレーショナル・データベースを使用して階層フォルダ構造を保持する場合、フォルダに対して項目を追加または削除するときに高度な同時実行性を保証することは重要な問題です。従来のファイル・システムでは、トランザクションの概念はありません。各操作(ファイルの追加、サブフォルダの作成、ファイル名の変更、ファイルの削除など)は、基本トランザクションとして処理されます。操作が完了すると、ファイル・システムのすべてのユーザーに対して変更がすぐに反映されます。
|
注意: データベースによって適用されるトランザクション・セマンティクスの結果として、SQL文を使用して作成されたフォルダは、トランザクションがコミットされるまで他のデータベース・ユーザーから参照されません。Oracle XML DBリポジトリへの同時アクセスは、Oracle Databaseで同時実行性を制御する場合と同じメカニズムを使用して制御されます。リポジトリとOracle Databaseの統合によって、XMLコンテンツを強力に管理するオプションが提供されます。 |
Oracle XML DBリポジトリの主要なメリットの1つは、論理トランザクションでのリポジトリ操作でSQLを使用できることです。アプリケーションでは、1つ以上のフォルダを更新する操作が含まれた、長時間実行するトランザクションを作成できます。この場合、更新されたフォルダまたはディレクトリ・ツリーに排他ロックを設定する従来のロック方針では、同時実行性に関する重大な問題がすぐに発生します。
キューに入れられたフォルダ変更のコミット前のロック
Oracle XML DBでは、フォルダ・レベル・ロックではなく名前レベル・ロックを提供して、これを解決します。サブフォルダまたはファイルの作成、名前の変更、移動、削除などのリポジトリ操作では、ターゲット・フォルダに対する排他書込みロックの付与は必要はありません。リポジトリは、フォルダ自体ではなくフォルダ内の名前をロックして、フォルダに対する同時操作を管理します。名前および変更タイプは、キューに入れられます。トランザクションがコミットされた場合のみ、フォルダがロックされてそのコンテンツが変更されます。したがって、Oracle XML DBでは、1つのフォルダのコンテンツに対して複数のアプリケーションが同時に更新を実行できます。また、キューを使用すると、2つのアプリケーションによる同じ名前のオブジェクトの作成を回避できるため、フォルダの同時実行性を管理できます。同じトランザクションで1つのフォルダに対して複数の変更が行われる場合は、コミット時までフォルダの変更をキューに入れることによって、I/Oを最小限にできます。これは、短時間の間に複数のアプリケーションが同じディレクトリ内にファイルを生成する場合に役立ちます。たとえば、トレース・ファイルやログ・ファイルを生成する場合、印刷または電子メール配信用にスプール・ディレクトリを保持する場合などです。
Oracle XML DBリポジトリに格納されたコンテンツは、次の方法で操作できます。
HTTP(S)、WebDAV、FTPなどの業界標準のプロトコルを使用して、挿入、更新、削除など文書レベルの操作を実行します。
SQLを使用して、表レベルまたは行レベルでOracle XML DBリポジトリに直接アクセスします。
Oracle XML DB Content Connectorを使用します(第31章「Oracle XML DB Content Connectorの使用」を参照)。
Oracle XML DBは、HTTP(S)、WebDAV、FTPなどの業界標準のインターネット・プロトコルをサポートしています。プロトコルのサポートとURLベースのアクセスを組み合せることによって、Windows Explorer、Microsoft Word、XMLSpyなどの標準的なデスクトップ・アプリケーションから、Oracle Databaseに格納されたコンテンツに対して挿入、取出し、更新および削除を行うことができます。
図3-4に、Windows Explorerを使用して、フォルダをローカル・ハード・ドライブからOracle Databaseに挿入する操作を示します。Windows Explorerは、WebDAVプロトコルをサポートしています。WebDAVはHTTP標準の拡張で、HTTPサーバーがファイル・サーバーとして機能できる動詞が追加されています。
Windows Explorerのコピー操作またはFTPの入力コマンドを使用して、いくつかの文書をOracle XML DBリポジトリに転送するとき、各putコマンドまたはpostコマンドは、個別の基本操作として処理されます。これによって、いずれかのファイル転送が失敗した場合でもクライアントに混乱が生じません。また、プロトコルを介して文書が変更された場合は、リクエストが処理されると同時に、他のユーザーはその変更内容を参照できます。
例3-53では、標準のコマンドラインFTPツールで文書をOracle XML DBリポジトリにロードするときに発行されるコマンドと、生成された出力を示します。
例3-53 FTPを使用したリポジトリへのコンテンツのアップロード
$ ftp mdrake-sun 2100
Connected to mdrake-sun.
220 mdrake-sun FTP Server (Oracle XML DB/Oracle Database 10g Enterprise Edition
Release 10.1.0.1.0 - Beta) ready.
Name (mdrake-sun:oracle10): QUINE
331 Password required for QUINE
Password: password
230 QUINE logged in
ftp> cd /source/schemas
250 CWD Command successful
ftp> mkdir PurchaseOrders
257 MKD Command successful
ftp> cd PurchaseOrders
250 CWD Command successful
ftp> mkdir 2002
257 MKD Command successful
ftp> cd 2002
250 CWD Command successful
ftp> mkdir "Apr"
257 MKD Command successful
ftp> put "Apr/AMCEWEN-20021009123336171PDT.xml"
"Apr/AMCEWEN-20021009123336171PDT.xml"
200 PORT Command successful
150 ASCII Data Connection
226 ASCII Transfer Complete
local: Apr/AMCEWEN-20021009123336171PDT.xml remote:
Apr/AMCEWEN-20021009123336171PDT.xml
4718 bytes sent in 0.0017 seconds (2683.41 Kbytes/s)
ftp> put "Apr/AMCEWEN-20021009123336271PDT.xml"
"Apr/AMCEWEN-20021009123336271PDT.xml"
200 PORT Command successful
150 ASCII Data Connection
226 ASCII Transfer Complete
local: Apr/AMCEWEN-20021009123336271PDT.xml remote:
Apr/AMCEWEN-20021009123336271PDT.xml
4800 bytes sent in 0.0014 seconds (3357.81 Kbytes/s)
.....
ftp> cd "Apr"
250 CWD Command successful
ftp> ls -l
200 PORT Command successful
150 ASCII Data Connection
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 AMCEWEN-20021009123336171PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 AMCEWEN-20021009123336271PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 EABEL-20021009123336251PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 PTUCKER-20021009123336191PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 PTUCKER-20021009123336291PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 SBELL-20021009123336231PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 SBELL-20021009123336331PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 SKING-20021009123336321PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 SMCCAIN-20021009123336151PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 SMCCAIN-20021009123336341PDT.xml
-rw-r--r1 QUINE oracle 0 JUN 24 15:41 VJONES-20021009123336301PDT.xml
226 ASCII Transfer Complete
remote: -l
959 bytes received in 0.0027 seconds (349.45 Kbytes/s)
ftp> cd ".."
250 CWD Command successful
....
ftp> quit
221 QUIT Goodbye.
$
この両方の例で示されている要点は、Windows ExplorerおよびFTPツールのいずれもがOracle XML DBの操作を認識していないことです。ツールおよびOracle XML DBの両方がオープン・インターネット・プロトコルをサポートしているため、最初から相互に使用できます。
WebDAVまたはFTPプロトコルを認識するツールを使用すると、Oracle XML DBリポジトリで管理されるコンテンツを作成できます。クライアントまたは中間層に追加のソフトウェアをインストールする必要はありません。
Windows ExplorerやFTPなどのツールを使用してフォルダのコンテンツを表示すると、そのフォルダに格納されたXML Schemaに基づくXML文書のサイズは0(ゼロ)バイトと表示されます。このように設計されているのは、次の2つの理由からです。
文書のどのサイズを表示する必要があるかが明確でありません。文書に関連するサイズには、文書を出力して生成されたCLOBインスタンスのサイズ、文書をデータベース内に永続的に保持するために使用するオブジェクトの格納に必要なバイト数などがあります。
選択された定義に関係なく、この情報を計算して保持するにはコストがかかります。
図3-5に、Internet ExplorerでURLおよびHTTPプロトコルを使用して、データベースに格納されたXML文書を表示する操作を示します。
Oracle XML DBリポジトリは、SQLから直接アクセスして更新できます。つまり、SQLを使用してOracle Databaseと対話できるアプリケーションまたはプログラミング言語からも、Oracle XML DBリポジトリに格納されたコンテンツにアクセスして更新できるということです。Oracle XML DBには、プログラムによるリソースの作成、変更および削除を可能にするメソッドが備わったPL/SQLパッケージDBMS_XDBが含まれています。
この項では、Oracle XML DBリポジトリのコンテンツにアクセスして更新するための機能について説明します。
SQLを使用したXML文書へのアクセス
リポジトリに格納されたコンテンツには、SQLおよびPL/SQLからアクセスして更新できます。このリポジトリの構造は、複合したいくつかの方法で問い合せることができます。たとえば、/home/mystylesheetdir以外の場所にある、拡張子が.xslの文書の数を調べる問合せを発行できます。
また、パスベースのリポジトリ・アクセスとコンテンツ・ベースのアクセスを組み合せることもできます。たとえば、/home/purchaseOrders以外の場所にある、値がKINGのXPath /PurchaseOrder/User/text()で識別されるノードを持つ文書の数を問い合せることができます。
リポジトリを管理するためのすべてのメタデータは、データベース・スキーマ(ユーザー・アカウント)XDBが所有するデータベース・スキーマに格納されます。ユーザーXDBは、Oracle XML DBのインストール時に作成されます。このスキーマの主な表は、XDB$RESOURCEというXMLType表です。この表には、リポジトリ内のリソース(ファイルまたはフォルダ)ごとに1行ずつが含まれます。この表内の文書はリソース・ドキュメントと呼ばれます。Oracle XML DBのリソース・ドキュメントの構造を定義するXML Schemaは、URL http://xmlns.oracle.com/xdb/XDBResource.xsdに登録されています。
|
関連項目: データベース・スキーマXDBの詳細は、『Oracle Database 2日でセキュリティ・ガイド』を参照してください。 |
RESOURCE_VIEWとPATH_VIEWを介して公開されるリポジトリのコンテンツ
表XDB$RESOURCEは、SQLプログラマに直接公開されていません。リポジトリのコンテンツは、2つのパブリック・ビュー(RESOURCE_VIEWおよびPATH_VIEW)を介して公開されます。リポジトリに格納された文書のメタデータおよびコンテンツはいずれも、これらのビューを介してアクセスして更新できます。いずれのビューにも仮想列RESが含まれます。パス表記法を使用したSQL文でドキュメントにアクセスして更新するには、RESを使用します。ビューに対する操作では、リポジトリ内の基礎となる表を使用します。
EXISTS_PATHとUNDER_PATHを使用した、WHERE句へのパスベースの述語の追加
Oracle XML DBには、リポジトリ固有のSQL関数としてexists_pathおよびunder_pathという2つの関数があります。これらの関数を使用して、パスベースの述語をSQL文のWHERE句に含めます。SQL操作では、リポジトリのフォルダ階層内におけるコンテンツの場所に基づいてリポジトリのコンテンツを選択できます。階層リポジトリ索引を使用すると、パスベースの問合せが効率的に実行されます。
XML Schemaに基づくXML文書をリポジトリに格納すると、その文書のコンテンツはXML Schemaで識別されるデフォルト表にオブジェクトとして格納されます。リポジトリには、文書に関するメタデータと、コンテンツが含まれたデフォルト表の行を識別するポインタ(XMLTypeのREF)のみが含まれます。
リポジトリへの非XML文書の格納も可能
別の種類の文書をリポジトリに格納することも可能です。非XML文書またはXML Schemaに基づかないXML文書をリポジトリに格納すると、文書のコンテンツは、その文書に関するメタデータとともにLOBに格納されます。
フォルダと文書の作成、削除、名前変更、移動などを実行するためのPL/SQLパッケージ
Oracle XML DBリポジトリはSQLを使用してアクセスおよび更新できるため、PL/SQLプロシージャをコールできるアプリケーションはすべて、このリポジトリを使用できます。すべてのSQLおよびPL/SQLリポジトリ操作はトランザクション型であるため、リポジトリとそのコンテンツへのアクセスは、リポジトリのアクセス制御リスト(ACL)とデータベース・セキュリティの対象となります。
提供されているPL/SQLパッケージDBMS_XDB、DBMS_XDBZおよびDBMS_XDB_VERSIONを使用すると、文書とフォルダの作成、削除および名前変更、フォルダ階層内でのファイルまたはフォルダの移動、ファイルまたはフォルダに対するアクセス権限の設定および変更、バージョニングの開始および管理を実行できます。
例3-55 PL/SQLパッケージDBMS_XDBを使用したフォルダの作成
この例では、PL/SQLパッケージDBMS_XDBを使用して、フォルダ/publicの下位に一連のサブフォルダを作成します。
DECLARE
RESULT BOOLEAN;
BEGIN
IF (NOT DBMS_XDB.existsResource('/public/mysource')) THEN
result := DBMS_XDB.createFolder('/public/mysource');
END IF;
IF (NOT DBMS_XDB.existsResource('/public/mysource/schemas')) THEN
result := DBMS_XDB.createFolder('/public/mysource/schemas');
END IF;
IF (NOT DBMS_XDB.existsResource('/public/mysource/schemas/poSource')) THEN
result := DBMS_XDB.createFolder('/public/mysource/schemas/poSource');
END IF;
IF (NOT DBMS_XDB.existsResource('/public/mysource/schemas/poSource/xsd')) THEN
result := DBMS_XDB.createFolder('/public/mysource/schemas/poSource/xsd');
END IF;
IF (NOT DBMS_XDB.existsResource('/public/mysource/schemas/poSource/xsl')) THEN
result := DBMS_XDB.createFolder('/public/mysource/schemas/poSource/xsl');
END IF;
END;
/
Oracle XML DBリポジトリに格納された文書のコンテンツには、いくつかの方法でアクセスできます。最も簡単な方法は、XDBURITypeを使用することです。XDBURITypeでは、URLを使用して、アクセスするリソースを指定します。XDBURITypeに渡されるURLは、リポジトリのルートから始まると想定されます。データ型XDBURITypeには、リソースに関連付けることのできる様々な種類のコンテンツにアクセスするためのメソッドgetBLOB()、getCLOB()およびgetXML()が用意されています。
例3-56 XDBURITypeを使用したリポジトリ内のテキスト・ドキュメントへのアクセス
この例では、XDBURITypeを使用してテキスト・ドキュメントのコンテンツにアクセスする方法を示します。
SELECT XDBURIType('/home/QUINE/NurseryRhyme.txt').getCLOB() FROM DUAL;
XDBURITYPE('/HOME/QUINE/NURSERYRHYME.TXT').GETCLOB()
----------------------------------------------------
Mary had a little lamb
Its fleece was white as snow
and everywhere that Mary went
that lamb was sure to go
1 row selected.
例3-57 XDBURITypeとリポジトリのリソースを使用したコンテンツへのアクセス
文書のコンテンツには、リソース・ドキュメントを使用してもアクセスできます。この例では、テキスト・ドキュメントのコンテンツにアクセスする方法を示します。
SELECT
DBMS_XMLGEN.convert(
extract(RES,
'/Resource/Contents/text/text()',
'xmlns="http://xmlns.oracle.com/xdb/XDBResource.xsd"').getCLOBVal(),
1)
FROM RESOURCE_VIEW r
WHERE equals_path(RES, '/home/QUINE/NurseryRhyme.txt') = 1;
DBMS_XMLGEN.CONVERT(EXTRACT(RES,'/RESOURCE/CONTENTS/TEXT/TEXT()','XMLNS="HTTP://
--------------------------------------------------------------------------------
Mary had a little lamb
Its fleece was white as snow
and everywhere that Mary went
that lamb was sure to go
1 row selected.
テキスト・ノードにアクセスするために、extractValueではなくSQL関数extractを使用しています。この関数は、テキスト・ノードのコンテンツをXMLTypeインスタンスとして戻します。これによって、XMLTypeメソッドgetCLOBVal()を使用して、このノードのコンテンツにアクセスできるようになります。したがって、4KB以上の文書のコンテンツにアクセスできます。この例では、DBMS_XMLGEN.convertを使用して、エスケープするエンティティをテキストから削除します。
例3-58 リソースと名前空間接頭辞を使用したXML文書へのアクセス
XML Schemaに基づくXML文書とXML Schemaに基づかないXML文書のコンテンツにも、リソースを使用してアクセスできます。この例では、リソース・ドキュメントのノードとXML文書のノードが含まれたXPath式、およびリソースを使用して、PurchaseOrder文書のコンテンツにアクセスする方法を示します。
SELECT des.description
FROM RESOURCE_VIEW rv,
XMLTable(XMLNAMESPACES ('http://xmlns.oracle.com/xdb/XDBResource.xsd' AS "r"),
'/r:Resource/r:Contents/PurchaseOrder/LineItems/LineItem'
PASSING rv.RES
COLUMNS description VARCHAR2(256) PATH 'Description') des
WHERE
equals_path(rv.RES, '/home/QUINE/PurchaseOrders/2002/Mar/SBELL-2002100912333601PDT.xml') = 1;
DES.DESCRIPTION
---------------------------------
A Night to Remember
The Unbearable Lightness Of Being
The Wizard of Oz
3 rows selected.
この例では、名前空間接頭辞rを使用し、リソースの名前空間のメンバーであるノードをXPath式から識別しています。発注書XML Schemaで名前空間が定義されておらず、名前空間接頭辞をPurchaseOrder文書のノードに適用できないため、この処理が必要になります。名前空間接頭辞rは、SQL関数XMLTableのXMLNAMESPACES句を使用して定義されます。
XML Schemaに基づくXML文書のコンテンツにアクセスするには、次の2つの方法があります。
XML Schemaに基づかないXML文書の場合と同様に、リソース・ドキュメントを使用してアクセスします。この方法では、RESOURCE_VIEWを使用して、XML Schemaに基づく様々な種類のXML文書を1つのSQL文で問い合せることができます。
XML SchemaをOracle XML DBに登録したときに定義したデフォルト表の行としてアクセスします。
リソース・ドキュメントのXMLRef要素は、SQL文で単一の操作の一部としてメタデータおよびコンテンツにアクセスまたは更新するときに必要な結合キーを提供します。
次の問合せでは、XMLRefの値に基づく結合を使用して、リソース・コンテンツにアクセスします。
例3-59 SQL関数REFおよび要素XMLRefを使用した、リポジトリのリソース・データの問合せ
この例では、Oracle XML DBリポジトリのパスに基づいて、defaultTableの行を検索します。SQL関数refは、リソース・ドキュメントRES内のXMLRef要素の値に基づいて、デフォルト表内のターゲットの行を検索します。
SELECT des.description
FROM RESOURCE_VIEW rv,
purchaseorder p,
XMLTable('/PurchaseOrder/LineItems/LineItem' PASSING p.OBJECT_VALUE
COLUMNS description VARCHAR2(256) PATH 'Description') des
WHERE equals_path(res, '/home/QUINE/PurchaseOrders/2002/Mar/SBELL-2002100912333601PDT.xml') = 1
AND ref(p) = extractValue(rv.RES, '/Resource/XMLRef');
DES.DESCRIPTION
---------------------------------
A Night to Remember
The Unbearable Lightness Of Being
The Wizard of Oz
3 rows selected.
例3-60 メタデータ、パスおよびコンテンツに基づくXML文書のフラグメントの選択
この例では、メタデータ、パスおよびコンテンツに基づいて、XML文書からフラグメントを選択する方法を示します。この問合せは、/home/QUINE/PurchaseOrders/2002/Marの下にあり、部品番号715515009058の発注が含まれる文書に対して、要素Referenceの値を戻します。
SELECT extractValue(p.OBJECT_VALUE, '/PurchaseOrder/Reference')
FROM RESOURCE_VIEW rv, purchaseorder p
WHERE under_path(rv.RES, '/home/QUINE/PurchaseOrders/2002/Mar') = 1
AND ref(p) = extractValue(rv.RES, '/Resource/XMLRef')
AND existsNode(p.OBJECT_VALUE,
'/PurchaseOrder/LineItems/LineItem/Part[@Id="715515009058"]')
= 1;
EXTRACTVALUE(P.OBJECT_VALUE,'/
------------------------------
CJOHNSON-20021009123335851PDT
LSMITH-2002100912333661PDT
SBELL-2002100912333601PDT
3 rows selected.
通常、XML Schemaに基づくXML文書のコンテンツにアクセスするときは、RESOURCE_VIEWまたはPATH_VIEWを単独で使用するよりも、RESOURCE_VIEWまたはPATH_VIEWをデフォルト表と結合して使用した方が効率的です。リソース・ドキュメントとデフォルト表を明示的に結合することによって、Oracle XML DBは、SQL文が1種類のXML文書に対してのみ機能することを認識します。これによって、XPathのリライトを使用して、デフォルト表に対する操作とリソースに対する操作を最適化できます。
Oracle XML DBリポジトリに格納された文書のコンテンツは、プロトコルまたはSQLを使用して更新できます。
現在、最も一般的なコンテンツ作成ツールは、HTTP、FTPおよびWebDAVプロトコルをサポートしています。このようなコンテンツ作成ツールでは、URLおよびHTTP動詞getを使用して文書のコンテンツにアクセスし、HTTP動詞putを使用してその文書のコンテンツを保存できます。したがって、適切なアクセス権限が付与されている場合、Oracle XML DBリポジトリに格納されたコンテンツにアクセスして編集するには、URLのみが必要です。
図3-6に、Microsoft WordのWebDAVサポートを使用して、Oracle XML DBリポジトリに格納された文書をMicrosoft Wordで更新および編集する方法を示します。
図3-6 Microsoft Wordを使用した、Oracle XML DBに格納されたコンテンツの更新および編集

Microsoft Wordなどの編集アプリケーションを使用して、Oracle XML DBに格納されたXML文書を更新すると、データベースは、文書の新しいコンテンツが含まれた入力ストリームを受け取ります。ただし、Wordなどの製品で更新された場合、Oracle XML DBは文書がどのように変更されたかを識別できません。これは、部分更新は不可能なため、文書全体を再解析し、元の文書から導出されたすべてのオブジェクトを、新しいコンテンツから導出されたオブジェクトに置換する必要があることを意味します。
updateXMLなどのSQL関数を使用すると、Oracle XML DBリポジトリに格納された文書のコンテンツを更新できます。文書のコンテンツを変更するには、リソース・ドキュメントまたは文書のコンテンツを保持するデフォルト表を更新します。
例3-61 リソースでUPDATEとUPDATEXMLを使用したドキュメントの更新
この例では、リソース・ドキュメントでSQL UPDATE文およびSQL関数updateXMLを使用して、簡単なテキスト・ドキュメントのコンテンツを更新する方法を示します。XPath式が更新操作のターゲットとしてupdateXMLに渡され、要素/Resource/Contents/textに属するテキスト・ノードが識別されます。
DECLARE
file BFILE;
contents CLOB;
dest_offset NUMBER := 1;
src_offset NUMBER := 1;
lang_context NUMBER := 0;
conv_warning NUMBER := 0;
BEGIN
file := bfilename('XMLDIR', 'tdadxdb-03-02.txt');
DBMS_LOB.createTemporary(contents, true, DBMS_LOB.SESSION);
DBMS_LOB.fileopen(file, DBMS_LOB.file_readonly);
DBMS_LOB.loadClobfromFile(contents,
file,
DBMS_LOB.getLength(file),
dest_offset,
src_offset,
nls_charset_id('AL32UTF8'),
lang_context,
conv_warning);
DBMS_LOB.fileclose(file);
UPDATE RESOURCE_VIEW
SET res = updateXML(res,
'/Resource/Contents/text/text()',
contents,
'xmlns="http://xmlns.oracle.com/xdb/XDBResource.xsd"')
WHERE equals_path(res, '/home/QUINE/NurseryRhyme.txt') = 1;
DBMS_LOB.freeTemporary(contents);
END;
/
関連するリソースの更新によって文書のコンテンツを更新する方法のメリットは、Oracle XML DBリポジトリに格納されたあらゆる種類の文書を更新できることです。
例3-62 UPDATEおよびUPDATEXMLを使用した、XML文書のノードの更新
この例では、リソース・ドキュメントで更新処理を実行することによって、XML文書のノードを更新する方法を示します。ここでは、SQL関数updateXMLによって、User要素に関連付けられたテキスト・ノードの値を変更します。
UPDATE RESOURCE_VIEW SET res = updateXML(res, '/r:Resource/r:Contents/PurchaseOrder/User/text()', 'SKING', 'xmlns:r="http://xmlns.oracle.com/xdb/XDBResource.xsd"') WHERE equals_path( res, '/home/QUINE/PurchaseOrders/2002/Mar/SBELL-2002100912333601PDT.xml') = 1; 1 row updated. SELECT extractValue(res, '/r:Resource/r:Contents/PurchaseOrder/User/text()', 'xmlns:r="http://xmlns.oracle.com/xdb/XDBResource.xsd"') FROM RESOURCE_VIEW WHERE equals_path( res, '/home/QUINE/PurchaseOrders/2002/Mar/SBELL-2002100912333601PDT.xml') = 1; EXTRACTVALUE(RES, '/R:RESOURCE/R:CONTENTS/PURCHASEORDER/USER/TEXT()', 'XMLNS:R="HTTP://XMLNS.ORACLE.COM/XDB/XDBRESOURCE.XSD"') --------------------------------------------------------------------- SKING 1 row selected.
文書のコンテンツを管理するために使用するデフォルト表に対して更新操作を直接実行することによって、XML Schemaに基づくXML文書を更新できます。メタデータに基づくパスまたは条件が含まれたWHERE句を使用して文書を配置する必要がある場合、UPDATE文では、リソースとデフォルト表間の結合を使用する必要があります。
一般に、XML Schemaに基づくXML文書のコンテンツを更新する場合は、RESOURCE_VIEWまたはPATH_VIEWを単独で使用するよりも、RESOURCE_VIEWまたはPATH_VIEWをデフォルト表と結合して使用するほうが効率的です。リソース・ドキュメントとデフォルト表を明示的に結合することによって、Oracle XML DBは、SQL文が1種類のXML文書に対してのみ機能することを認識します。これによって、デフォルト表およびリソースで部分更新を使用できます。
例3-63 リポジトリ内のXML Schemaに基づく文書の更新
この例では、SQL関数updateXMLは、パスによって識別されるターゲットの行を使用してデフォルト表を操作します。更新される行は、REFによって識別されます。REFは、SQL関数equals_pathを使用して、リポジトリ・パスによって識別されます。これにより、更新対象は、指定されたパスで識別されるリソースに対応する行のみに制限されます。
UPDATE purchaseorder p SET p.OBJECT_VALUE = updateXML(p.OBJECT_VALUE, '/PurchaseOrder/User/text()', 'SBELL') WHERE ref(p) = (SELECT extractValue(rv.RES,'/Resource/XMLRef') FROM RESOURCE_VIEW rv WHERE equals_path(rv.RES, '/home/QUINE/PurchaseOrders/2002/Mar/SBELL-2002100912333601PDT.xml') = 1); 1 row updated. SELECT extractValue(p.OBJECT_VALUE, '/PurchaseOrder/User/text()') FROM purchaseorder p, RESOURCE_VIEW rv WHERE ref(p) = extractValue(rv.RES, '/Resource/XMLRef') AND equals_path(rv.RES, '/home/QUINE/PurchaseOrders/2002/Mar/SBELL-2002100912333601PDT.xml') = 1; EXTRACTVAL ---------- SBELL 1 row selected.
アクセス制御リスト(ACL)を使用すると、Oracle XML DBリポジトリ内のリソースへのアクセスを制御できます。ACLはアクセス制御エントリ(ACE)のリストで、各エントリは、特定のプリンシパルへの一連の権限を付与または拒否します。プリンシパルとは、データベース・ユーザー、データベース・ロール、LDAPユーザー、LDAPグループ、またはリソースの所有者である特別なプリンシパルdav:ownerです。リポジトリ内の各リソースは、ACLによって保護されます。ACLによって、ユーザーがリソースに対して持つ権限(read-propertiesやupdateなど)が決まります。各リポジトリ操作には、現行ユーザーがその操作の実行を許可されているかどうかを判断するために、ACLの確認が含まれています。デフォルトでは、新規のリソースはその親フォルダのACLを継承します。ただし、PL/SQLプロシージャDBMS_XDB.setACLを使用してリソースのACLを設定することもできます。Oracle XML DBのリソースのセキュリティの詳細は、第27章「アクセス制御リストおよびセキュリティ・クラス」を参照してください。
次の例で、現行ユーザーはQUINEです。問合せでは、フォルダ/publicのリソースの数が戻されます。このフォルダには、f1とf2の2つのリソースのみが存在すると想定します。また、f1のACLではread-properties権限がQUINEに付与されますが、f2のACLではQUINEに付与される権限はないと想定します。ユーザーがリソースを参照するには、そのリソースに対するread-properties権限が必要です。QUINEはf1のみ参照できるため、問合せの結果は1です。
SELECT count(*) FROM RESOURCE_VIEW r WHERE under_path(r.res, '/public') = 1;
COUNT(*)
--------
1
SQLを使用して作業をしている場合は、通常のトランザクション動作が適用されます。1つの論理作業単位内では、updateXMLなどのSQL関数のコールを複数回使用できます。updateXMLなどの関数を使用して実行された変更は、トランザクションがコミットされるまで他のデータベース・ユーザーから参照されません。任意の時点でROLLBACKを使用して、前回のコミット以降に行われた一連の変更をバック・アウトできます。
Oracle XML DBには、各リソースのシステム定義のメタデータがXML文書として保持されています。これらのリソース・ドキュメントの構造は、XML Schema XDBResource.xsdによって定義されます。このスキーマは、グローバルXML SchemaとしてURL http://xmlns.oracle.com/xdb/XDBResource.xsdに登録されています。
Oracle XML DBを使用すると、2つのパブリック・ビュー(RESOURCE_VIEWおよびPATH_VIEW)を使用して、メタデータおよびフォルダ階層に関する情報にアクセスできます。
RESOURCE_VIEWには、Oracle XML DBリポジトリに格納されたファイルまたはフォルダごとに1つのエントリが含まれています。RESOURCE_VIEWの列RESにはリソース(リソースのコンテンツに関連付けられたメタデータ・プロパティを管理するXML文書)が含まれます。列ANY_PATHには、リソースのコンテンツにアクセスするために現行ユーザーがXDBURITypeに渡すことができる有効なURLが含まれます。このコンテンツがバイナリ・データでない場合、リソースそのものにもコンテンツが含まれます。
Oracle XML DBは、リンクの概念をサポートしています。リンクによって、指定した文書への複数のパスを定義できます。リンク・プロパティ文書と呼ばれる各XML文書では、(リソース固有ではなく)パス固有のメタデータ・プロパティが保持されます。リソースが作成されるたびに、最初のリンクも作成されます。
PATH_VIEWは、リンク・プロパティ文書を公開します。PATH_VIEWには、文書に対してアクセス可能なパスごとに1つのエントリがあります。PATH_VIEWの列RESには、このリンクの参照先のリソース・ドキュメントが含まれます。列PATHには、リンクがリソースへのアクセスに使用できるパスが含まれます。列LINKには、このPATHのリンク・プロパティ文書(メタデータ)が含まれます。
例3-64 RESOURCE_VIEWおよびPATH_VIEWの構造の表示
次の例では、パブリック・ビューRESOURCE_VIEWおよびPATH_VIEWの記述を示します。
DESCRIBE RESOURCE_VIEW
Name Null? Type
-------------------------------------------------------------
RES SYS.XMLTYPE(XMLSchema
"http://xmlns.oracle.com/xdb/XDBResource.xsd"
Element
"Resource")
ANY_PATH VARCHAR2(4000)
RESID RAW(16)
DESCRIBE PATH_VIEW
Name Null? Type
-------------------------------------------------------------
PATH VARCHAR2(1024)
RES SYS.XMLTYPE(XMLSchema
"http://xmlns.oracle.com/xdb/XDBResource.xsd"
Element
"Resource")
LINK SYS.XMLTYPE
RESID RAW(16)
|
関連項目:
|
Oracle XML DBには、フォルダ限定の問合せを実行するために使用するSQL関数として、equals_pathおよびunder_pathの2つが用意されています。このような問合せは、RESOURCE_VIEWまたはPATH_VIEWを操作するSQL文を、Oracle XML DBのフォルダ階層内の特定の場所にある文書に制限します。関数equals_pathは、SQL文を、指定したパスで識別される単一の文書に制限します。関数under_pathは、SQL文を、階層内の特定の場所より下位に存在する文書に制限します。
次の各例に、RESOURCE_VIEWおよびPATH_VIEWに格納されたリソース・ドキュメントに対する簡単なフォルダ限定の問合せを示します。
例3-65 EQUALS_PATHおよびRESOURCE_VIEWを使用したリソースへのアクセス
次の問合せは、SQL関数equals_pathおよびRESOURCE_VIEWを使用して、例3-64で作成したリソースにアクセスします。
SELECT r.RES.getCLOBVal()
FROM RESOURCE_VIEW r
WHERE equals_path(res, '/home/QUINE/NurseryRhyme.txt') = 1;
R.RES.GETCLOBVAL()
--------------------------------------------------------------------------------
<Resource xmlns="http://xmlns.oracle.com/xdb/XDBResource.xsd"
Hidden="false"
Invalid="false"
Container="false"
CustomRslv="false"
VersionHistory="false"
StickyRef="true">
<CreationDate>2005-06-13T13:19:20.566623</CreationDate>
<ModificationDate>2005-06-13T13:19:22.997831</ModificationDate>
<DisplayName>NurseryRhyme.txt</DisplayName>
<Language>en-US</Language>
<CharacterSet>UTF-8</CharacterSet>
<ContentType>text/plain</ContentType>
<RefCount>1</RefCount>
<ACL>
<acl description=
"Private:All privileges to OWNER only and not accessible to others"
xmlns="http://xmlns.oracle.com/xdb/acl.xsd" xmlns:dav="DAV:"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/xdb/acl.xsd
http://xmlns.oracle.com/xdb/acl.xsd"
shared="true">
<ace>
<grant>true</grant>
<principal>dav:owner</principal>
<privilege>
<all/>
</privilege>
</ace>
</acl>
</ACL>
<Owner>QUINE</Owner>
<Creator>QUINE</Creator>
<LastModifier>QUINE</LastModifier>
<SchemaElement>http://xmlns.oracle.com/xdb/XDBSchema.xsd#text</SchemaElement>
<Contents>
<text>Hickory Dickory Dock
The Mouse ran up the clock
The clock struck one
The Mouse ran down
Hickory Dickory Dock
</text>
</Contents>
</Resource>
1 row selected.
例3-65に示すように、リソース・ドキュメントは、DAV標準で定義された一連のメタデータを取得するXML文書です。メタデータには、CreationDate、Creator、Owner、ModificationDate、DisplayNameなどの情報が含まれています。リソース・ドキュメントのコンテンツは、extract、extractValue、existsNode、updateXMLなどのSQL関数を使用して、他のXML文書と同様の方法で問合せおよび更新ができます。
例3-66 リポジトリに格納されたXSLスタイルシートへのパスの判別
最初の問合せは、Oracle XML DBリポジトリに格納された各XSLスタイルシートへのパスを検索します。この問合せは、.xslで終わるDisplayNameの検索を実行します。
SELECT ANY_PATH FROM RESOURCE_VIEW WHERE extractValue(RES, '/Resource/DisplayName') LIKE '%.xsl'; ANY_PATH ------------------------------------------- /source/schemas/poSource/xsl/empdept.xsl /source/schemas/poSource/xsl/purchaseOrder.xsl 2 rows selected.
例3-67 パスの下に存在するリソースのカウント
この例では、パス/home/QUINE/PurchaseOrdersの下に存在するリソース(ファイルおよびフォルダ)の数をカウントします。PATH_VIEWではなくRESOURCE_VIEWを使用すると、複数リンクのターゲットであるリソースは1回のみカウントされます。SQL関数under_pathを使用すると、結果セットは、/home/QUINE/PurchaseOrdersで始まるパスを使用してアクセス可能な文書に制限されます。
SELECT count(*)
FROM RESOURCE_VIEW
WHERE under_path(RES, '/home/QUINE/PurchaseOrders') = 1;
COUNT(*)
----------
145
1 row selected.
例3-68 パス内のフォルダのコンテンツのリスト
この問合せは、パス/home/QUINE/PurchaseOrders/2002/Aprで識別されるフォルダのコンテンツをリストします。この問合せによって、フォルダ内のディレクトリのリストを効率的に作成できます。
SELECT PATH FROM PATH_VIEW WHERE under_path(RES, '/home/QUINE/PurchaseOrders/2002/Apr') = 1; PATH ---------------------------------------------------------------------- /home/QUINE/PurchaseOrders/2002/Apr/AMCEWEN-20021009123336171PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/AMCEWEN-20021009123336271PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/EABEL-20021009123336251PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/PTUCKER-20021009123336191PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/PTUCKER-20021009123336291PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/SBELL-20021009123336231PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/SBELL-20021009123336331PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/SKING-20021009123336321PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/SMCCAIN-20021009123336151PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/SMCCAIN-20021009123336341PDT.xml /home/QUINE/PurchaseOrders/2002/Apr/VJONES-20021009123336301PDT.xml 11 rows selected.
例3-69 フォルダに格納されたリンクのリスト
この問合せは、パス/home/QUINE/PurchaseOrders/2002/Aprで識別されるフォルダに含まれる、関連するリソースのDisplayName要素がSで始まる一連のリンクをリストします。
SELECT PATH
FROM PATH_VIEW
WHERE extractValue(RES, '/Resource/DisplayName') like 'S%'
AND under_path(RES, '/home/QUINE/PurchaseOrders/2002/Apr') = 1;
PATH
----------------------------------------------------------------------
/home/QUINE/PurchaseOrders/2002/Apr/SBELL-20021009123336231PDT.xml
/home/QUINE/PurchaseOrders/2002/Apr/SBELL-20021009123336331PDT.xml
/home/QUINE/PurchaseOrders/2002/Apr/SKING-20021009123336321PDT.xml
/home/QUINE/PurchaseOrders/2002/Apr/SMCCAIN-20021009123336151PDT.xml
/home/QUINE/PurchaseOrders/2002/Apr/SMCCAIN-20021009123336341PDT.xml
5 rows selected.
例3-70 発注書のXML文書が含まれたリソースへのパスの検索
この問合せは、PurchaseOrder文書が含まれたOracle XML DBリポジトリで、各リソースへのパスを検索します。文書は、メタデータ・プロパティSchemaElementに基づいて識別されます。このメタデータ・プロパティは、リポジトリに格納されたXML Schemaに基づくXMLデータのXML Schema URLおよびグローバル要素を識別します。
SELECT ANY_PATH
FROM RESOURCE_VIEW
WHERE existsNode(RES,
'/Resource[SchemaElement=
"http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd#PurchaseOrder"]')
= 1;
この問合せは、PurchaseOrder文書が含まれる次のパスを戻します。
ANY_PATH
-----------------------------------------------------------------------
/home/QUINE/PurchaseOrders/2002/Apr/AMCEWEN-20021009123336171PDT.xml
/home/QUINE/PurchaseOrders/2002/Apr/AMCEWEN-20021009123336271PDT.xml
/home/QUINE/PurchaseOrders/2002/Apr/EABEL-20021009123336251PDT.xml
/home/QUINE/PurchaseOrders/2002/Apr/PTUCKER-20021009123336191PDT.xml
...
132 rows selected.
従来のリレーショナル・データベースでは、パスベースのアクセスおよびフォルダ限定の問合せはCONNECT BY操作を使用して実装する必要があります。このような問合せはコストがかかるため、パスベースのアクセスおよびフォルダ限定の問合せは、文書の数やフォルダ階層の深さが増すにつれて効率が下がります。
この問題に対処するために、Oracle XML DBでは階層リポジトリ索引という新しい索引タイプが導入されました。これを使用すると、CONNECT BY操作を使用しなくても、データベースでフォルダ限定の問合せを解決できます。したがって、Oracle XML DBでは、パスベースおよびフォルダ限定の問合せを効率的に実行できます。階層リポジトリ索引は、Oracleのドメイン索引として実装されます。これは、Oracle Text索引のサポートおよび他の多数の高度な索引タイプをデータベースに追加する場合の方法と同じです。
例3-71 フォルダ限定の問合せのEXPLAIN PLANの出力
この例では、フォルダ限定の問合せで生成されたEXPLAIN PLANの出力を示します。次に示すように、階層リポジトリ索引(XDBHI_IDX)を使用して問合せを解決します。
EXPLAIN PLAN FOR
SELECT PATH
FROM PATH_VIEW
WHERE extractValue(RES, '/Resource/DisplayName') LIKE 'S%'
AND under_path(RES, '/home/QUINE/PurchaseOrders/2002/Apr') = 1;
Explained.
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------
Plan hash value: 2568289845
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 254 | 46736 | 34 (6)| 00:00:01 |
| 1 | NESTED LOOPS | | 254 | 46736 | 34 (6)| 00:00:01 |
| 2 | NESTED LOOPS | | 254 | 42418 | 34 (6)| 00:00:01 |
| 3 | NESTED LOOPS | | 254 | 35306 | 34 (6)| 00:00:01 |
|* 4 | TABLE ACCESS BY INDEX ROWID | XDB$RESOURCE | 1 | 137 | 3 (0)| 00:00:01 |
|* 5 | DOMAIN INDEX | XDBHI_IDX | | | | |
| 6 | COLLECTION ITERATOR PICKLER FETCH| | | | | |
|* 7 | INDEX UNIQUE SCAN | XDB_PK_H_LINK | 1 | 28 | 0 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | SYS_C003728 | 1 | 17 | 0 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("P"."SYS_NC00011$" LIKE 'S%')
5 - access("XDB"."UNDER_PATH"(SYS_MAKEXML('8758D485E6004793E034080020B242C6',734,"XMLEXTRA"
,"XMLDATA"),'/home/QUINE/PurchaseOrders/2002/Apr',9999)=1)
7 - access("H"."PARENT_OID"=SYS_OP_ATG(VALUE(KOKBF$),3,4,2) AND
"H"."NAME"=SYS_OP_ATG(VALUE(KOKBF$),2,3,2))
8 - access("R2"."SYS_NC_OID$"=SYS_OP_ATG(VALUE(KOKBF$),3,4,2))
25 rows selected.
Oracle XML DBでは、XML文書を特別な方法で処理します。XML Schemaに基づくXML文書のコンテンツを格納するルールは、XML Schemaで定義されます。文書のコンテンツは、グローバル要素定義に関連付けられたデフォルト表に格納されます。
Oracle XML DBリポジトリには、JPEGイメージやWord文書など、XMLデータを含まないファイルも格納されます。各リソースのXML Schemaでは、使用可能な要素を定義し、ファイルのコンテンツをBLOBインスタンスとして格納するか、またはCLOBインスタンスとして格納するかを指定します。XML Schemaに基づかないXML文書のコンテンツは、CLOBインスタンスとしてリポジトリに格納されます。
リポジトリ内のファイルまたはフォルダごとに、1つのリソースおよび1つのリンク・プロパティ文書が存在します。指定した文書へのアクセス・パスが複数存在する場合は、リンクごとにリンク・プロパティ文書が存在します。リソース・ドキュメントおよびリンク・プロパティ文書は、両方ともXML文書として格納されます。これらの文書はすべてリポジトリ内の表に格納されます。
XMLファイルをリポジトリにロードすると、次の順序でイベントが発生します。
Oracle XML DBは、XML文書のルート要素を調べ、既知(登録済)のXML Schemaに関連付けられているかどうかを確認します。このとき、文書にXMLSchema-instance名前空間の名前空間宣言が含まれているかどうかが確認され、文書に関連付けられたXML Schemaを識別するschemaLocation属性またはnoNamespaceSchemaLocation属性が検索されます。
文書が既知のXML Schemaに基づいている場合は、XML SchemaのメタデータがXML Schemaのキャッシュからロードされます。
XML文書は解析され、XML Schemaから導出された一連のSQLオブジェクトに分解されます。
XMLファイルから作成されたSQLオブジェクトは、XML Schemaがデータベースに登録されたときに定義されたデフォルト表に格納されます。
リソース・ドキュメントは、処理された文書ごとに作成されます。これによって、リポジトリを使用して、文書のコンテンツにアクセスできます。XML Schemaに基づくXMLTypeのリソース・ドキュメントには、XMLRef要素が含まれています。この要素のコンテンツはXMLTypeのREFで、リソースに関連付けられたコンテンツが含まれるデフォルト表で行を検索するときに使用できます。
Oracle XML DBに組み込まれたHTTPサーバーでは、ブラウザを使用して、Oracle XML DBリポジトリに格納された文書にアクセスできます。リソースにはXMLType表またはビューの行に対するREFを含めることができるため、パスを使用してこのようなコンテンツにアクセスできます。
Oracle XML DBに含まれているDBUriサーブレットを使用すると、ブラウザからすべての表またはビューのコンテンツに直接アクセスできます。DBUriサーブレットは、DBURITypeの機能を使用し、表のコンテンツから簡単なXML文書を生成します。サーブレットはC言語ベースで、Oracle XML DB HTTPサーバーにインストールされます。デフォルトでは、サーブレットは仮想ディレクトリ/oradbにインストールされます。
DBUriサーブレットに渡されるURLは、DBURITypeに渡されるURLの拡張です。このURLは、Oracle XML DB HTTPサーバーのアドレスとポート番号、およびHTTP(S)リクエストをDBUriサーブレットに転送する仮想ルートを使用して拡張されています。このURLのデフォルト構成は/oradbです。
これは、URL http://localhost:8080/oradb/HR/DEPARTMENTSが、HRデータベース・スキーマにあるDEPARTMENTS表のコンテンツが含まれるXML文書を戻すことを意味します。この場合、Oracle XML DB HTTPサーバーはポート8080で実行され、DBUri servletの仮想ルートは/oradbで、リクエストを発行したユーザーにはHRデータベース・スキーマに対するアクセス権限があると想定されます。
DBUriサーブレットは、ROWタグの名前、およびクライアントに戻される文書のMIMEタイプを指定できるパラメータを受け取ります。
XMLType表またはビューのコンテンツにも、DBUri servletを介してアクセスできます。DBUri servletに渡されるURLでXMLType表またはXMLTypeビューを参照する場合は、表または行内のどの文書が戻されるかを判別できるXPath式を使用してURLを拡張できます。URLに追加するXPath式は、文書内のすべてのノードを参照できます。
DBUriサーブレットで生成されたXMLは、Oracle XML DBに組み込まれているXSLTプロセッサを使用して変換できます。これによって、DBUri servletで生成されたXMLを、HTMLなど読みやすい形式で表示できます。
スタイルシート処理を開始するには、DBUri servletに渡されるURLの一部としてtransformパラメータを指定します。スタイルシートは、そのスタイルシートのデータベース内での場所を参照するURIを使用して指定します。URIは、表またはビュー内のXMLType列を識別するDBURIType値、またはOracle XML DBリポジトリに格納された文書へのパスのいずれかになります。スタイルシートは、生成されたXMLがクライアントに戻される前に、XMLに直接適用されます。DBUriサーブレットを使用してXSLT処理を実行するときは、contenttypeパラメータを使用して、生成された出力のMIMEタイプを明示的に指定することをお薦めします。
変換されるXML文書がXML Schemaに基づくXMLTypeインスタンスとして格納されると、Oracle XML DBは、遅延ロードされた仮想DOMの機能を使用できるため、XSL変換に関連するオーバーヘッドを削減できます。
URLのルートは/oradbであるため、このURLは、Oracle XML DBリポジトリのリソースとしてではなく、SCOTTデータベース・スキーマのpurchaseorder表にアクセスするDBUriサーブレットに渡されます。このURLには、結果セットを、述語で指定した値がノード/PurchaseOrder/Reference/text()に含まれる文書に制限するXPath式が含まれます。contenttypeパラメータは、生成される文書のMIMEタイプをtext/xmlに設定します。
図3-7に、DBUriサーブレットで生成されたXMLコンテンツにXSL変換を適用する方法を示します。この例では、DBUriに渡すURLにtransformパラメータが含まれています。これによって、DBUriサーブレットは、メインのURLで識別されるPurchaseOrder文書がブラウザに戻される前に、SQL関数XMLTransformを使用して、スタイルシート/home/SCOTT/xsl/purchaseOrder.xslを文書に適用します。このスタイルシートによって、XML文書がわかりやすいHTMLページに変換されます。また、URLでは、contentTypeパラメータを使用して、最後の文書のMIMEタイプがtext/htmlになることを指定します。
図3-8に、HTML文書として表示されたdepartments表を示します。コーディングは不要で、これを表示するためには、SQL/XML関数に基づくXMLTypeビュー、業界標準のXSLスタイルシートおよびDBUriサーブレットのみが必要です。
脚注の凡例
脚注1: XML Schema注釈maintainOrder = "false"を使用すると、Ordered Collectionでなく、Unordered Collectionが使用されます。XMLデータの場合、Ordered Collection(maintainOrder = "true")の使用をお薦めします。