ヘッダーをスキップ
Oracle XML DB開発者ガイド
11gリリース1(11.1)
E05669-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

3 Oracle XML DBの使用

この章では、Oracle XML DBの使用方法の概要を説明します。この章の例では、発注書のXMLコンテンツへのアクセスおよび管理の方法を示します。発注書は高度に構造化されたXML文書であるため、XML発注書の形式およびデータはOracle XML DBの記憶域および処理方法に適しています。ただし、ここで説明する方法の多くは、非構造化データや半構造化データなど他のタイプのXML文書を管理する際にも使用できます。この章では、第1章「Oracle XML DBの概要」で紹介したOracle XML DBの概念についても詳しく説明します。

この章の内容は次のとおりです。

XMLをXMLTypeとして格納

Oracle XML DBが導入される前は、次の2つの方法でXMLコンテンツをOracle Databaseに格納していました。

いずれの場合も、Oracle DatabaseはXMLコンテンツを管理していることを認識しません。

Oracle XML DBおよびXMLTypeデータ型の導入によって、XMLコンテンツをデータベースに永続的かつ簡単に格納する方法が新たに提供されました。この方法には、XML文書をXMLType列または表、あるいはOracle XML DBリポジトリに格納する方法が含まれます。XMLをXMLType列または表として格納すると、Oracle DatabaseはコンテンツがXMLであることを認識します。これによって、データベースで次の処理が可能になります。

XMLTypeの概要

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関数extractXMLTypeメソッドextract()に相当します。

Oracle XML DBの機能は、関連するXML標準(XML Parser、XML DOM、XML Schema Validatorなど)のOracle XML Developer's KitのC実装に基づいています。


関連項目:


XMLTypeデータ型およびAPIのメリット

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を使用する場合

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を使用するアプリケーションを作成することによって、アプリケーションの再作成なしに、これらの最適化および拡張を将来のリリースで簡単に実現および保持できます。

XMLType表および列の作成

次に、Oracle DatabaseでXMLコンテンツを管理するために、XMLType列および表を作成する例を示します。

例3-1 XMLType列を含む表の作成

CREATE TABLE mytable1 (key_column VARCHAR2(10) PRIMARY KEY, xml_column XMLType);

Table created.

例3-2 XMLType表の作成

CREATE TABLE mytable2 OF XMLType;

Table created.

バイナリXML形式で格納されているデータの仮想列使用による制約

XMLデータには独自の構造がありますが、XMLTypeのオブジェクト・リレーショナル記憶域を除き、データベース構造には直接反映されません。つまり、個別のXML要素および属性がデータベースの個別の列や表にマップされることはありません。

これは、個別の要素や属性の値に応じてXMLデータを制約する場合、リレーショナル・データに対する標準的な手法を適用できないことを意味します。このため、対象のXMLデータを表す仮想列を作成してから、その仮想列を使用して必要な制約を定義する必要があります。

この手法は、バイナリXML形式で格納されているXMLデータにのみ適用されます。未構造化記憶域を使用するXMLデータの場合、データベースはXML構造を認識せず、データは構造のないテキストとして処理されます。しかしバイナリXML記憶域の場合は、構造が認識されます。この構造に関する認識を利用して仮想列を作成すると、データベースはそれを制約の場合に使用することができます。

手順は次のとおりです。

  1. 対象のXMLデータに対応する仮想列を定義します。

  2. その列を使用してXMLTypeデータを一括して制約します。

XMLTypeデータに対する仮想列の作成は、他の型のデータを使用した仮想列の作成と同様ですが、構文が多少異なります。特に、列定義に関連付けて制約を指定することができません。

XMLTypeは抽象データ型なので、XMLType表に対する仮想列を作成する場合、その列は非表示になり、DESCRIBE文などに表示されません。これにより、DESCRIBEなどの操作を使用するツールが、仮想列に惑わされずに正常に機能することができます。XMLType列を持つ表に仮想列を作成する場合、仮想列は仮想列でないすべての列とともに、DESCRIBE操作によりリストされます。

XML要素または属性に基づく仮想列を作成するには、その要素や属性を含むSQL式によってXML要素または属性を定義します。つまり、ファンクションに基づく列を作成します。ファンクションとしてはSQL関数extractValueを使用できます。


関連項目:


Oracle XML DBへのXMLコンテンツのロード

XMLコンテンツは、次の方法を使用してOracle XML DBにロードできます。

SQLまたはPL/SQLを使用したXMLコンテンツのロード

SQLまたはPL/SQLの簡単なINSERT操作を使用して、XML文書をデータベースにロードできます。文書は、XMLType列または表として格納する前に、XMLTypeコンストラクタの1つを使用してXMLTypeインスタンスに変換する必要があります。


関連項目:


XMLTypeコンストラクタを使用すると、VARCHARCLOBおよび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-3 XMLType表へのXMLコンテンツの挿入

INSERT INTO mytable2 VALUES (XMLType(bfilename('XMLDIR', 'purchaseOrder.xml'),
                                     nls_charset_id('AL32UTF8')));

1 row created.

nls_charset_idに渡される値は、読み取られるファイルのエンコーディングがUTF-8であることを示します。

Javaを使用したXMLコンテンツのロード

例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インタフェースです。

Cを使用したXMLコンテンツのロード

例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セキュリティ・ガイド』を参照してください。


関連項目:

この例の完全なリストは、付録A「Oracleが提供するXML Schemaおよび例」を参照してください。

小規模なXML文書を含む大規模なXMLファイルのロード

小規模な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」を参照してください。

SQL*Loaderを使用した大規模なXMLファイルのロード

大量の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オプションを使用して、各データ保存で読み取られる行数を少なくすることです。

DBMS_XDBを使用したリポジトリへのXML文書のロード

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にコピーする簡単なドラッグ・アンド・ドロップ操作を示します。

図3-1 Windows Explorerを使用したリポジトリへのコンテンツのロード

図3-1の説明が続きます
「図3-1 Windows Explorerを使用したリポジトリへのコンテンツのロード」の説明

コピーされたフォルダには、XML Schema文書、HTMLページおよびいくつかのXSLTスタイルシートが含まれていることがあります。


注意:

Oracle XML DBリポジトリには、XML文書(XML Schemaに基づくXML文書およびXML Schemaに基づかないXML文書)と同様に、HTMLファイル、JPEGイメージ、Word文書など、XMLデータではないコンテンツも格納できます。

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文書は、エンティティと呼ばれる単位で構成されます。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

XML文書をデータベースにロードするときのキャラクタ・セットの決定

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
    

データベースからXML文書を取り出すときのキャラクタ・セットの決定

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データをVARCHARCLOBまたは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勧告の概要

W3CのXML Schema勧告では、一連のXML文書の構造、コンテンツおよび特定のセマンティクスを指定するための標準化された言語が定義されています。XML Schemaは、XML文書のクラスを示すメタデータとみなすことができます。XML Schemaの勧告については、http://www.w3.org/TR/xmlschema-0/を参照してください。

XMLインスタンス・ドキュメント

指定のXML Schemaに準拠する文書は、そのXML Schemaで定義されたクラスのメンバーまたはインスタンスとみなすことができます。したがって、「インスタンス・ドキュメント」という用語は、多くの場合、指定されたスキーマに準拠するXML文書を示すために使用されます。XML Schemaの最も一般的な用途は、指定されたインスタンス・ドキュメントがXML Schemaで定義されたルールに準拠していることを確認することです。

XML Schema for Schemas

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の編集

XML Schemaは、次のいずれかを使用して作成および編集できます。

  • emacsやviなどの簡単なテキスト・エディタ

  • Oracle JDeveloperに付属のXMLエディタなど、XML Schemaを認識するエディタ

  • Altova社のXMLSpyなどの明示的なXML Schema作成ツール

XML Schemaの機能

XML Schema言語は、47のスカラー・データ型を定義します。これによって、要素と属性の厳密な型指定が可能になります。W3CのXML Schema勧告では、継承や拡張などのオブジェクト指向の技法もサポートしているため、XML Schema言語で定義された基本データ型から複合的なオブジェクトを持つXML Schemaを設計できます。ボキャブラリには、定義および順序付けの構造体、デフォルト値、必須コンテンツ、ネスト、セットの繰返しおよび再定義が含まれます。Oracle XML DBは、再定義を除くすべての構造体をサポートします。

XML Schema PurchaseOrderのテキスト表現

次の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>

発注書XML 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によるグラフィカル表現

図3-2の説明が続きます
「図3-2 XML Schema PurchaseOrderのXMLSpyによるグラフィカル表現」の説明

XML Schema PurchaseOrderは、通常のXML文書の主要な機能を示す簡単なXML Schemaです。

  • グローバル要素PurchaseOrderは、complexType PurchaseOrderTypeのインスタンスです。

  • PurchaseOrderTypeでは、PurchaseOrder要素を構成する一連のノードが定義されます。

  • LineItem要素は、LineItems要素のコレクションで構成されます。

  • LineItem要素は、2つの要素(DescriptionおよびPart)で構成されます。

  • Part要素には、属性IdQuantityおよびUnitPriceがあります。

Oracle XML DBでのXML Schemaの使用

この項では、Oracle XML DBでのXML Schemaの使用について説明します。

XML SchemaをOracle XML DBとともに使用する理由

次に、XML SchemaをOracle XML DBとともに使用する主な理由を説明します。

XML Schemaを使用したインスタンス・ドキュメントの検証

XML Schemaの最も一般的な用途は、インスタンス・ドキュメントが指定のXML Schemaに準拠していることを確認するメカニズムとして使用することです。XMLTypeデータ型のメソッドisSchemaValid()およびschemaValidate()によって、Oracle XML DBは、XMLTypeに格納されたインスタンス・ドキュメントのコンテンツをXML Schemaと照合して検証できます。

ビジネス・ルールまたは書式準拠に対するインスタンス・ドキュメントの制約

XML Schemaは、XMLTypeの表または列の作成時に制約としても使用できます。たとえば、XMLTypeは、XML Schemaで定義されたいずれかのグローバル要素に準拠するXML文書の格納用に制限されます。

データベースへのXMLTypeコンテンツの格納方法の定義

Oracle XML DBでは、XML Schemaを、XMLTypeインスタンスのコンテンツをデータベース内に格納する方法を定義するメカニズムとしても使用します。バイナリXML、構造化、非構造化およびハイブリッド(構造化と非構造化の組合せ)のすべての記憶域モデルで、XML Schemaの使用をサポートしています。XMLTypeに使用可能な記憶域モデルの詳細は、「XMLType記憶域モデル」を参照してください。

XML文書の構造化記憶域

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コンテンツの問合せおよび更新に必要なメモリー量も削減できます。

ネーミング、マッピングおよび記憶域を制御するためのXML Schemaの注釈付け

W3CのXML Schema勧告では、ベンダー固有の情報をXML Schemaに追加できる注釈メカニズムが定義されています。Oracle XML DBでは、このメカニズムを使用して、XML Schemaとデータベース・オプションの間のマッピングを制御します。

XML Schema注釈を使用すると、次の操作を実行できます。

  • XMLデータを格納するデータベース表の指定

  • XML Schemaデータ型と、バイナリXMLエンコーディング型、またはSQLデータ型(構造化記憶域の場合)の間のデフォルト・マッピングの上書き

  • XMLデータを格納するために作成されるデータベース・オブジェクトおよび属性の命名(構造化記憶域の場合)

オブジェクト・リレーショナルなXMLType記憶域の場合のコレクション格納方法の制御

オブジェクト・リレーショナルに格納されるデータのXML Schemaを登録し、登録パラメータGENTABLESTRUEに設定する場合、関連付けられたXMLインスタンス・ドキュメントを格納するためにデフォルト表が自動的に作成されます。

格納されたときのXMLコレクション要素の順序が維持されます。結果はOrdered Collectionです。脚注1 データは、次の方法でOrdered Collectionに格納できます。

  • 表内のVARRAY。コレクション内の各要素は、SQLオブジェクトにマップされます。SQLオブジェクトのコレクションは、Ordered Collection TableOCT)と呼ばれる表に、一連の行として格納されます。デフォルトでは、すべてのコレクションが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.registerschemaOPTIONSパラメータでREGISTER_NT_AS_IOTを渡します。


注意:

オラクル社によりIOTの使用を明示的に指示された場合以外は、IOTでなく、ヒープに基づくOCTを使用してください。IOTの記憶域には、次のような大きな制限があります。
  • コレクション表(IOT)のパーティショニングが無効化されます。

    オブジェクト・リレーショナル形式で格納されたXMLTypeデータの場合、ベースXMLType表またはXMLType列を持つベース表をパーティション化すると、ヒープに基づく表記憶域を使用するすべてのコレクション表に対しても、デフォルトで自動的に同一レベル・パーティション化が行われます。同一レベル・パーティション化とは、ベース表のパーティションごとに、対応するコレクション表パーティションが存在するということです。子要素は、その親要素のベース表パーティションに対応するコレクション表パーティションに格納されます。

  • 文書レベルのOracle Text索引しかサポートされないため、要素に固有の索引や属性に固有の索引は無効になります。

XMLデータでのOracle Textの使用方法の詳細は、第11章「XMLデータの全文検索」を参照してください。



注意:

Oracle Database 11gリリース1より前のリリースの場合:
  • xdb:storeVarrayAsTableのデフォルト値はfalseでした。

  • OCTはデフォルトでIOTとして格納されていました。


Oracle XML DB名前空間の宣言

XML Schemaに注釈を付けるには、最初にOracle XML DB名前空間を宣言する必要があります。Oracle XML DB名前空間は、次のように宣言します。

http://xmlns.oracle.com/xdb

名前空間をXML Schemaで宣言するには、次のような名前空間宣言をXML Schemaのルート要素に追加します。

xmlns:xdb="http://xmlns.oracle.com/xdb"

名前空間接頭辞(xdb)が使用されていることに注意してください。名前空間接頭辞を使用すると、注釈を追加するときに名前空間をxdbに省略できます。

例3-8に、注釈付きのXML Schema PurchaseOrderの最初の部分を示します。完全なXML Schemaのコードは、例A-1を参照してください。

例3-8 注釈付きの発注書XML Schema、purchaseOrder.xsd

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:xdb="http://xmlns.oracle.com/xdb"
           version="1.0"
           xdb:storeVarrayAsTable="true">
  <xs:element name="PurchaseOrder" type="PurchaseOrderType" xdb:defaultTable="PURCHASEORDER"/>
  <xs:complexType name="PurchaseOrderType" xdb:SQLType="PURCHASEORDER_T">
    <xs:sequence>
      <xs:element name="Reference" type="ReferenceType" minOccurs="1" xdb:SQLName="REFERENCE"/>
      <xs:element name="Actions" type="ActionsType" xdb:SQLName="ACTIONS"/>
      <xs:element name="Reject" type="RejectionType" minOccurs="0" xdb:SQLName="REJECTION"/>
      <xs:element name="Requestor" type="RequestorType" xdb:SQLName="REQUESTOR"/>
      <xs:element name="User" type="UserType" minOccurs="1" xdb:SQLName="USERID"/>
      <xs:element name="CostCenter" type="CostCenterType" xdb:SQLName="COST_CENTER"/>
      <xs:element name="ShippingInstructions" type="ShippingInstructionsType"
                  xdb:SQLName="SHIPPING_INSTRUCTIONS"/>
      <xs:element name="SpecialInstructions" type="SpecialInstructionsType"
                  xdb:SQLName="SPECIAL_INSTRUCTIONS"/>
      <xs:element name="LineItems" type="LineItemsType" xdb:SQLName="LINEITEMS"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="LineItemsType" xdb:SQLType="LINEITEMS_T">
    <xs:sequence>
      <xs:element name="LineItem" type="LineItemType" maxOccurs="unbounded"
                  xdb:SQLName="LINEITEM" xdb:SQLCollType="LINEITEM_V"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="LineItemType" xdb:SQLType="LINEITEM_T">
    <xs:sequence>
      <xs:element name="Description" type="DescriptionType"
                  xdb:SQLName="DESCRIPTION"/>
      <xs:element name="Part" type="PartType" xdb:SQLName="PART"/>
    </xs:sequence>
    <xs:attribute name="ItemNumber" type="xs:integer" xdb:SQLName="ITEMNUMBER"
                  xdb:SQLType="NUMBER"/>
  </xs:complexType>
  <xs:complexType name="PartType" xdb:SQLType="PART_T">
    <xs:attribute name="Id" xdb:SQLName="PART_NUMBER" xdb:SQLType="VARCHAR2">
      <xs:simpleType>
        <xs:restriction base="xs:string">
          <xs:minLength value="10"/>
          <xs:maxLength value="14"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:attribute>
    <xs:attribute name="Quantity" type="moneyType" xdb:SQLName="QUANTITY"/>
    <xs:attribute name="UnitPrice" type="quantityType" xdb:SQLName="UNITPRICE"/>
  </xs:complexType>
  <xs:simpleType name="ReferenceType">
    <xs:restriction base="xs:string">
      <xs:minLength value="18"/>
      <xs:maxLength value="30"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:complexType name="ActionsType" xdb:SQLType="ACTIONS_T">
    <xs:sequence>
      <xs:element name="Action" maxOccurs="4" xdb:SQLName="ACTION" xdb:SQLCollType="ACTION_V">
        <xs:complexType xdb:SQLType="ACTION_T">
          <xs:sequence>
            <xs:element name="User" type="UserType" xdb:SQLName="ACTIONED_BY"/>
            <xs:element name="Date" type="DateType" minOccurs="0" xdb:SQLName="DATE_ACTIONED"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="RejectionType" xdb:SQLType="REJECTION_T">
    <xs:all>
      <xs:element name="User" type="UserType" minOccurs="0" xdb:SQLName="REJECTED_BY"/>
      <xs:element name="Date" type="DateType" minOccurs="0" xdb:SQLName="DATE_REJECTED"/>
      <xs:element name="Comments" type="CommentsType" minOccurs="0" xdb:SQLName="REASON_REJECTED"/>
    </xs:all>
  </xs:complexType>
  <xs:complexType name="ShippingInstructionsType" xdb:SQLType="SHIPPING_INSTRUCTIONS_T">
    <xs:sequence>
      <xs:element name="name" type="NameType" minOccurs="0" xdb:SQLName="SHIP_TO_NAME"/>
      <xs:element name="address" type="AddressType" minOccurs="0" xdb:SQLName="SHIP_TO_ADDRESS"/>
      <xs:element name="telephone" type="TelephoneType" minOccurs="0" xdb:SQLName="SHIP_TO_PHONE"/>
    </xs:sequence>
  </xs:complexType>
  <xs:simpleType name="moneyType">
    <xs:restriction base="xs:decimal">
      <xs:fractionDigits value="2"/>
      <xs:totalDigits value="12"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="quantityType">
    <xs:restriction base="xs:decimal">
      <xs:fractionDigits value="4"/>
      <xs:totalDigits value="8"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="UserType">
    <xs:restriction base="xs:string">
      <xs:minLength value="0"/>
      <xs:maxLength value="10"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="RequestorType">
    <xs:restriction base="xs:string">
      <xs:minLength value="0"/>
      <xs:maxLength value="128"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="CostCenterType">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="4"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="VendorType">
    <xs:restriction base="xs:string">
      <xs:minLength value="0"/>
      <xs:maxLength value="20"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="PurchaseOrderNumberType">
    <xs:restriction base="xs:integer"/>
  </xs:simpleType>
  <xs:simpleType name="SpecialInstructionsType">
    <xs:restriction base="xs:string">
      <xs:minLength value="0"/>
      <xs:maxLength value="2048"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="NameType">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="20"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="AddressType">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="256"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="TelephoneType">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="24"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="DateType">
    <xs:restriction base="xs:date"/>
  </xs:simpleType>
  <xs:simpleType name="CommentsType">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="2048"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="DescriptionType">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
      <xs:maxLength value="256"/>
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

このXML Schema PurchaseOrderは、次の2つの名前空間を定義します。

  • http://www.w3c.org/2001/XMLSchema。これは、W3CによってSchema for Schemasのために予約されています。

  • http://xmlns.oracle.com/xdb。これは、オラクル社によってOracle XML DBのスキーマ注釈用に予約されています。

また、このPurchaseOrderXML Schemaは、次の注釈を含むいくつかの注釈を使用します。

  • PurchaseOrder要素内のdefaultTable注釈。このXML Schemaに準拠するXML文書をpurchaseorderというデータベース表に格納することを指定します。

  • SQLType注釈。

    SQLTypeが最初に出現したとき、complexType要素PurchaseOrderTypeから生成されたSQL型の名前をpurchaseorder_tと指定します。

    SQLTypeが2番目に出現したとき、complexType要素LineItemTypeから生成されたSQL型の名前をlineitem_tと指定し、LineItem要素のコレクションを管理するSQL型の名前をlineitem_vと指定します。

  • SQLName注釈。purchaseorder_tの各SQL属性の明示的な名前を提供します。

図3-3に、XMLSpyのOracleタブを示します。このタブを使用すると、グラフィカル・エディタでの作業中にOracle XML DBのスキーマ注釈をXML Schemaに容易に追加できます。

図3-3 XMLSpyにおけるOracle XML DBスキーマ注釈のサポート

図3-3の説明が続きます
「図3-3 XMLSpyにおけるOracle XML DB Schema注釈のサポート」の説明

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表の作成

XML Schema登録時のSQL型および表の作成

例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_tlineitem_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を登録する際、または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.registerSchemaOPTIONSパラメータで、REGISTER_AUTO_OOLを使用してXML Schemaを登録することができます。その場合、Oracle XML DBは自動的に巨大な型を表外に移動し、エラーの発生確率を低下させます。このオプションを使用する場合、登録パラメータGENTABLESTRUEに設定する必要もあります。

ただしこのオプションは応急処置であることに注意してください。万能の対処ではありません。これにより、通常XML Schemaの登録が可能になります。それによって、自動的に生成された表を確認して記憶域表の作成に使用するオブジェクト属性の数を削減し、用途に適した結果に到達することができます。

削減を成功させるには、次の2つの方法があります。

  • XML文書を管理する複数のXMLType表を使用したトップダウン方法を使用します。この方法は、指定した記憶域表について、SQL型階層内のSQL属性の数を減らします。いずれの表も管理するオブジェクト属性が1000を超えないかぎり、この問題は解決します。

  • SQL型階層内のSQL属性の数を減らすボトムアップ方法を使用します。XML Schemaで定義された一部の要素と属性が縮小されて、単一のCLOB値として格納されます。

いずれの方法とも、XML Schemaに注釈を付けて、特定のcomplexTypeをデータベースに格納する方法を定義します。

トップダウン方法の場合は、SQLInline = "false"およびdefaultTableという注釈によって、XML文書内の一部のサブ要素が別のXMLType表に行として強制的に格納されます。Oracle XML DBは、XMLTypeREFを使用して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に基づくXMLType列および表の作成

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登録の際、パラメータGENTABLESTRUEに設定すると、Oracle XML DBにより自動生成されるCREATE TABLE文と同等です。デフォルトでは、XML Schema注釈storeVarrayAsTableの値はtrueで、XML Schema登録時に、コレクションに対してOrdered Collection Tables(OCT)を自動生成します。このOCTにはシステムが生成した、覚えにくい名前が付けられます。SQL文RENAME TABLEを使用して、わかりやすい名前を付けることができます。

例3-11CREATE 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 Schemaインスタンス・ドキュメントの識別

XML文書をXML Schemaに基づくXMLType表または列に挿入する前に、関連付けられているXML Schemaを識別する必要があります。識別するには、次の2つの方法があります。

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つまたは両方の属性が必要です。

属性noNamespaceSchemaLocationおよびschemaLocation

ターゲットの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">

複数の名前空間の使用

XML Schemaに複数の名前空間で定義された要素が含まれている場合は、XML SchemaごとにschemaLocation属性のエントリが必要です。各エントリは、名前空間宣言およびスキーマの場所を示すヒントで構成されます。また、各エントリは1つ以上の空白文字で区切られています。主要なXML Schemaでターゲットの名前空間が宣言されていない場合でも、インスタンス・ドキュメントには、主要なXML Schemaのスキーマの場所を示すヒントを指定するnoNamespaceSchemaLocation属性を含める必要があります。

データベースを使用したXMLデータ整合性の規定

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 SchemaでtargetNamespaceが宣言されている場合、インスタンス・ドキュメントには、XML Schemaで定義されたtargetNamespaceに文書のルート要素を配置するための適切な名前空間宣言が含まれている必要があります。


注意:

XMLによる制限は、個々のXML文書内で適用されます。データベース(SQL)による制限は、一連のXML文書にわたって適用されます。

XML Schemaの部分検証と全体検証の比較

この項では、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トリガーの場合は、必要なコーディングが表レベルの制約よりわずかに多くなります。このトリガーでは、XMLTypeschemaValidate()メソッドを起動してXML文書を検証します。schemaValidate()を使用するメリットは、例外が発生した場合にそのインスタンス・ドキュメントの問題点に関する追加情報が提供されることです。また、BEFORE INSERTトリガーを使用すると、無効な文書が存在する場合に適切な処置を行うことができます。

XML Schemaの全体検証による処理時間とメモリーの消費

バイナリ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'

SQL制約を使用した参照整合性の規定

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は、データベース・スキーマOEXMLTypepurchaseorderにおける類似の一意性制約を定義しています。さらに、各発注書の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.xmlReference要素に関連付けられたテキスト・ノードに、XML文書PurchaseOrder.xml内の対応するノードと同じ値が含まれています。したがって、両方の文書をOracle XML DBに格納しようとすると、制約reference_is_uniqueに違反します。

また、XML文書InvalidUser.xmlUser要素に関連付けられたテキスト・ノードには、値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コンテンツに対するDML操作

Oracle XML DBを使用してXMLコンテンツを管理するもう1つの主なメリットは、Oracle Databaseの機能を使用してXMLコンテンツの問合せと更新を行う強力で柔軟な機能が提供されることです。次の機能が含まれます。

XPathおよびOracle 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関数またはXMLTypeメソッドによって、戻される値が決まります。たとえば、XPath式の引数がどのノードもターゲットにしていない場合、SQL関数extractNULLを戻します。deleteXMLなど更新のSQL関数は、入力されたXMLデータをそのままの状態で戻します。どのノードもターゲットになっていない場合にはエラーは発生しませんが、XPath式の引数が、属性ノードやテキスト・ノードなどの不適切なノードをターゲットにしている場合は、更新のSQL関数でエラーが発生します。


Oracle XML DBに格納されたXMLコンテンツの問合せ

この項では、Oracle XML DBの問合せ方法およびXMLコンテンツの取出し方法について説明します。この項の内容は次のとおりです。

XML文書PurchaseOrder

この項では、次の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を使用したXML文書のコンテンツの取出し

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.

EXTRACTを使用したXML文書のフラグメントまたはノードへのアクセス

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.

XMLCASTおよびXMLQUERYを使用したテキスト・ノードおよび属性値へのアクセス

テキスト・ノードおよび属性値には、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.

関連項目:


XMLTABLEを使用したXMLTypeフラグメントでのSQL操作の実行

例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式を評価するためのコンテキストとして、XMLTypepurchaseorderのコンテンツ(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.

XMLTableCOLUMNS句を使用して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 BYGROUP BYなどのSQLキーワードをSQL関数XMLTableによって作成された仮想表データに適用する方法も示しています。

この例の問合せでは、最初に、SQL関数existsNodeへのXPath引数と一致する一連のXML文書が検索されます。次に、選択された文書ごとに、一連のLineItemノードが含まれる仮想表が生成されます。最後に、PurchaseOrder文書ごとにLineItemノードの数がカウントされます。相関結合によって、GROUP BYLineItem要素が属する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.

XMLEXISTSを使用したXML文書のコンテンツの検索

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属性値が715515009058Part要素が含まれている必要があります。

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属性値が715515009058Part要素が含まれている必要があります。

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 WHERE句でのXMLEXISTSの使用

前の項の例では、SQL/XML関数XMLExistsSELECTリスト内で使用して、XML文書に含まれる情報を戻す方法を示しました。XMLExistsWHERE句で使用して、SELECTUPDATEまたは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関数XMLQueryXMLExistsを使用して、最初のLineItem要素にId 715515009058の品目の発注が含まれるPurchaseOrder要素についてReferenceを検索します。関数XMLExistsWHERE句で使用して、選択する行を決定します。さらに、XMLQuerySELECTリスト内で使用して、選択した文書のどの部分を結果に表示するかを制御します。

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コンテンツへのビューを使用したリレーショナル・アクセス

Oracle XML DBで提供されるXML固有の関数およびメソッドを使用すると、XMLコンテンツへのリレーショナル・アクセスを提供する従来のリレーショナル・ビューを作成できます。これによって、Oracle Databaseには対処していてもXMLには対処していないプログラマ、ツールおよびアプリケーションでも、データベースに格納されたXMLコンテンツを操作できます。

リレーショナル・ビューでは、XPath式とextractValueXMLTableなどのSQL関数を使用して、ビュー内の列とXML文書内のノードとの間のマッピングを定義します。XML文書が、CLOBインスタンスとしてではなく、構造化(オブジェクト・リレーショナル)XML記憶域またはバイナリXML記憶域を使用して格納されている場合のみ、パフォーマンス上の理由からこの方法をお薦めします。


関連項目:


単一レベルのXMLデータの分割

XMLType表内の各文書をリレーショナル・ビューの行として公開する必要がある場合は、次の方法を使用できます。

  1. CREATE OR REPLACE VIEWを使用して、ビューを構成する一連の列を定義します。

  2. 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つの行が含まれます。

複数レベルのXMLデータの分割

XMLType表に複数レベルで含まれているデータをリレーショナル・ビューの個別の行として公開する必要がある場合は、単一レベルの分割と同じ一般的な方法を使用し、1)ビューを構成する列の定義、および、2)列へのXMLノードのマップを行います。ただし、この場合は、分割してリレーショナル列に格納する必要がある各文書レベルにSQL/XML標準関数XMLTableを適用することをお薦めします。

この方法は、XMLType表内の文書とビュー内の行が1対他(1:N)関係の場合はいつでも使用できます。

たとえば、各PurchaseOrder要素にLineItems要素が含まれていて、この要素に1つ以上のLineItem要素が含まれているとします。各LineItem要素には、DescriptionItemNumber属性などの子要素があります。このような下位レベルのデータをリレーショナル値としてアクセス可能にするには、PurchaseOrder要素とLineItemコレクションの両方を分割する必要があります。この分割は、いずれもXMLTableを使用して行われます。要素PurchaseOrderを分割すると、LineItem要素は、XMLフラグメントが含まれている型XMLTypeのリレーショナル列にマップされます。この列は次に、XMLTypeへの2回目のコールに渡され、リレーショナル値の複数の行として複数の部分に分割されます。例3-32を参照してください。

例3-32 ビューを使用したコレクションの各メンバーへのアクセス

この例では、XMLTypepurchaseorder内の文書とビューの行の間に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の各行は、XMLTypepurchaseorderに格納されているXML文書内の各LineItem要素に対応しています。

CREATE OR REPLACE VIEW文では、ビューを構成する一連の列を定義します。SELECT文は、コンテキストとしてpurchaseorder表を関数XMLTableに渡し、仮想表pを作成します。この表には、列referenceおよびlineitemがあります。これらの列には、発注書のReference要素およびLineItem要素がそれぞれ含まれます。

lineitemにはLineItem要素のコレクションがXMLTypeインスタンスとして含まれ、各行が各LineItem要素に対応します。これらの行は次に、2つ目のXMLTable式に渡され、そのコンテキストとして機能します。この2つ目のXMLTable式により、明細/項目行の仮想表が作成され、各列が要素LineItemの様々な子孫ノードに対応します。これらの子孫の大半は属性(ItemNumberPart/@Idなど)であり、そのうちの1つはDescription子要素です。

Reference要素は、ビューpurchaseorder_detail_viewに列referenceとして含まれます。この要素は、ビューpurchaseorder_detail_viewの行をビューpurchaseorder_master_viewの対応する行に結合する際に使用できる外部キーを提供します。CREATE VIEW文の相関結合によって、ビューにアクセスするたびに、Reference要素と関連するLineItem要素との間の1対多(1:N)関係が保持されます。

リレーショナル・データとしてのXMLコンテンツの問合せ

この項の例では、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の行に値が SBELLuserid列が含まれている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コンテンツの更新

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.

XML Schemaに基づくXML文書および基づかないXML文書の更新

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に基づかないデータと基づくデータの両方に適用されます。

Oracle XML DBでの名前空間のサポート

名前空間のサポートは、W3CのXML勧告の主要な特徴です。Oracle XML DBでは、W3Cの名前空間勧告を完全にサポートしています。XMLTypeメソッドおよびXML固有のSQL関数はすべて、名前空間接頭辞を含むXPath式で使用できます。XPath式で使用する名前空間接頭辞を正しく解決するために、すべてのメソッドおよび関数は、名前空間宣言を指定するオプションのnamespace引数を受け入れます。指定されたXPath式に名前空間接頭辞が含まれている場合は、常にnamespaceパラメータが必要です。パラメータnamespaceが指定されている場合は、デフォルトの名前空間がnoNamespace名前空間でないかぎり、このパラメータでデフォルトの名前空間と接頭辞付き名前空間を明示的に宣言する必要があります。パラメータnamespaceが指定されていない場合、Oracle XML DBでは、XPath式に関して次のことを前提とします。

XPath式の解決に必要な名前空間を正しく定義しないと、XPathを使用した操作が予測どおりに機能しません。名前空間宣言が不適切または欠落している場合、操作の結果はエラーではなくNULLになります。混同を避けるため、noNamespace以外の名前空間がXPath式またはターゲットのXML文書に存在する場合は、常に、デフォルトの名前空間の宣言を含む一連の名前空間宣言をすべて渡してください。

XMLTypeメソッドとXML固有のSQL関数の処理

Oracle XML DBは、DOMベースまたはSQLベースの方法を使用して、extractextractValueexistsNodeなどのSQL関数、およびそれらと同等のXMLTypeメソッドを処理します。

XPathのリライトの理解および最適化

XPathリライトによって、XPathを使用した関数が従来のリレーショナルSQL文に変換されるため、その関数が含まれるSQL文のパフォーマンスが向上します。これにより、データベース・オプティマイザがXPath表記法やXMLデータ・モデルを認識する必要がなくなります。データベース・オプティマイザは、リライトされたSQL文を他のSQL文と同じ方法で処理します。このように、データベース・オプティマイザは従来の関係代数に基づいて実行計画を導出できます。その結果、XPathを使用した関数を含むSQL文がリレーショナルSQL文とほぼ同じパフォーマンスで実行されます。

XPathのリライトを実行するには、次の条件を満たす必要があります。

十分なレベルのスケーラビリティとパフォーマンスを実現するOracle XML DBアプリケーションを開発するには、XPathのリライトの概念、およびXPathのリライトを実行するための条件を理解することが重要です。

EXPLAIN PLANを使用した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.

索引を使用した、XPathを使用する関数のパフォーマンスの改善

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オブジェクトにコレクションを変換すると、解析のコストが発生しなくなります。ただし、この場合も、各コレクション・メンバーに対する操作を実行する前に、コレクションをメモリーにロードする必要があります。

OCTとして格納されたコレクションでの、索引を使用した問合せのチューニング

例3-43では、部品番号717951002372(Id属性の値が717951002372Part要素)の発注を含む文書から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で問合せが効率的に解決されているか判別されます。

ACLベースのセキュリティに対応したEXPLAIN PLAN: SYS_CHECKACLフィルタ

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の抽象的概念は、基礎となる格納テクノロジに依存しないアプリケーションを開発することを可能にします。従来のリレーショナル・アプリケーションと同様に、索引を作成または削除することによってアプリケーションのパフォーマンスをチューニングできるため、アプリケーションをリライトする必要はありません。

XMLを使用したリレーショナル・データベース・コンテンツへのアクセス

Oracle XML DBには、リレーショナル・データからXMLを生成するいくつかの方法が用意されています。最も強力で柔軟性の高い方法は、発展中のSQL/XML標準に基づいて生成する方法です。このANSI標準では、SELECT文から直接XMLを生成できる一連のSQL関数が定義されています。これらの関数を使用すると、問合せから、従来の表形式の結果セットではなく、1つ以上のXML文書を生成できます。SQL/XML標準関数を使用すると、ほとんどすべての形式のXMLデータを生成できます。次の関数が含まれます。

例3-46 SQL/XML関数を使用したXMLの生成

この問合せは、表departmentslocationscountriesemployeesおよび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要素には、サブ要素のNameLocationおよびEmployeeListも含まれます。

  • Name要素に関連付けられたテキスト・ノードは、departments表のname列から生成されます。

  • Location要素には、子要素AddressCityStateZipおよび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を使用して作成された要素の子孫でない場合のみです。

DBURITypeを使用したリレーショナル表からのXMLの生成

リレーショナル・データから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式によって、値が10DEPARTMENT_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文書を生成します。

XSL変換とOracle XML DB

W3CのXSLT勧告は、XML文書の形式を別の形式に変換する方法を指定するためのXML言語を定義します。変換には、1つのXML Schemaから別のXML Schemaへのマッピング、またはXMLからHTMLやWMLなどの他の形式へのマッピングが含まれる場合があります。


関連項目:

XSLT標準の詳細は、http://www.w3.org/XML/Schemaを参照してください。

XSL変換は、通常、必要なメモリー量および処理量の面からコストがかかります。文書の様々な部分へのランダムなアクセスが可能になるように、ソース・ドキュメントとスタイルシートの両方を解析してメモリー構造にロードする必要があります。ほとんどのXSLプロセッサは、DOMを使用して両方の文書のメモリー内表現を提供します。次に、XSLプロセッサは、スタイルシートをソース・ドキュメントに適用して、3番目の文書を生成します。

Oracle XML DBには、XSL変換をデータベース内部で実行できるXSLTプロセッサが含まれています。この方法で、Oracle XML DBは、XML固有のメモリーを最適化できます。これによって、変換の実行に必要なメモリー量が大幅に削減されます。また、文書の解析に関連するオーバーヘッドも削減できます。ただし、これらの最適化を使用できるのは、変換対象のソースがXML Schemaに基づくXML文書である場合のみです。

Oracle XMLでは、次の3つの方法でXSLプロセッサを起動できます。

これらの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リポジトリの使用

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リポジトリのインストールおよび削除

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日でセキュリティ・ガイド』を参照してください。

Oracle XML DBで提供される名前レベル・ロック

リレーショナル・データベースを使用して階層フォルダ構造を保持する場合、フォルダに対して項目を追加または削除するときに高度な同時実行性を保証することは重要な問題です。従来のファイル・システムでは、トランザクションの概念はありません。各操作(ファイルの追加、サブフォルダの作成、ファイル名の変更、ファイルの削除など)は、基本トランザクションとして処理されます。操作が完了すると、ファイル・システムのすべてのユーザーに対して変更がすぐに反映されます。


注意:

データベースによって適用されるトランザクション・セマンティクスの結果として、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を最小限にできます。これは、短時間の間に複数のアプリケーションが同じディレクトリ内にファイルを生成する場合に役立ちます。たとえば、トレース・ファイルやログ・ファイルを生成する場合、印刷または電子メール配信用にスプール・ディレクトリを保持する場合などです。

プロトコルまたはSQLを使用した、リポジトリのコンテンツへのアクセスおよび処理

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-4 Oracle XML DBリポジトリへのファイルのコピー

図3-4の説明が続きます
「図3-4 Oracle XML DBリポジトリへのファイルのコピー」の説明

FTPを使用したOracle XML DBへのコンテンツのアップロード

例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文書を表示する操作を示します。

図3-5 HTTPとURLを使用したパスベースのアクセス

図3-5の説明が続きます
「図3-5 HTTPとURLを使用したパスベースのアクセス」の説明

プログラムを使用したOracle XML DBリポジトリへのアクセス

Oracle XML DBリポジトリは、SQLから直接アクセスして更新できます。つまり、SQLを使用してOracle Databaseと対話できるアプリケーションまたはプログラミング言語からも、Oracle XML DBリポジトリに格納されたコンテンツにアクセスして更新できるということです。Oracle XML DBには、プログラムによるリソースの作成、変更および削除を可能にするメソッドが備わったPL/SQLパッケージDBMS_XDBが含まれています。

例3-54 DBMS_XDBを使用したテキスト・ドキュメント・リソースの作成

次の例では、DBMS_XDBを使用してリソースを作成する方法を示します。このリソースは、提供されたテキストを含む簡単なテキスト・ドキュメントです。

DECLARE
  res BOOLEAN;
BEGIN
  res := DBMS_XDB.createResource('/home/QUINE/NurseryRhyme.txt',
                                 bfilename('XMLDIR', 'tdadxdb-03-01.txt'),
                                 nls_charset_id('AL32UTF8'));
END;
/

リポジトリ内のXMLコンテンツのアクセスおよび更新

この項では、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で識別されるデフォルト表にオブジェクトとして格納されます。リポジトリには、文書に関するメタデータと、コンテンツが含まれたデフォルト表の行を識別するポインタ(XMLTypeREF)のみが含まれます。

リポジトリへの非XML文書の格納も可能

別の種類の文書をリポジトリに格納することも可能です。非XML文書またはXML Schemaに基づかないXML文書をリポジトリに格納すると、文書のコンテンツは、その文書に関するメタデータとともにLOBに格納されます。

フォルダと文書の作成、削除、名前変更、移動などを実行するためのPL/SQLパッケージ

Oracle XML DBリポジトリはSQLを使用してアクセスおよび更新できるため、PL/SQLプロシージャをコールできるアプリケーションはすべて、このリポジトリを使用できます。すべてのSQLおよびPL/SQLリポジトリ操作はトランザクション型であるため、リポジトリとそのコンテンツへのアクセスは、リポジトリのアクセス制御リスト(ACL)とデータベース・セキュリティの対象となります。

提供されているPL/SQLパッケージDBMS_XDBDBMS_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;
/

SQLを使用した文書のコンテンツへのアクセス

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関数XMLTableXMLNAMESPACES句を使用して定義されます。


関連項目:

XMLTableXMLNAMESPACES句の詳細は、第18章「Oracle XML DBでのXQueryの使用」を参照してください。

XML Schemaに基づく文書のコンテンツへのアクセス

XML Schemaに基づくXML文書のコンテンツにアクセスするには、次の2つの方法があります。

  • XML Schemaに基づかないXML文書の場合と同様に、リソース・ドキュメントを使用してアクセスします。この方法では、RESOURCE_VIEWを使用して、XML Schemaに基づく様々な種類のXML文書を1つのSQL文で問い合せることができます。

  • XML SchemaをOracle XML DBに登録したときに定義したデフォルト表の行としてアクセスします。

結合でXMLRef要素を使用した、リソース・コンテンツへのアクセス

リソース・ドキュメントの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に格納されたコンテンツの更新および編集

図3-6の説明が続きます
「図3-6 Microsoft Wordを使用した、Oracle XML DBに格納されたコンテンツの更新および編集」の説明

Microsoft Wordなどの編集アプリケーションを使用して、Oracle XML DBに格納されたXML文書を更新すると、データベースは、文書の新しいコンテンツが含まれた入力ストリームを受け取ります。ただし、Wordなどの製品で更新された場合、Oracle XML DBは文書がどのように変更されたかを識別できません。これは、部分更新は不可能なため、文書全体を再解析し、元の文書から導出されたすべてのオブジェクトを、新しいコンテンツから導出されたオブジェクトに置換する必要があることを意味します。

SQLを使用したリポジトリのコンテンツの更新

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 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-propertiesupdateなど)が決まります。各リポジトリ操作には、現行ユーザーがその操作の実行を許可されているかどうかを判断するために、ACLの確認が含まれています。デフォルトでは、新規のリソースはその親フォルダのACLを継承します。ただし、PL/SQLプロシージャDBMS_XDB.setACLを使用してリソースのACLを設定することもできます。Oracle XML DBのリソースのセキュリティの詳細は、第27章「アクセス制御リストおよびセキュリティ・クラス」を参照してください。

次の例で、現行ユーザーはQUINEです。問合せでは、フォルダ/publicのリソースの数が戻されます。このフォルダには、f1f2の2つのリソースのみが存在すると想定します。また、f1のACLではread-properties権限がQUINEに付与されますが、f2のACLではQUINEに付与される権限はないと想定します。ユーザーがリソースを参照するには、そのリソースに対するread-properties権限が必要です。QUINEf1のみ参照できるため、問合せの結果は1です。

SELECT count(*) FROM RESOURCE_VIEW r WHERE under_path(r.res, '/public') = 1;

COUNT(*)
--------
       1

Oracle XML DBのトランザクション・セマンティクス

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および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)

関連項目:


RESOURCE_VIEWおよびPATH_VIEW内のリソースの問合せ

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文書です。メタデータには、CreationDateCreatorOwnerModificationDateDisplayNameなどの情報が含まれています。リソース・ドキュメントのコンテンツは、extractextractValueexistsNodeupdateXMLなどの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.

Oracle XML DBの階層リポジトリ索引

従来のリレーショナル・データベースでは、パスベースのアクセスおよびフォルダ限定の問合せは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ファイルをリポジトリにロードすると、次の順序でイベントが発生します。

  1. Oracle XML DBは、XML文書のルート要素を調べ、既知(登録済)のXML Schemaに関連付けられているかどうかを確認します。このとき、文書にXMLSchema-instance名前空間の名前空間宣言が含まれているかどうかが確認され、文書に関連付けられたXML Schemaを識別するschemaLocation属性またはnoNamespaceSchemaLocation属性が検索されます。

  2. 文書が既知のXML Schemaに基づいている場合は、XML SchemaのメタデータがXML Schemaのキャッシュからロードされます。

  3. XML文書は解析され、XML Schemaから導出された一連のSQLオブジェクトに分解されます。

  4. XMLファイルから作成されたSQLオブジェクトは、XML Schemaがデータベースに登録されたときに定義されたデフォルト表に格納されます。

  5. リソース・ドキュメントは、処理された文書ごとに作成されます。これによって、リポジトリを使用して、文書のコンテンツにアクセスできます。XML Schemaに基づくXMLTypeのリソース・ドキュメントには、XMLRef要素が含まれています。この要素のコンテンツはXMLTypeREFで、リソースに関連付けられたコンテンツが含まれるデフォルト表で行を検索するときに使用できます。

ブラウザを使用した、リレーショナル・データのXMLとしての表示

Oracle XML DBに組み込まれたHTTPサーバーでは、ブラウザを使用して、Oracle XML DBリポジトリに格納された文書にアクセスできます。リソースにはXMLType表またはビューの行に対するREFを含めることができるため、パスを使用してこのようなコンテンツにアクセスできます。

DBUriサーブレットを使用したブラウザから表またはビューへのアクセス

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など読みやすい形式で表示できます。


関連項目:

「DBUriServlet」

スタイルシート処理を開始するには、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に設定します。

DBUriサーブレットを使用したXSL変換

図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-7 DBUriサーブレットを使用したPurchaseOrderのデータベースXSL変換

図3-7の説明が続きます
「図3-7 DBUriサーブレットを使用したPurchaseOrderのデータベースXSL変換」の説明

図3-8に、HTML文書として表示されたdepartments表を示します。コーディングは不要で、これを表示するためには、SQL/XML関数に基づくXMLTypeビュー、業界標準のXSLスタイルシートおよびDBUriサーブレットのみが必要です。

図3-8 DBUriサーブレットを使用したDepartments表のデータベースXSL変換

図3-8の説明が続きます
「図3-8 DBUriサーブレットを使用したDepartments表のデータベースXSL変換」の説明



脚注の凡例

脚注1: XML Schema注釈maintainOrder = "false"を使用すると、Ordered Collectionでなく、Unordered Collectionが使用されます。XMLデータの場合、Ordered Collection(maintainOrder = "true")の使用をお薦めします。