この章では、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のスキーマ注釈用に予約されています。
また、このPurchaseOrder
XML 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"
)の使用をお薦めします。