16 XQuery API for Javaを使用したOracle XML DBへのアクセス

XQuery API for Java (XQJ)を使用してOracle XML DBにアクセスする方法について説明します。

16.1 Oracle XML DBのXQJのサポートの概要

XQuery API for Java (XQJ)(JSR-225とも呼ばれる)は、JavaプログラムからXQueryを使用してExtensible Markup Language (XML)データにアクセスするための業界標準の方法を提供します。これにより、XMLのデータ・ソースに対してXQuery式を評価したり、その結果をXMLデータとして処理できます。

Oracleでは、XQuery式を評価するための2つのXQueryエンジンが用意されています。1つはOracle XML DBにあり、データベースのXMLデータで使用し、もう1つはOracle XML Developer's Kit (XDK)にあり、データベース外部のXMLデータで使用します。(XDK用のXQueryエンジンについては、「XQuery Processor for Javaの使用」を参照してください)。

Oracleでは、これら2つのXQueryエンジンにアクセスするために、2つのXQJ実装が用意されています。これらの実装は両方ともXDKに含まれており、データがデータベース内にある場合でもその他の場所にある場合でも、この実装によりXDKを使用して標準XQJ APIでXMLデータにアクセスできます。

XQJで実行される問合せは、Oracle XML DBでサポートされる標準のWorld Wide Web Consortium (W3C) XQuery 1.0言語で記述されます。この機能の一般的なユースケースは、ローカルのJavaプログラムからリモートのデータベース(Oracle XML DB)に格納されているXMLデータにアクセスすることです。

このドキュメントでは、XQueryおよびXQJの一般的な情報についてはとりあげません。

関連項目:

16.1.1 XQJを使用したOracle XML DBへのアクセスの前提条件

Oracle XML DBでXQJを使用するには、Javaランタイム環境1.6が必要です。また、特定のJavaアーカイブ(JAR)ファイルをCLASSPATH環境変数に指定するか、コマンドライン・オプションclasspathを使用して渡す必要があります。

JARファイルは次のとおりです。

これらのJARファイルのディレクトリ・パスは、データベース・インストールのORACLE_HOMEディレクトリへの相対パスです。

16.2 例: XQJを使用したOracle XML DBの問合せ

次の例では、XQJを使用してOracle XML DBのデータを問い合せて取得する方法を示します。

例16-1に、XQJを使用してOracle XML DBの表からデータを問い合せる方法を示します。Order Entry (OE)データベース・サンプル・スキーマのWAREHOUSES表を使用します。OEサンプル・スキーマのWAREHOUSES表には、倉庫情報を持つXML文書が含まれます。WAREHOUSES表には、XMLType列warehouse_specおよびその他の列が含まれます。(この例で使用されるデータの詳細は、『Oracle XML DB開発者ガイド』の標準データベース・スキーマに関する項を参照してください。)

例16-1では特に、次のステップを実行する方法を示します。

  1. Oracle XML DBへのXQJ接続の取得

    XQJを使用してOracle XML DBに接続するプログラムはすべて、まずOXQDDataSourceオブジェクトを作成する必要があります。次に、必須プロパティ値でOXQDDataSourceを初期化してから、Oracle XML DBインスタンスへのXQJ接続を取得します。

  2. XQuery式の準備

  3. 評価のためのXQuery式の送信

  4. 生成されたXQueryシーケンスの各項目の印刷

例16-1では、XQuery式はUniversal Resource Identifier (URI)スキームoradbを介してWAREHOUSES表にアクセスします。(XQueryを使用したXML DBでの表の問合せまたはデータの表示の詳細は、『Oracle XML DB開発者ガイド』のURIスキームoradbに関する項を参照してください。)

例16-1では、XQJで外部変数値をバインドする方法も示します。問合せには、WAREHOUSES表から戻された行をWAREHOUSE_IDでフィルタリングするための外部変数$xがあります。

例16-1で生成される出力は次のとおりです(読みやすくするために再フォーマット済です)。

<Warehouse><Building>Owned</Building><Area>25000</Area><Docks>2</Docks>
 <DockType>Rearload</DockType><WaterAccess>Y</WaterAccess>
 <RailAccess>N</RailAccess><Parking>Street</Parking>
 <VClearance>10 ft</VClearance></Warehouse>

<Warehouse><Building>Rented</Building><Area>50000</Area><Docks>1</Docks>
 <DockType>Sideload</DockType><WaterAccess>Y</WaterAccess>
 <RailAccess>N</RailAccess><Parking>Lot</Parking>
 <VClearance>12 ft</VClearance></Warehouse>

例16-2に、XQJを使用してOracle XML DBリポジトリからデータを取得する方法を示します。この例では、depts.xmlemps.xmlの2つのファイルがXML DBリポジトリのフォルダ/publicの下にアップロードされていると想定しています。たとえば、FTPを使用して2つのファイルをOracle XML DBリポジトリにアップロードできます。(Oracle XML DBリポジトリへのデータの格納およびOracle XML DBリポジトリの使用の詳細は、『Oracle XML DB開発者ガイド』のOracle XML DBリポジトリの使用に関する項を参照してください。)

depts.xmlの内容は次のとおりです。

depts.xml:
 
<?xml version="1.0"?>
     <depts>
       <dept deptno="10" dname="Administration"/>
       <dept deptno="20" dname="Marketing"/>
       <dept deptno="30" dname="Purchasing"/>
     </depts>

emps.xmlの内容は次のとおりです。

emps.xml:
 
<?xml version="1.0"?>
   <emps>
    <emp empno="1" deptno="10" ename="John"  salary="21000"/>
       <emp empno="2" deptno="10" ename="Jack" salary="310000"/>
       <emp empno="3" deptno="20" ename="Jill" salary="100001"/>
     </emps>

fn:docおよびfn:collection関数を使用して、XQueryでOracle XML DBリポジトリのデータを問い合せることができます。例16-2に、XQuery内でfn:doc関数を使用してリポジトリにアクセスする方法を示します。(これらのXQuery関数の使用の詳細は、『Oracle XML DB開発者ガイド』のOracle XML DBリポジトリのXMLデータの問合せに関する項を参照してください。)

例16-2で生成される出力は次のとおりです。

<emp ename="Jack" dept="Administration"/>
<emp ename="Jill" dept="Marketing"/>

例16-1 XQJを使用したXQueryでのXML DB表の問合せ

import oracle.xml.xquery.xqjdb.OXQDDataSource;
 
import javax.xml.xquery.XQItemType;
import javax.xml.xquery.XQResultSequence;
import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQPreparedExpression;
import javax.xml.namespace.QName;
 
public class example1
{
  public static void main(String argv[])
  {
    try
    {
      // Create a new OXQDDataSource for connecting to Oracle XML DB
      OXQDDataSource oxqDS = new OXQDDataSource();
      // Set appropriate connection information for the database instance.
      // Must use the thin driver
      oxqDS.setProperty("driver", "jdbc:oracle:thin");
      oxqDS.setProperty("dbusername", "oe");
      oxqDS.setProperty("dbpassword", "oe");
      // Machine hostname
      oxqDS.setProperty("dbserver", "myserver");
      // Database instance port number
      oxqDS.setProperty("dbport", "6479");
      // Database instance port number
      oxqDS.setProperty("serviceName", "mydbinstance");
      XQConnection conn = oxqDS.getConnection();
      XQItemType  itemTypeInt = conn.createAtomicType(XQItemType.XQBASETYPE_INT);
      XQPreparedExpression expr = conn.prepareExpression("declare variable $x as
        xs:int external; for $i in fn:collection('oradb:/OE/WAREHOUSES') where
          $i/ROW/WAREHOUSE_ID < $x return $i/ROW/WAREHOUSE_SPEC/Warehouse");
      expr.bindInt(new QName("x"), 3, itemTypeInt);
      XQResultSequence xqSeq = expr.executeQuery();
      while (xqSeq.next())
         System.out.println (xqSeq.getItemAsString(null));
     }
     catch (Exception e)
     {
      e.printStackTrace();
     }
  }
}

例16-2 XQJを使用したXQueryでのXML DBリポジトリの問合せ

import oracle.xml.xquery.xqjdb.OXQDDataSource;
 
import javax.xml.xquery.XQItemType;
import javax.xml.xquery.XQResultSequence;
import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQPreparedExpression;
import javax.xml.namespace.QName;

public class example2
{
  public static void main(String argv[])
  {
    try
    {
      // Create a new OXQDDataSource for connecting to Oracle XML DB
      OXQDDataSource oxqDS = new OXQDDataSource();
      // Set appropriate connection information for the database instance.
      // Must use the thin driver
      oxqDS.setProperty("driver", "jdbc:oracle:thin");
      oxqDS.setProperty("dbusername", "oe");
      oxqDS.setProperty("dbpassword", "oe");
      // Machine hostname
      oxqDS.setProperty("dbserver", "myserver");
      // Database instance port number
      oxqDS.setProperty("dbport", "6479");
      // Database instance port number
      oxqDS.setProperty("serviceName", "mydbinstance");
      XQConnection conn = oxqDS.getConnection();
      XQPreparedExpression expr = conn.prepareExpression("for $e in
        doc(\"/public/emps.xml\")/emps/emp let $d :=
        doc(\"/public/depts.xml\")//dept[@deptno = $e/@deptno]/@dname where
        $e/@salary > 100000 order by $e/@empno return 
        <emp ename=\"{$e/@ename}\" dept=\"{$d}\"/>");
      XQResultSequence xqSeq = expr.executeQuery();
      while (xqSeq.next())
         System.out.println (xqSeq.getItemAsString(null));
     }
     catch (Exception e)
     {
      e.printStackTrace();
     }
  }
}

16.3 Oracle XML DBのXQJのサポート

2つのOracle XQJ実装は、いくつかの点で違いがあります。Oracle XML DBのXQJのサポートについて説明します。

XQJを使用した中間層のXQueryエンジンへのアクセスについては、「XQuery Processor for Javaの使用」で説明しています。

表16-1に、Oracle XML DBへの接続に使用するOXQDDataSourceプロパティを示します。Oracle XML DBへのXQJ接続を作成するには、これらのプロパティの値を設定する必要があります。dbnameプロパティまたはserviceNameプロパティの値、および表16-1にリストされているすべてのその他のOXQDDataSourceプロパティの値を設定する必要があります。

表16-1 OXQDDataSourceプロパティ

プロパティ getメソッド setメソッド

driver

jdbc:oracle:thin

getDriver

setDriver

dbusername

データベース・スキーマ(ユーザー)名

getDBUserName

setDBUserName

dbpassword

データベース・スキーマのパスワード

getDBPassword

setDBPassword

dbserver

データベース・インスタンスのホスト名

getDBServer

setDBServer

dbport

XQJ接続用のデータベース・インスタンスのポート番号

getDBPort

setDBPort

dbname

データベース・インスタンス名(サービスID)脚注 1

getDBName

setDBName

serviceName

サービス名脚注1

getServiceName

setServiceName

脚注1

サービスIDまたはサービス名のいずれかを使用して、データベースを識別できます。

表16-2で、Oracle XML DBでのオプションのXQJ機能のサポートについて説明します。

注意:

Oracle XML DBによる一部のXQJ機能のサポートは、中間層のXQueryエンジンによるサポートとは異なります。特に、Oracle XML DB XQJ実装では、ユーザー定義タイプの使用をサポートしていません。

表16-2 Oracle XML DBでのオプションのXQJ機能のサポート

XQJ機能 Oracle XML DBのサポート

XQDataSource実装のクラス名

oracle.xml.xquery.xqjdb.OXQDDataSource

JDBC接続

サポートされません。

OXQDDataSourceで定義されたプロパティ(接続情報)

表16-1を参照してください。

コマンド

サポートされません。

XQPreparedExpression.cancel (問合せ実行の取消)

サポートされません。

シリアライズ

xmlを持つパラメータmethodおよび値UTF-8またはUTF-16を持つパラメータencodingのみ。

追加のStAXおよびSAXイベント

サポートされません。

ユーザー定義スキーマ型

サポートされません。

ノードが外部変数にバインドされている場合の、ノードID、文書順、ノード・コンテキストの完全保持

サポートされません。

ログイン・タイムアウト

サポートされません。

トランザクション

サポートされません。

入力ノードが文書ノードでない場合のXQItemAccessorメソッドgetNodeUri()の動作

NULLを戻します。

匿名タイプのXQItemTypeメソッドgetTypeName()の動作

falseを戻します。

XQItemTypeメソッドgetSchemaURI()の動作

NULLまたはタイプ作成時に指定されたスキーマURIを戻します。現在、Oracle XML DB XQJ実装では、スキーマURIを使用してタイプ情報を取得しません。また、ユーザー定義タイプはサポートされていません。

入力が整形式XML文書でない場合のXQDataFactoryメソッドcreateItemFromDocument()およびbindDocument()の動作

例外を呼び出します。

XQQueryExceptionから戻される追加のエラー・コード

サポートされません。

インタフェースConnectionPoolXQDataSourcePooledXQConnectionXQConnectionEventおよびXQConnectionEventListener

サポートされません。

XQDataSource.getConnection(
  java.sql.Connection)

サポートされません。(JDBC接続はサポートされません。)

XQDataSource.getConnection(
  java.lang.String,
  java.lang.String)

引数なしのgetConnection()と同じ: 引数は無視されます。

関連項目:

Oracle XML DBでのXQuery言語の使用の詳細は、『Oracle XML DB開発者ガイド』を参照してください

16.3.1 Oracle XML DB XQJサポートのその他の制約

Oracle XML DBのXQJのサポートの制限事項について説明します。これらは、中間層のXQueryエンジンによるXQJサポートには適用されません。

Oracle XML DBのXQJのサポートは、次のように制限されます。

  • Oracle XML DB XQueryサポートに対する制約はすべて、Oracle XML DBでのXQJのサポートにも適用されます。

  • XDK Document Object Model (DOM)のみサポートされます。他のDOMを使用するとエラーが発生する可能性があります。

  • Oracle XML DB XQJ実装は、他のXQJ実装(XDK JavaでのXQJの実装を含む)とは相互運用できません。(「相互運用可能」の意味については、XQJ標準(JSR-225)を参照してください。)

  • XQDataSourceメソッドgetLogWriterおよびsetLogWriterは効果がありません(無視されます)。

  • XQStaticContentメソッドgetBoundarySpacePolicysetBoundarySpacePolicygetDefaultCollationおよびsetDefaultCollationは効果がありません(無視されます)。

  • XQStaticContentメソッドの名前空間コピー・モードsetCopyNamespacesModPreserveおよびsetCopyNamespacesModeInheritは効果がありません(無視されます)。使用される値は常に、それぞれpreserveおよびinheritです。

  • XQDynamicContextメソッドを使用したDocumentFragmentオブジェクトのバインドはサポートされません。

  • タイプxs:durationの値はサポートされません。XQDynamicContextメソッドを使用してxs:durationをバインドしたり、xs:duration値にアクセスしたりすると、エラーが発生します。

  • xs:datexs:dateTimexs:gYearおよびxs:gYearMonth値の年は-4712から9999 (-4712と9999を含む)にする必要があります。この範囲外の年を使用すると、エラーまたは予期しない結果が生じる可能性があります。

16.4 Oracle XML DBで使用する際のXQJのパフォーマンスに関する考慮事項

データベースから項目シーケンスをフェッチするには、XQResultSequenceメソッドnext()を使用して一度に1つずつ項目を取得してから、XQItemAccessorメソッドを使用してそれらの項目に対応するすべてのデータをフェッチします。

これにより、次に示す全シーケンスをフェッチするメソッド(データを戻す前にシーケンス全体を生成)を使用するよりもパフォーマンスが向上します。

  • getSequenceAsStream()

  • getSequenceAsString(java.util.Properties props)

  • writeSequence(java.io.OutputStream os, java.util.Properties props)

  • writeSequence(java.io.Writer ow, java.util.Properties props)

  • writeSequenceToResult(javax.xml.transform.Result result)

  • writeSequenceToSAX(org.xml.sax.ContentHandler saxhdlr)

たとえば、getSequenceAsStream()を起動すると、XQuery結果のすべてのシーケンス・データがデータベースからフェッチされた後に、そこからXMLStreamReaderインスタンスが生成され、ユーザーのプログラムに戻されます。

また、項目自体はストリーム可能でないことに注意してください。項目アクセッサ・メソッドは、常に項目全体を生成してから、項目の一部を出力します。

入力については、XQDynamicContextで定義されたすべてのバインド・メソッドは、入力データを完全に生成してからデータベースに渡します。

たとえば、bindDocument(javax.xml.namespace.QName varName, javax.xml.stream.XMLStreamReader value, XQItemType type)を起動すると、入力XMLStreamReaderインスタンスによって参照されるすべてのデータが処理されてから、外部XQuery変数がこれらのデータにバインドされます。