プライマリ・コンテンツに移動
Oracle® XML DB開発者ガイド
12cリリース1 (12.1)
B71282-04
目次へ移動
目次
索引へ移動
索引

前
次

3 Oracle XML DBの使用方法の概要

Oracle XML DBの様々な使用方法の概要について説明します。

この概要では、XMLType表および列の作成およびパーティション化、データ整合性の適用、データベースXMLコンテンツのロード、問合せおよび更新、リレーショナル・データからのXMLデータの生成を行う方法について説明します。また、XML文書で使用するキャラクタ・セットをOracle XML DBが判断する方法についても説明します。

主なXML Schema機能を示す発注書

この章の例の多くでは、発注書のXMLコンテンツへのアクセスおよび管理の方法を示します。発注書は高度に構造化された文書ですが、ほとんど構造化されていないXML文書に対しても、ここに示す方法を使用することができます。

ここで例として使用する発注書は、次のような一般的なXML文書の主要な機能を示す発注書XML Schemaに準拠しています。

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

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

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

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

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

関連項目:

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

3.1 XMLType表および列の作成

XMLTypeは抽象データ型であるため、XMLType表または列は容易に作成できます。

記憶域オプションとXML Schemaを指定しない基本的なCREATE TABLE文では、XMLTypeデータはバイナリXMLとして格納されます。脚注 1

例3-1ではXMLType列を作成し、例3-2ではXMLType表を作成します。

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

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

例3-2 XMLType表の作成

CREATE TABLE mytable2 OF XMLType;

3.2 バイナリXMLとして格納されたXMLTypeデータでの仮想列の作成

仮想列は、バイナリXMLとして格納されているXMLTypeデータに対してのみ作成できます。このような列は、データのパーティション化および制約に役立ちます。

XMLデータの仮想列は他のデータ型の場合と同じ方法で作成できますが、若干異なる構文を使用します。(特に、列定義に関連付けて制約を指定することができません。)

XML要素または属性に基づく仮想列を作成するには、その要素や属性を含むSQL式によって仮想列を定義します。したがって、作成される列はファンクション・ベースです。

これには、例3-3および例3-4に示すように、SQL/XML関数XMLCastおよびXMLQueryを使用します。関数XMLQueryのXQuery式引数は、子および属性の軸のみを使用する簡単なXPath式にする必要があります。

例3-3では、バイナリXMLとして格納されるXMLTypepo_binaryxmlを作成しています。属性/PurchaseOrder/@orderDate内のXMLデータを表す仮想列date_colを作成しています。

例3-4では、主キー用のVARCHAR2key_colとXMLデータ用のXMLTypexml_colという2つの列を持つリレーショナル表rel_tabを作成しています。

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

関連項目:

例3-3 XMLType表内のXML属性の仮想列の作成

CREATE TABLE po_binaryxml OF XMLType
  XMLTYPE STORE AS BINARY XML
  VIRTUAL COLUMNS
    (date_col AS (XMLCast(XMLQuery('/PurchaseOrder/@orderDate'
                                   PASSING OBJECT_VALUE RETURNING CONTENT)
                          AS DATE)));

例3-4 XMLType列内のXML属性の仮想列の作成

CREATE TABLE reltab (key_col VARCHAR2(10) PRIMARY KEY,
                     xml_col XMLType)
  XMLTYPE xml_col STORE AS BINARY XML
  VIRTUAL COLUMNS
    (date_col AS (XMLCast(XMLQuery('/PurchaseOrder/@orderDate'
                                   PASSING xml_col RETURNING CONTENT)
                          AS DATE)));

3.3 バイナリXMLとして格納されたXMLTypeデータが含まれる表のパーティション化

バイナリXMLとして格納されたXMLTypeデータが含まれる表をパーティション化できます。

2つの可能性があります。

  • 表は、XMLType列および非XMLType列を持つリレーショナル形式です。

  • 表は、データ型XMLTypeです。

XMLType列の場合、非XMLType列をパーティション化キーとして使用します。例3-5で説明します。

この例では、XMLデータに関して新しいことや特別なことは示されていません。列の1つにXMLTypeデータが含まれることは重要ではありません。異なるのは他のこと、つまり、XMLType表がパーティション化されていることです。

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

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

手順は次のとおりです。

  1. 目的のXML要素または属性に対応する仮想列を定義します。

  2. その列を使用して、XMLTypeデータを一括してパーティション化します。

これは例3-6で説明されています。仮想列date_colは、発注書の要素PurchaseOrderorderDate属性をターゲットにしています。この列は、パーティション化キーとして使用されています。

XMLデータが含まれるパーティション化表を使用して最適なパフォーマンスを実現するには、XMLType表ではなくXMLType列を使用し、これにより、非XMLType列を使用してパーティション化することをお薦めします。

注意:

  • 仮想列を使用してXMLType表をパーティション化できるのは、記憶域モデルがバイナリXMLである場合のみです。レンジ、ハッシュおよびリストのパーティション化がサポートされています。

  • XMLとして格納されたXMLType表のパーティション化は、11gリリース2 (11.2)以降でサポートされます。データベースの互換性(ファイルinit.ora内のパラメータcompatible)が11.2以上の場合にのみサポートされます。

  • リレーショナル表にXMLTypeが含まれる場合、XMLデータの仮想列を定義する列を使用して表をパーティション化することはできません。

例3-5 XMLType列を持つリレーショナル表のパーティション化

CREATE TABLE reltab (key_col VARCHAR2(10) PRIMARY KEY,
                     xml_col XMLType)
  XMLTYPE xml_col STORE AS BINARY XML
  PARTITION BY RANGE (key_col)
    (PARTITION P1 VALUES LESS THAN ('abc'),
     PARTITION P2 VALUES LESS THAN (MAXVALUE));

例3-6 XMLType表のパーティション化

CREATE TABLE po_binaryxml OF XMLType
  XMLTYPE STORE AS BINARY XML
  VIRTUAL COLUMNS
    (date_col AS (XMLCast(XMLQuery('/PurchaseOrder/@orderDate'
                                   PASSING OBJECT_VALUE RETURNING CONTENT)
                          AS DATE)))
  PARTITION BY RANGE (date_col)
    (PARTITION orders2001 VALUES LESS THAN (to_date('01-JAN-2002')),
     PARTITION orders2002 VALUES LESS THAN (MAXVALUE));

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

SQLおよびXMLの能力と、ルールを適用するデータベースの機能を組み合せることができます。

XML Schemaによって提供される機能を補完するために、SQLを使用できます。XMLType表または列に格納できるのは、整形式のXML文書のみです。整形式のXML文書とは、XML宣言で宣言されたXMLバージョンの構文に準拠しているXML文書です。これには、ルート要素が単一か、タグが適切にネストされているかなどが含まれます。さらに、XMLType表または列がXML Schemaに制限される場合、その表または列に格納できるのはXML Schemaに準拠する文書のみです。これ以外のXML文書をXML Schemaに基づくXMLTypeに格納または挿入しようとすると、エラーが発生します。例3-7に、これを示します。

このようなエラーは、コンテンツが直接XMLType表に挿入されるときにのみ発生します。Oracle XML DBが、XML Schemaにより定義されたクラスのメンバーとして文書を認識していなかったことを示します。スキーマにより定義されたクラスのメンバーとして認識される文書は、次の条件を満たしている必要があります。

  • XML文書のルート要素の名前が、XMLType表または列の定義で使用するグローバル要素の名前と一致する必要があります。

  • XML文書にXMLSchema-instance名前空間の適切な属性が含まれているか、またはXMLTypeコンストラクタかXMLTypecreateSchemaBasedXML()メソッドを使用してXML文書がXML Schemaに明示的に関連付けられている必要があります。

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

注意:

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

例3-7 不適切な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.

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

SQL制約およびデータベース・トリガーを使用して、一意性と外部キーの関係など、データ整合性プロパティを保証できます。

W3CのXML Schema勧告では、XML文書のコンテンツを定義するための強力な言語が定義されています。ただし、現在はW3CのXML Schema勧告で扱われていない簡単なデータ管理の概念がいくつかあります。たとえば、要素または属性の値が次のいずれかのプロパティを持っているかを確認できることなどです。

  • XML文書のセット間で一意であること(UNIQUE制約)

  • 現在の文書以外の特定のデータ・ソース内に存在していること(FOREIGN KEY制約)

ただし、Oracle XML DBでは、そうした制約を強制的に適用できます。XMLデータで整合性を規定するために使用するメカニズムは、リレーショナル・データで整合性を規定するためのメカニズムと同じです。一意性と外部キーの関係などの簡単なルールは、SQL制約を指定することによって規定できます。複雑なルールは、データベース・トリガーを指定して規定できます。

Oracle XML DBを使用すると、XML Schema構造体を使用して指定できるルールに加え、データベースを使用して、ビジネス・ルールもXMLコンテンツに実施することができます。データベースでは、XMLが表に直接挿入されているか、Oracle XML DBリポジトリでサポートされているプロトコルの1つを使用してアップロードされているかに関係なく、これらのビジネス・ルールを規定します。

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

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

手順は次のとおりです。

  1. 目的のXML要素または属性に対応する仮想列を定義します。

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

バイナリXMLデータは、XMLType表またはリレーショナル表のXMLType列に含まれる場合があります。前者の場合、必要に応じて、制約の作成をCREATE TABLE文の一部として含めることができます。後者の場合、リレーショナル表が作成された後、ALTER TABLE文を使用して制約を作成する必要があります。

例3-8 仮想列を使用したバイナリXML表の制約

この例では、XMLType表の場合の方法を示しています。ここでは、発注書のReference要素を使用して、仮想列c_xtabrefを定義しています。この列に、表に格納されたすべての文書間でノード/PurchaseOrder/Reference/text()の値が一意であることを保証する一意性制約reference_is_uniqueを定義しています。表にはOE.purchaseorderのデータが入力されています。次に、重複文書DuplicateReference.xmlを挿入しようとしますが、これは一意性制約に違反し、エラーが発生しています。

CREATE TABLE po_binaryxml OF XMLType
  (CONSTRAINT reference_is_unique UNIQUE (c_xtabref))
  XMLTYPE STORE AS BINARY XML
  VIRTUAL COLUMNS
    (c_xtabref AS (XMLCast(XMLQuery('/PurchaseOrder/Reference'
                                      PASSING OBJECT_VALUE RETURNING CONTENT)
                             AS VARCHAR2(32))));
 
INSERT INTO po_binaryxml SELECT OBJECT_VALUE FROM OE.purchaseorder;

132 rows created.
 
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-9 仮想列を使用したバイナリXML列の制約: 一意性

この例では、リレーショナル表のXMLType列の場合の方法を示しています。ここでは、仮想列c_xcolref、および例3-8で定義した一意性制約を参照するfk_refを定義しています。例3-8の場合のように、これは、XMLTypepo_binxml_colに格納されたすべての文書間でノード/PurchaseOrder/Reference/text()の値が一意であることを保証しています。

この例では、XMLType列にOE.purchaseorderの同じデータが入力されています。次に、重複文書DuplicateReference.xmlを挿入しようとしますが、これは一意性制約に違反し、エラーが発生しています。

CREATE TABLE po_reltab (po_binxml_col XMLType)
  XMLTYPE po_binxml_col STORE AS BINARY XML
  VIRTUAL COLUMNS
    (c_xcolref AS (XMLCast (XMLQuery('/PurchaseOrder/Reference'
                                    PASSING po_binxml_col RETURNING CONTENT)
                           AS VARCHAR2(32))));

ALTER TABLE po_reltab ADD CONSTRAINT reference_is_unique UNIQUE (c_xcolref));

INSERT INTO po_reltab SELECT OBJECT_VALUE FROM OE.purchaseorder;
INSERT INTO po_reltab
  VALUES (XMLType(bfilename('XMLDIR', 'DuplicateReference.xml'),
                  nls_charset_id('AL32UTF8')));
INSERT INTO po_reltab
*
ERROR at line 1:
ORA-00001: unique constraint (OE.REFERENCE_IS_UNIQUE) violated

例3-10 仮想列を使用したバイナリXML列の制約: 外部キー

この例は例3-9と似ていますが、例3-8で定義した一意性制約を持つ列を参照する外部キー制約fk_refを使用しています。ここでは、ファイルDuplicateReference.xmlの文書の挿入は、この文書が表po_binaryxmlの(仮想)列c_tabref内にあるため、成功しています。表po_binaryxml内の文書と一致しない文書の挿入です。

CREATE TABLE po_reltab (po_binxml_col XMLType)
  XMLTYPE po_binxml_col STORE AS BINARY XML
  VIRTUAL COLUMNS
    (c_xcolref AS (XMLCast (XMLQuery('/PurchaseOrder/Reference'
                                    PASSING po_binxml_col RETURNING CONTENT)
                           AS VARCHAR2(32))));

ALTER TABLE po_reltab ADD CONSTRAINT fk_ref FOREIGN KEY (c_xcolref)
                                            REFERENCES po_binaryxml(c_xtabref);

INSERT INTO po_reltab
  VALUES (XMLType(bfilename('XMLDIR', 'DuplicateReference.xml'),
                  nls_charset_id('AL32UTF8')));

INSERT INTO po_reltab
  VALUES ('<PurchaseOrder><Reference>Not Compliant</Reference></PurchaseOrder>');
INSERT INTO po_reltab VALUES ('<PurchaseOrder><Reference>Not Compliant
</Reference></PurchaseOrder>')
*
ERROR at line 1:
ORA-02291: integrity constraint (OE.FK_REF) violated - parent key not found

例3-11 FTPを使用してXMLをロードしたときのデータベース整合性の規定

XML Schemaに基づくXMLコンテンツがOracle XML DBリポジトリにロードされると、制約およびトリガーを使用して定義された整合性ルールも規定されます。この例では、XML Schemaに基づくXMLコンテンツが、FTPなどのプロトコルを使用してOracle XML DBリポジトリにアップロードされると、データベース整合性も適用されることを示します。この例では、一意性以外の別の制約も違反しています。

$ 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

プロトコルを使用して文書をアップロードしているときにエラーが発生すると、Oracle XML DBはクライアントに対して完全なSQLエラー・トレースを提供します。エラーの解析とレポートの方法は、クライアント・アプリケーションに組み込まれたエラー処理によって決まります。たとえば、コマンドラインFTPツールなどのクライアントはOracle XML DBから戻されたエラーをレポートし、Microsoft Windows Explorerなどのクライアントは単に汎用エラー・メッセージをレポートします。

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

XMLコンテンツをOracle XML DBにロードする方法は複数あります。

3.5.1 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 INSERTを使用して、コレクションを含む大規模な文書を(XMLType列ではなく)XMLType表に挿入する場合、Oracle XML DBによってロード時間とメモリー使用量が最適化されます。

例3-13に、XMLコンテンツをXMLType表に挿入する方法を示します。この挿入を行う前に、処理するファイルが含まれたディレクトリを指すデータベース・ディレクトリ・オブジェクトを作成する必要があります。作成するためには、CREATE ANY DIRECTORY権限が必要です。

関連項目:

例3-12 データベース・ディレクトリの作成

CREATE DIRECTORY xmldir AS path_to_folder_containing_XML_file;

例3-13 XMLType表へのXMLコンテンツの挿入

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

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

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

JavaでDOMを使用してXMLTypeインスタンスをロードできます。

例3-14は、ドキュメント・オブジェクト・モデル(DOM)を指定して最初にJavaでXMLTypeインスタンスを作成することによって、XMLコンテンツをOracle XML DBにロードする方法を示しています。

単純なバルク・ローダー・アプリケーションがOracle Technology Network (OTN)サイト(http://www.oracle.com/technetwork/database-features/xmldb/overview/index.html)で入手可能です。これにはJava Database Connectivity (JDBC)を使用してXMLファイルのディレクトリをOracle XML DBにロードする方法が示されています。JDBCは、Oracle Databaseに対する一連のJavaインタフェースです。

例3-14 Javaを使用したXMLType表へのコンテンツの挿入

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();
}

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

CコードでDOMを使用してXMLTypeインスタンスをロードできます。

例3-15に、DOMを指定してXMLTypeインスタンスを作成することによって、CコードでXMLコンテンツをXMLType表に挿入する方法を示します。この例の完全なリストは、「C (OCI)を使用したXMLデータのロード」を参照してください。

注意:

この機能を簡単に説明するために、この例では、デプロイされたシステムで通常使用されるパスワード管理手法を実行していません。本番環境では、Oracle Databaseパスワード管理のガイドラインに従い、サンプル・アカウントをすべて無効化してください。パスワード管理のガイドラインおよびセキュリティに関するその他の推奨事項は、『Oracle Databaseセキュリティ・ガイド』を参照してください。

例3-15 Cを使用したXMLType表へのコンテンツの挿入

. . .
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();
}

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

小規模なXML文書のコレクションで構成された大規模なXMLファイルをロードするときは、Simple API for XML(SAX)の解析機能を使用してファイルを一連の小規模な文書に分割してから文書を挿入すると、効率的にロードできます。

SAXは、XML Parserがイベント・ベース・アプリケーション用に提供するXML標準インタフェースです。SAXを使用して、ノードのコレクションから各文書を作成することによって、30MB以上の大規模なXMLファイルからデータベース表をロードできます。XMLファイルは、バルク・ロードすることもできます。

関連項目:

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

SQL*Loaderを使用すると、大量のXMLデータをOracle Databaseにロードできます。

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

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

PL/SQLパッケージDBMS_XDB_REPOSを使用すると、XML文書をOracle XML DBリポジトリにロードできます。表ベースではなく、パスベースの方法でリポジトリの文書(リソース)にアクセスできます。

指定のパスのリポジトリにXML文書をロードするには、PL/SQL関数DBMS_XDB_REPOS.createResourceを使用します。例3-16に、これを示します。

Oracle XML DBを構成して使用するための多くの操作は、1つ以上のXML文書の処理に基づいています。たとえば、XML Schemaの登録や、XSL変換の実行などです。これらのXML文書をOracle Databaseで使用可能にする最も簡単な方法は、そのXML文書をOracle XML DBリポジトリにロードすることです。

例3-16 CREATERESOURCEを使用したリポジトリへのXMLコンテンツの挿入

DECLARE
  res BOOLEAN;
BEGIN
  res := DBMS_XDB_REPOS.createResource('/home/QUINE/purchaseOrder.xml',
                                       bfilename('XMLDIR', 'purchaseOrder.xml'),
                                       nls_charset_id('AL32UTF8'));
END;/

3.5.7 プロトコルを使用したリポジトリへの文書のロード

文書は、XML文書を含め、一般的なプロトコルを使用して、ローカル・ファイル・システムからOracle XML DBリポジトリにロードできます。

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

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スタイルシートが含まれていることがあります。

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

Oracle XML DBのXMLコンテンツを問い合せて取得する方法は多数あります。

注意:

効率的な問合せパフォーマンスを実現するために、通常、索引を作成する必要があります。XMLデータの索引付けの詳細は、XMLTypeデータの索引を参照してください。

3.6.1 例で使用されているXML文書PurchaseOrder

XML Schemaは、例で使用されている発注書を定義します。

ここに示す例は、例3-17のXML文書PurchaseOrderに基づいています。

例3-17 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>

3.6.2 疑似列OBJECT_VALUEを使用したXML文書のコンテンツの取出し

疑似列OBJECT_VALUEは、オブジェクト表の値の別名として使用できます。

XMLTypeの単一列からなるXMLType表の場合、XML文書全体が取り出されます。(OBJECT_VALUEは、Oracle Database 10g リリース1より前のリリースで使用されていたvalue(x)およびSYS_NC_ROWINFO$別名に置き換わるものです。)

例3-18では、文書全体が改行なしで正しく出力されるように、SQL*Plus設定のPAGESIZEおよびLONGを使用しています。(読みやすいように、フォーマット出力で示しています。)

例3-18 OBJECT_VALUEを使用したXML文書全体の取出し

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.

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

SQL/XML関数XMLQueryを使用すると、XQuery式と一致するノードを抽出できます。結果は、XMLTypeのインスタンスとして戻されます。

例3-19に、複数の問合せの例を示します。

例3-19 XMLQUERYを使用したXMLフラグメントへのアクセス

次の問合せは、XPath式と一致するReference要素を含むXMLTypeインスタンスを戻します。

SELECT XMLQuery('/PurchaseOrder/Reference' PASSING OBJECT_VALUE RETURNING CONTENT)
  FROM purchaseorder;

XMLQUERY('/PURCHASEORDER/REFERENCE'PASSINGOBJECT_
-------------------------------------------------
<Reference>SBELL-2002100912333601PDT</Reference>
 
1 row selected.

次の問合せは、LineItemコレクション内の最初のLineItems要素を含むXMLTypeインスタンスを戻します。

SELECT XMLQuery('/PurchaseOrder/LineItems/LineItem[1]'
                PASSING OBJECT_VALUE RETURNING CONTENT)
  FROM purchaseorder;

XMLQUERY('/PURCHASEORDER/LINEITEMS/LINEITEM[1]'PASSINGOBJECT_
-------------------------------------------------------------
<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 XMLQuery('/PurchaseOrder/LineItems/LineItem/Description'
                PASSING OBJECT_VALUE RETURNING CONTENT)
  FROM purchaseorder;

XMLQUERY('/PURCHASEORDER/LINEITEMS/LINEITEM/DESCRIPTION'PASSINGOBJECT_
----------------------------------------------------------------------
<Description>A Night to Remember</Description>
<Description>The Unbearable Lightness Of Being</Description>
<Description>Sisters</Description>
 
1 row selected.

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

テキスト・ノードおよび属性値には、SQL/XML標準関数XMLQueryおよびXMLCastを使用してアクセスできます。

このためには、XMLQueryに渡されるXQuery式は、文書内の単一のテキスト・ノードまたは属性値(リーフ・ノード)を一意に識別する必要があります。例3-20に、複数の問合せを使用する例を示します。

関連項目:

SQL/XML関数XMLQueryおよびXMLCastの詳細は、XQueryとOracle XML DBを参照してください。

例3-20 XMLCASTおよびXMLQueryを使用したテキスト・ノード値へのアクセス

次の問合せは、対象のXPath式と一致するReference要素に関連付けられたテキスト・ノードの値を戻します。値は、VARCHAR2値として戻されます。

SELECT  XMLCast(XMLQuery('$p/PurchaseOrder/Reference/text()'
                         PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
                AS VARCHAR2(30))
  FROM purchaseorder;
 
XMLCAST(XMLQUERY('$P/PURCHASEO
------------------------------
SBELL-2002100912333601PDT
 
1 row selected.

次の問合せは、LineItem要素に含まれるDescription要素に関連付けられたテキスト・ノードの値を戻します。特定のLineItem要素は、そのId属性値によって指定されます。LineItem要素を識別する述語は、[Part/@Id="715515011020"]です。アットマーク(@)は、Idが要素でなく属性であることを指定します。値は、VARCHAR2値として戻されます。

SELECT XMLCast(
         XMLQuery('$p/PurchaseOrder/LineItems/LineItem[Part/@Id="715515011020"]/Description/text()'
                  PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
               AS VARCHAR2(30))
  FROM purchaseorder;
 
XMLCAST(XMLQUERY('$P/PURCHASEO
------------------------------
Sisters
 
1 row selected.

次の問合せは、最初のLineItem要素に含まれるDescription要素に関連付けられたテキスト・ノードの値を戻します。最初のLineItem要素は、位置述語[1]で示されます。

SELECT XMLCast(XMLQuery('$p/PurchaseOrder/LineItems/LineItem[1]/Description'
                        PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
               AS VARCHAR2(4000))
  FROM purchaseorder;
 
XMLCAST(XMLQUERY('$P/PURCHASEORDER/LINEITEMS/LINEITEM[1]/DESCRIPTION'PASSINGOBJECT_VALUEAS"P"
---------------------------------------------------------------------------------------------
A Night to Remember
 
1 row selected.

3.6.5 XMLEXISTS、XMLCASTおよびXMLQUERYを使用したXML文書の検索

SQL/XML標準関数XMLExistsXMLCastおよびXMLQueryをSQL WHERE句で使用すると、問合せ結果を制限できます。

SQL/XML標準関数XMLExistsは、指定された文書にW3CのXPath式と一致するノードが含まれているかどうかを評価します。これは、関数に指定されたXPath式によって指定されたノードが文書に含まれている場合はブール値のtrueを、そうでない場合はfalseの値を戻します。XPath式には述語を含めることができるため、XMLExistsは、指定されたノードが文書内に存在するかどうか、および指定された値を持つノードが文書内に存在するかどうかを判断できます。

同様に、関数XMLCastおよびXMLQueryを使用すると、問合せ結果を一部のプロパティを満たす文書に制限できます。例3-21に、XMLExistsXMLCastおよびXMLQueryを使用して文書を検索する方法を示します。

例3-22では、XML文書内のノードの値と別のリレーショナル表のデータに基づいて結合を実行しています。

関連項目:

SQL/XML関数XMLQueryXMLExistsおよびXMLCastの詳細は、XQueryとOracle XML DBを参照してください。

例3-21 XMLExists、XMLCastおよびXMLQueryを使用した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.

この問合せでは、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が含まれているかどうかを確認します。このルート要素には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文の結果として戻します。XQueryでは、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.

次の問合せは、XMLExistsを使用して、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.

次の例では、SQL/XML関数XMLQueryおよびXMLExistsを使用して、最初の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.

例3-22 XMLType表とリレーショナル表のデータの結合

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.

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

SQL/XML関数XMLTableを使用すると、XQuery式と一致する一連のノードに対してSQL操作を実行できます。

例3-19は、XPath式と一致する1つ以上のノードを含むXMLTypeインスタンスを戻す方法を示しています。指定されたXPath式と一致するノードが文書に複数含まれている場合、このような問合せでは、一致するすべてのノードが含まれるXMLフラグメントを戻します。XML文書と異なり、XMLフラグメントには、ルート要素である単一の要素はありません。

このような結果は、次の場合に一般的です。

  • コレクションに含まれている一連の要素を取り出す場合。この場合、フラグメント内のすべてのノードは同じタイプです(例3-23を参照)。

  • 対象のXPath式がワイルドカードで終わる場合。この場合、フラグメント内のノードは異なるタイプになることがあります(例3-25を参照)。

SQL/XML関数XMLTableを使用すると、XMLTypeインスタンスに含まれているXMLフラグメントを分割し、コレクション要素データを新しい仮想表に挿入することができ、その後、SQLを結合式などで使用して問い合せることができます。特に、XMLフラグメントを仮想表に変換することにより、複数のノードを戻すXMLQuery式の評価の結果を処理しやすくなります。

関連項目:

SQL/XML関数XMLTableの詳細は、XQueryとOracle XML DBを参照してください。

例3-23に、PurchaseOrder文書のDescription要素ごとにテキスト・ノードにアクセスする方法を示します。例3-19の単一のXMLフラグメント出力を複数のテキスト・ノードに分割します。

例3-24では、コレクション内の要素数をカウントします。また、ORDER BYGROUP BYなどのSQLキーワードをSQL/XML関数XMLTableによって作成された仮想表データに適用する方法も示しています。

例3-25では、SQL/XML関数XMLTableを使用して、指定された要素の要素の数をカウントする方法を示します。XMLTableに渡されるXPath式には、PurchaseOrder要素の直接の子孫である全要素と一致するワイルド・カード(*)が含まれます。XMLTableで作成された仮想表の各行には、XPath式と一致するノードが含まれます。仮想表内の行数をカウントすることによって、要素PurchaseOrderの子要素の数が判明します。

例3-23 XMLTABLEを使用したDescriptionノードへのアクセス

SELECT des.COLUMN_VALUE
  FROM purchaseorder p,
       XMLTable('/PurchaseOrder/LineItems/LineItem/Description'
                PASSING p.OBJECT_VALUE) des
  WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                  PASSING OBJECT_VALUE AS "p");
 
COLUMN_VALUE
------------
<Description>A Night to Remember</Description>
<Description>The Unbearable Lightness Of Being</Description>
<Description>Sisters</Description>

3 rows selected.

この例では、SQLを使用してテキスト・ノードのコンテンツを処理するために、SQL/XML関数XMLTableを使用してDescriptionノードのコレクションを仮想表に変換します。この仮想表には3つの行があり、単一のDescription要素を持つ単一のXMLTypeインスタンスが各行に含まれています。

XPath式は、Description要素をターゲットにしています。PASSING句では、XPath式を評価するためのコンテキストとしてXMLTypepurchaseorderのコンテンツ(OBJECT_VALUE)を使用することを指定しています。

したがって、XMLTable式はpurchaseorder表に依存します。これは左側結合です。この相関結合によって、アクセスされるpurchaseorder行と、XMLTableによってその行から生成される行は、1対多(1:N)の関係であることが保証されます。この相関結合により、purchaseorder表は、FROMリストのXMLTable式よりも前に記述する必要があります。これは、PASSING句が表の列を参照する場合に一般的な要件です。

仮想表のXMLTypeインスタンスにはそれぞれ、Description要素が1つずつ含まれます。XMLTableCOLUMNS句を使用して、XPath式'Description'のターゲットのデータを、SQLデータ型VARCHAR2(256)descriptionという列に分割できます。この列を定義する'Description'式は、コンテキストのXPath式'/PurchaseOrder/LineItems/LineItem'相対的です。

SELECT des.description
  FROM purchaseorder p,
       XMLTable('/PurchaseOrder/LineItems/LineItem' PASSING p.OBJECT_VALUE
                COLUMNS description VARCHAR2(256) PATH 'Description') des
  WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                  PASSING OBJECT_VALUE AS "p");

DESCRIPTION
---------------------------------
A Night to Remember
The Unbearable Lightness Of Being
Sisters
 
3 rows selected.

COLUMNS句を使用すると、正確なSQLデータ型を指定できるため、静的型チェックがさらに便利になります。この例では、単一の列(description)のみを使用します。XMLType表に複数レベルで含まれているデータをリレーショナル・ビューの個別の行として公開するには、分割してリレーショナル列に格納する各文書レベルにXMLTableを適用します。この例は、例9-2を参照してください。

例3-24 XMLTABLEを使用したコレクション内の要素数のカウント

SELECT reference, count(*)
  FROM purchaseorder,
       XMLTable('/PurchaseOrder' PASSING OBJECT_VALUE
                COLUMNS reference VARCHAR2(32) PATH 'Reference',
                        lineitem  XMLType      PATH 'LineItems/LineItem'),
       XMLTable('LineItem' PASSING lineitem)
  WHERE XMLExists('$p/PurchaseOrder[User="SBELL"]'
                  PASSING OBJECT_VALUE AS "p")
  GROUP BY reference
  ORDER BY reference;

REFERENCE                    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.

この例の問合せでは、SQL/XML関数XMLExistsへのXPath式と一致する一連のXML文書が検索されます。これにより、次の2つの列を含む仮想表が生成されます。

  • reference: この列には、選択された各文書のReferenceノードが含まれます。

  • lineitem: この列には、選択された各文書の一連のLineItemノードが含まれます。

文書ごとにLineItemノードの数がカウントされます。相関結合によって、GROUP BYLineItem要素が属するPurchaseOrder要素を正しく判別できます。

例3-25 XMLTABLEを使用した要素内の子要素数のカウント

SELECT count(*)
  FROM purchaseorder p, XMLTable('/PurchaseOrder/*' PASSING p.OBJECT_VALUE)
  WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                  PASSING OBJECT_VALUE AS "p");
 
  COUNT(*)
----------
         9

1 row selected.

3.7 Oracle XML DBに格納されたXMLコンテンツの更新

XMLコンテンツを更新する場合は、文書のコンテンツ全体または文書の特定部分のみを置換できます。

XML文書を部分的に更新する機能は非常に強力で、特に大きな文書に小さな変更を行う場合に、更新の実行に必要なネットワーク・トラフィックとディスクの入出力を大幅に削減できます。

文書に対する複数の変更を1回の操作で実行できます。どちらの場合も、XQuery式を使用して更新するノードを特定し、そのノードに新しい値を指定します。

例3-26では、要素Userに関連付けられたテキスト・ノードを更新します。

例3-27では、XML文書内の要素全体を置換します。XQuery式によって要素が参照され、置換値はXMLTypeオブジェクトとして渡されます。

文書に対する複数の変更を1つの文で実行できます。例3-28では、要素CostCenterおよびSpecialInstructionsに属するテキスト・ノードの値を1つのSQL UPDATE文で変更します。

例3-26 テキスト・ノードの更新

SELECT XMLCast(XMLQuery('$p/PurchaseOrder/User' PASSING OBJECT_VALUE AS "p"
                                                RETURNING CONTENT)
               AS VARCHAR2(60))
  FROM purchaseorder
  WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                  PASSING OBJECT_VALUE AS "p");
 
XMLCAST(XMLQUERY('$P/PURCHAS
----------------------------
SBELL
 
1 row selected.

UPDATE purchaseorder
SET OBJECT_VALUE =
    XMLQuery('copy $i := $p1 modify
                (for $j in $i/PurchaseOrder/User
                 return replace value of node $j with $p2)
              return $i'
             PASSING OBJECT_VALUE AS "p1", 'SKING' AS "p2" RETURNING CONTENT)
    WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                    PASSING OBJECT_VALUE AS "p");
 
1 row updated.

SELECT XMLCast(XMLQuery('$p/PurchaseOrder/User' PASSING OBJECT_VALUE AS "p"
                                                RETURNING CONTENT)
               AS VARCHAR2(60))
  FROM purchaseorder
  WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                  PASSING OBJECT_VALUE AS "p");
 
XMLCAST(XMLQUERY('$P/PURCHAS
----------------------------
SKING

1 row selected.

例3-27 XQuery Updateを使用した要素全体の置換

SELECT XMLQuery('$p/PurchaseOrder/LineItems/LineItem[1]'
                PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
  FROM purchaseorder
  WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                  PASSING OBJECT_VALUE AS "p");
 
XMLQUERY('$P/PURCHAS
--------------------
<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 =
        XMLQuery('copy $i := $p1 modify
                    (for $j in $i/PurchaseOrder/LineItems/LineItem[1]
                     return replace node $j with $p2)
                  return $i'
                 PASSING OBJECT_VALUE AS "p1",
                         XMLType('<LineItem ItemNumber="1">
                                    <Description>The Lady Vanishes</Description>
                                    <Part Id="37429122129" UnitPrice="39.95"
                                          Quantity="1"/>
                                  </LineItem>') AS "p2"
                 RETURNING CONTENT)
        WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                        PASSING OBJECT_VALUE AS "p");
 
1 row updated.

SELECT XMLQuery('$p/PurchaseOrder/LineItems/LineItem[1]'
                PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
  FROM purchaseorder
  WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                  PASSING OBJECT_VALUE AS "p");

XMLQUERY('$P/PURCHAS
--------------------
<LineItem ItemNumber="1">
  <Description>The Lady Vanishes</Description>
  <Part Id="37429122129" UnitPrice="39.95" Quantity="1"/>
</LineItem>
 
1 row selected.

例3-28 XQuery Updateを使用したテキスト・ノード値の変更

SELECT XMLCast(XMLQuery('$p/PurchaseOrder/CostCenter'
                        PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
               AS VARCHAR2(4)) "Cost Center",
       XMLCast(XMLQuery('$p/PurchaseOrder/SpecialInstructions'
                        PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
               AS VARCHAR2(2048)) "Instructions"
  FROM purchaseorder
  WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                  PASSING OBJECT_VALUE AS "p");

Cost Center  Instructions
------------ ------------
S30          Air Mail
 
1 row selected.

UPDATE purchaseorder
  SET OBJECT_VALUE =
        XMLQuery('copy $i := $p1 modify
                    ((for $j in $i/PurchaseOrder/CostCenter
                      return replace value of node $j with $p2)
                     (for $j in $i/PurchaseOrder/SpecialInstructions
                      return replace value of node $j with $p3))
                 return $i'
                 PASSING OBJECT_VALUE AS "p1",
                         'B40' AS "p2",
                         'Priority Overnight Service' AS "p3"
                 RETURNING CONTENT)
        WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                        PASSING OBJECT_VALUE AS "p");
 
1 row updated.

SELECT XMLCast(XMLQuery('$p/PurchaseOrder/CostCenter'
                        PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
               AS VARCHAR2(4)) "Cost Center",
       XMLCast(XMLQuery('$p/PurchaseOrder/SpecialInstructions'
                        PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
               AS VARCHAR2(2048)) "Instructions"
  FROM purchaseorder
  WHERE XMLExists('$p/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]'
                  PASSING OBJECT_VALUE AS "p");
 
Cost Center  Instructions
------------ --------------------------
B40          Priority Overnight Service
 
1 row selected.

3.8 リレーショナル・データからのXMLデータの生成

Oracle XML DBを使用して、リレーショナル・データからXMLデータを生成できます。

3.8.1 SQL/XML関数を使用した、リレーショナル・データからのXMLデータの生成

標準のSQL/XML関数を使用すると、XML文書を1つ以上生成できます。

SQL/XML関数XMLQueryは、これを行うための最も一般的な方法です。この操作に使用できるSQL/XML関数には、他に次のものがあります。

  • XMLElementは、要素を作成します。

  • XMLAttributesは、属性を要素に追加します。

  • XMLForestは、要素のフォレストを作成します。

  • XMLAggは、要素のコレクションから単一の要素を作成します。

例3-29の問合せでは、これらの関数を使用して、表departmentslocationscountriesemployeesおよびjobsの情報を含むXML文書を生成します。

この問合せは、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関数で生成される出力は、通常はフォーマット出力ではありません。ただし、関数XMLSerializeは例外で、XMLSerializeを使用してフォーマット出力します。このため、他のSQL/XML関数で必要な出力を生成するときに、(1)完全なDOMが作成されるのを回避し、(2)生成される文書のサイズを縮小できます。ほとんどのアプリケーションでは、このように大半のSQL/XML関数でフォーマット出力が生成されなくても問題ありません。ただし、生成された出力を手動で検証することは困難になります。

また、SQL/XML生成関数を使用して構築されるXMLTypeビューを作成および問合せすることもできます。例3-30および例3-31に、これを示します。このようなXMLTypeビューには、リレーショナル・データをXMLコンテンツとして永続的に保持する効果があります。また、XMLTypeビューの行は、Oracle XML DBリポジトリに文書として永続的に保持できます。

例3-31では、SQL/XML関数XMLExistsに渡されるXPath式によって、問合せ結果セットは、Executive部門の情報が含まれたノードに制限されます。結果は、わかりやすくするためフォーマット出力しています。

注意:

XMLTypeビューで操作するXML式でのXPathリライトは、XPath式で参照するノードが、SQL関数XMLAggを使用して作成された要素の子孫でない場合にのみサポートされます。

例3-29 SQL/XML関数を使用した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>2005-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>2001-01-13</StartDate><JobTitle>Administration Vice Presiden
t</JobTitle><Salary>17000</Salary><Manager>Steven
 King</Manager><Commission></Commission></Employee></EmployeeList></Department>

例3-30 従来のリレーショナル表のXMLTypeビューの作成

CREATE OR REPLACE VIEW department_xml OF XMLType
  WITH OBJECT ID (substr(
                    XMLCast(
                      XMLQuery('$p/Department/Name'
                               PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
                      AS VARCHAR2(30)),
                    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;

例3-31 XMLTypeビューの問合せ

SELECT OBJECT_VALUE FROM department_xml
  WHERE XMLExists('$p/Department[Name="Executive"]' PASSING OBJECT_VALUE AS "p");
 
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>2005-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>2001-01-13</StartDate>
      <JobTitle>Administration Vice President</JobTitle>
      <Salary>17000</Salary>
      <Manager>Steven King</Manager>
      <Commission/>
    </Employee>
  </EmployeeList>
</Department>
 
1 row selected.

次の実行計画の出力に示すとおり、Oracle XML DBには、XMLExists式のXPath式の引数を、基礎となるリレーショナル表のSELECT文に正しくリライトする機能があります。

SELECT OBJECT_VALUE FROM department_xml
  WHERE XMLExists('$p/Department[Name="Executive"]' PASSING OBJECT_VALUE AS "p");

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 |   115 |            |          |
|*  2 |   HASH JOIN                            |                   |    10 |  1150 |     7  (15)| 00:00:01 |
|*  3 |    HASH JOIN                           |                   |    10 |   960 |     5  (20)| 00:00:01 |
|   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES         |    10 |   690 |     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.

3.8.2 DBURITYPEを使用した、リレーショナル・データからのXMLデータの生成

SQL関数DBURITypeを使用して、リレーショナル・データからXMLデータを生成できます。

関数DBURITypeは、指定された表またはビューの1つ以上の行を単一のXML文書として公開します。ルート要素の名前は、表またはビューの名前から導出されます。ルート要素には、一連のROW要素が含まれます。表またはビュー内の行ごとにROW要素が1つずつあります。各ROW要素の子は、表またはビューの列から導出されます。各子要素には、指定された行の列の値を持つテキスト・ノードが含まれます。

例3-32に、SQL関数DBURITypeを使用して、データベース・スキーマHRの表departmentsのコンテンツにアクセスする方法を示します。メソッドgetXML()を使用して結果の文書をXMLTypeインスタンスとして戻します。

例3-33では、XPath述語を使用して、DBURITypeによって生成されるXML文書に含める行を制限する方法を示します。この例のXPath式によって、値が10DEPARTMENT_ID列のみにXML文書が制限されます。

SQL関数DBURITypeを使用すると、リレーショナル表の一部または全部の行を1つ以上のXML文書として簡単に公開できます。関数DBURITypeに渡されるURLを拡張してビューまたは表から単一列を戻すことができますが、その場合、URLには、ターゲットの表またはビューの単一行を識別する述語も含まれる必要があります。

例3-34に、これを示します。述語[DEPARTMENT_ID="10"]句は、department_id列に値10が含まれるdepartments行について、department_name列の値を問合せで戻します。

SQL関数DBURITypeは、次の点でSQL/XML関数よりも柔軟性が低くなっています。

  • DBURITypeでは、生成された文書の形式を制御できません。

  • データは、単一の表またはビューからのみ生成できます。

  • 生成される文書は、1つ以上のROW要素で構成されます。各ROW要素には、ターゲット表の列ごとの子が含まれます。

  • 子要素の名前は、列の名前から導出されます。

XML要素の名前を制御する場合、複数の表からの列を含める場合、または生成される文書に含める表の列を制御する場合は、必要な列を単一行として公開するリレーショナル・ビューを作成してから、関数DBURITypeを使用して、そのビューのコンテンツからXML文書を生成します。

例3-32 DBURITypeおよびgetXML()を使用したリレーショナル表からのXMLデータの生成

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>

例3-33 XPath述語を使用した行の制限

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.

例3-34 XPath述語を使用した行と列の制限

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.

3.9 XML文書のキャラクタ・セット

XML文書で使用するキャラクタ・セットをOracle XML DBが決定する方法はいくつかあります

注意:

AL32UTF8は、XMLTypeデータに適したOracle Databaseキャラクタ・セットです。これはIANAの登録済標準であるUTF-8エンコーディングと同等であり、すべての有効なXML文字をサポートします。

Oracle Databaseのデータベース・キャラクタ・セットUTF8(ハイフンなし)とデータベース・キャラクタ・セットAL32UTF8またはキャラクタ・エンコーディングUTF-8を混同しないでください。データベース・キャラクタ・セットUTF8はAL32UTF8で置き換えられています。XMLデータにはUTF8を使用しないでください。キャラクタ・セットUTF8でサポートされるのはUnicodeバージョン3.1以下のみです。すべての有効なXML文字がサポートされるわけではありません。AL32UTF8には、このような制限はありません。

XMLデータにデータベース・キャラクタ・セットUTF8を使用すると、システムが停止したりセキュリティに悪影響を及ぼす可能性があります。入力した文書要素の名前にデータベース・キャラクタ・セットでサポートされない文字が含まれている場合、その文字は置換文字(通常は「?」)で置き換えられます。このため、解析が終了して例外が発生します。リカバリ不能なエラーが発生する場合もあります。

3.9.1 XMLエンコーディング宣言

XMLエンコーディング宣言を使用して、指定された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

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

文書がデータベースにロードされるときには、XMLデータがCLOB値またはVARCHAR値から取得される場合を除き、文字エンコーディングはエンコーディング宣言によって決まります。

XMLデータがCLOB値またはVARCHAR値から取得される場合、これらの2つのデータ型は常にデータベース・キャラクタ・セットでエンコードされるので、エンコーディング宣言の存在は無視されます

さらに、プログラムAPIまたは転送プロトコルのいずれかを介してデータをOracle XML DBにロードするときは、外部エンコーディングを指定して文書のエンコーディング宣言をオーバーライドできます。XML Schemaに基づくXML文書に指定のエンコーディングに対して不適切な文字が含まれている場合、その文書をロードしようとするとエラーが発生します。

次の各例で、外部エンコーディングを指定するいくつかの方法を示します。

  • PL/SQLファンクションDBMS_XDB_REPOS.createResourceを使用してBFILEからファイル・リソースを作成する場合、CSID引数でファイルのエンコーディングを指定できます。CSIDにゼロを指定すると、ファイルのエンコーディングは文書のエンコーディング宣言から自動検出されます。

    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_REPOS.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
    

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

XMLデータがCLOB値またはVARCHAR値に格納されている場合を除き、これをSQLクライアント、プログラムAPIまたは転送プロトコルを使用してOracle XML DBから取り出す場合に使用するエンコーディングを指定できます。

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 XMLSERIALIZE(DOCUMENT e.RES AS BLOB ENCODING 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
    

    関連項目:

    FTP Quoteメソッド

  • HTTP(S) - HTTP(S)リクエストでAccept-Charsetパラメータを使用できます。

    /httptest/mypurchaseorder.xml  1.1 HTTP/Host: localhost:2345
    Accept: text/*
    Accept-Charset:  iso-8859-1, utf-8
    


脚注の凡例

脚注1:

XML Schemaに基づくデータのXMLType記憶域モデルは、参照するXML Schemaの登録時に指定したものです。登録時に記憶域モデルが指定されなかった場合、オブジェクト・リレーショナル記憶域が使用されます。