この章では、Oracle XML Developer's Kit (XDK) XQuery Processor for Javaの使用方法について説明します。
内容は次のとおりです。
XDKには、Javaアプリケーションで使用するためのスタンドアロンのXQuery プロセッサが用意されています。XQueryは、Extensible Markup Language (XML)用のWorld Wide Web Consortium (W3C)標準問合せ言語です。Javaアプリケーション内でXQueryを使用してXMLを処理することで、開発者の生産性とアプリケーションのパフォーマンスが向上します。一般に、XQueryで記述されたアプリケーションは、すべてJavaで記述されたアプリケーションよりもコードが少なくなり、高速で実行でき、少しのメモリーしか使用しません。
JSR 225: XQuery API for Java (XQJ)に、Javaアプリケーションから問合せを実行する方法が定義されています。XQJを使用するには、アプリケーションがJavaバージョン1.6で実行されている必要があります。さらに、次のJARファイルも必要です。
jlib/oxquery.jar
jlib/xqjapi.jar
jlib/orai18n-mapping.jar
lib/xmlparserv2.jar
xdk/jlib/apache-xmlbeans.jar
これらのJava Archive (JAR)ファイルのディレクトリ・パスは、Oracle DatabaseインストールのORACLE_HOME
ディレクトリへの相対パスです。
例7-1に、XQuery API for Java (XQJ)を使用して簡易な「Hello World」問合せを実行する方法を示します。XQueryプロセッサはJava仮想マシン(JVM)で直接実行されるため、この例を実行するのにデータベースやサーバーは必要ありません。例では、<hello-world>2</hello-world>
を出力します。
この章では、OracleによるXQueryの実装に固有の機能および拡張機能について説明します。このドキュメントでは、XQueryおよびXQJの一般的な情報についてはとりあげません。
関連項目:
関連するAPIドキュメントについては、Oracle Database XML Java APIリファレンスのXQuery Packages
に関する項を参照してください
JSR 225: XQuery API for Java (XQJ)は、https://jcp.org/aboutJava/communityprocess/final/jsr225/index.html
にあります
XQuery 3.0: An XML Query Languageは、http://www.w3.org/TR/xquery-30/
にあります
注意:
Oracleでは、Oracle XML DBの一部としてもXQueryおよびXQJを実装しています。Oracle XML DBの詳細は、「XQuery API for Javaを使用したOracle XML DBへのアクセス」を参照してください。
例7-1 XQJを使用した簡易な問合せ
import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQException;
import javax.xml.xquery.XQPreparedExpression;
import javax.xml.xquery.XQSequence;
import oracle.xml.xquery.OXQDataSource;
public class HelloWorld {
public static void main(String[] args) throws XQException {
OXQDataSource ds = new OXQDataSource();
XQConnection con = ds.getConnection();
String query = "<hello-world>{1 + 1}</hello-world>";
XQPreparedExpression expr = con.prepareExpression(query);
XQSequence result = expr.executeQuery();
// prints "<hello-world>2</hello-world>
"
System.out.println(result.getSequenceAsString(null));
result.close();
expr.close();
con.close();
}
}
XDKでは、問合せ処理中にドキュメント、スキーマ、モジュール、照合および外部関数を取得する方法を制御するために、エンティティ・リゾルバ・フレームワークによってXQJを拡張しています。この項の各例で、複数のタイプのエンティティにエンティティ・リゾルバを使用する方法を示します。問合せプロセッサがリクエストできるエンティティ・タイプの完全なリストについては、Oracle Database XML Java APIリファレンスのoracle.xml.xquery.OXQEntity
クラスに関する項を参照してください。
この項は、次のトピックで構成されています。
この項の例では、エンティティ・リゾルバを使用してfn:doc
関数から返されるドキュメントを特定する方法を示します。
例7-2に、books.xml
の内容を示します。
例7-3に、books.xq
の内容を示します。
例7-4に、カスタム・エンティティ・リゾルバを使用して問合せbooks.xq
を実行する方法を示します。
次の出力が生成されます。
<title>A Game of Thrones</title>
接続に設定することで、MyEntityResolver
のインスタンスがXQueryプロセッサに渡されます。XQueryプロセッサは問合せ処理中にエンティティ・リゾルバを起動して、fn:doc
関数から返されるドキュメントを取得します。
例7-2 books.xml
<books> <book> <title>A Game of Thrones</title> <author><first>George</first><last>Martin</last></author> <price>10.99</price> </book> <book> <title>The Pillars of the Earth</title> <author><first>Ken</first><last>Follett</last></author> <price>7.99</price> </book> </books>
例7-3 books.xq
for $book in fn:doc('books.xml')/books/book where xs:decimal($book/price) gt 10.00 return $book/title
例7-4 カスタム・エンティティ・リゾルバを使用した問合せの実行
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URI; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQView; public class ResolveDocument { private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws IOException { if (kind == OXQEntityKind.DOCUMENT) { URI systemId = locator.getSystemIdAsURI(); if ("file".equals(systemId.getScheme())) { File file = new File(systemId); FileInputStream input = new FileInputStream(file); OXQEntity result = new OXQEntity(input); result.enlistCloseable(input); return result; } } return null; } } public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); // OXQView is used to access Oracle extensions on XQJ objects. OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); File query = new File("books.xq"); // Relative URIs are resolved against the base URI before invoking the entity resolver. // The relative URI 'books.xml' used in the query will be resolved against this URI. XQStaticContext ctx = con.getStaticContext(); ctx.setBaseURI(query.toURI().toString()); FileInputStream queryInput = new FileInputStream(query); XQPreparedExpression expr = con.prepareExpression(queryInput, ctx); queryInput.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
問合せで宣言される外部関数ごとに、oracle.xml.xquery.OXQEntityKind.EXTERNAL_FUNCTION
という種類のエンティティを使用してエンティティ・リゾルバがコールされます。コールでエンティティ・リゾルバに渡されるoracle.xml.xquery.OXQEntityLocator
インスタンスにより、XQuery関数の名前とその引数のタイプが指定されます。エンティティ・リゾルバは、publicコンストラクタを持ち、oracle.xml.xquery.OXQFunctionEvaluator
を拡張する任意のクラスを返すことができます。その後、XQueryプロセッサは返されたクラスをインスタンス化します。XQuery外部関数コールが評価される際、evaluate()
メソッドが起動されます。
例7-6に、エンティティ・リゾルバを使用してXQuery外部関数の実装を定義する方法を示します。
例7-5に、trim.xq
の内容を示します。
例7-6では、trim.xq
を実行して、外部関数の実装を定義する方法を示します。
次の出力が生成されます。
<result>John Doe</result>
外部関数util:trim
を使用して、文字列値の冒頭および末尾から空白を削除します。この関数はJavaに実装されており、問合せ内でコールされます。
例7-6では、エンティティ・リゾルバはOXQFunctionEvaluator
を拡張するクラスを返しました。クラスではなくJava静的メソッドを返す方が便利な場合もあります。静的メソッドが返されると、問合せプロセッサは自動的にメソッド引数をマップして、XQJ仕様で定義されたとおりに、値をXQueryデータ・モデルに返します。
例7-7では、再度trim.xq
を実行しますが、今回は、Java静的メソッドに外部関数がバインドされています。
例によって、次の出力が生成されます。
<result>John Doe</result>
例7-5 trim.xq
declare namespace util = "http://example.com/util"; declare function util:trim($arg as xs:string) as xs:string external; (: a string with surrounding white space :) declare variable $input := " John Doe "; <result>{util:trim($input)}</result>
例7-6 外部関数の実装の定義
import java.io.FileInputStream; import java.io.IOException; import java.util.Collections; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQFunctionContext; import oracle.xml.xquery.OXQFunctionEvaluator; import oracle.xml.xquery.OXQFunctionMetaData; import oracle.xml.xquery.OXQView; public class ResolveExternalFunction { public static class TrimFunction extends OXQFunctionEvaluator { @Override public XQSequence evaluate(OXQFunctionContext context, XQSequence[] params) throws XQException { XQConnection con = context.getConnection(); XQSequence arg = params[0]; String value = arg.getSequenceAsString(null); String trimmed = value.trim(); return con.createSequence(Collections.singleton(trimmed).iterator()); } } private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws XQException, IOException { if (kind == OXQEntityKind.EXTERNAL_FUNCTION) { OXQFunctionMetaData metaData = (OXQFunctionMetaData)locator.getExtension(); QName name = metaData.getName(); int arity = metaData.getParameterTypes().length; if ("http://example.com/util".equals(name.getNamespaceURI()) && "trim".equals(name.getLocalPart()) && arity == 1) { return new OXQEntity(TrimFunction.class); } } return null; } } public static void main(String[] args) throws IOException, XQException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); FileInputStream query = new FileInputStream("trim.xq"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
例7-7 外部関数のJava静的メソッドへのバインド
import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Method; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQFunctionMetaData; import oracle.xml.xquery.OXQView; public class ResolveExternalFunction2 { public static String trim(String value) { return value.trim(); } private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws XQException, IOException { if (kind == OXQEntityKind.EXTERNAL_FUNCTION) { OXQFunctionMetaData metaData = (OXQFunctionMetaData)locator.getExtension(); QName name = metaData.getName(); int arity = metaData.getParameterTypes().length; if ("http://example.com/util".equals(name.getNamespaceURI()) && "trim".equals(name.getLocalPart()) && arity == 1) { Method staticMethod = null; try { staticMethod = ResolveExternalFunction2.class.getMethod("trim", String.class); } catch (NoSuchMethodException e) { throw new IllegalStateException(e); } return new OXQEntity(staticMethod); } } return null; } } public static void main(String[] args) throws IOException, XQException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); FileInputStream query = new FileInputStream("trim.xq"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
XQueryライブラリ・モジュールには、他のモジュールによってインポートできる関数や変数が用意されています。インポートされたモジュールごとに、oracle.xml.xquery.OXQEntityKind.MODULE
という種類のエンティティを使用してエンティティ・リゾルバがコールされます。oracle.xml.xquery.OXQEntityLocator
インスタンスを使用してgetSystemId()
メソッドを起動し、インポートされるモジュールの場所を取得できます。モジュール・インポートで場所が指定されていない場合、getNamespace()
メソッドを起動して、モジュールのターゲット名前空間を取得できます。これにより、エンティティ・リゾルバは対応するライブラリ・モジュールを返すことができます。
この項の例では、エンティティ・リゾルバを使用してXQueryライブラリ・モジュールの解決を制御する方法を示します。
例7-8に、math.xq
の内容を示します。
例7-9に、main.xq
の内容を示します。
例7-10に、ライブラリ・モジュールをインポートする問合せを実行する方法を示します。
次の出力が生成されます。
20.546015931
問合せmain.xq
はライブラリ・モジュールmath.xq
をインポートしてから、関数math:circumference
を起動して円の円周を計算します。
例7-8 math.xq
module namespace math = "http://example.com/math"; declare variable $math:pi as xs:decimal := 3.14159265; declare function math:circumference($diameter as xs:decimal) { $math:pi * $diameter };
例7-9 main.xq
import module namespace math = "http://example.com/math" at "math.xq"; math:circumference(6.54)
例7-10 ライブラリ・モジュールをインポートする問合せの実行
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URI; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQView; public class ResolveLibraryModule { private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws IOException { if (kind == OXQEntityKind.MODULE) { URI systemId = locator.getSystemIdAsURI(); if (systemId != null && "file".equals(systemId.getScheme())) { File file = new File(systemId); FileInputStream input = new FileInputStream(file); OXQEntity result = new OXQEntity(input); result.enlistCloseable(input); return result; } } return null; } } public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); // OXQView is used to access Oracle extensions on XQJ objects. OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); File query = new File("main.xq"); // Relative URIs are resolved against the base URI before invoking the entity resolver. // The relative URI 'math.xq' used in the query will be resolved against this URI. XQStaticContext ctx = con.getStaticContext(); ctx.setBaseURI(query.toURI().toString()); FileInputStream queryInput = new FileInputStream(query); XQPreparedExpression expr = con.prepareExpression(queryInput, ctx); queryInput.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
XQueryスキーマ・インポートでは、要素宣言、属性宣言および型定義をXMLスキーマからインポートします。インポートされた宣言および定義を問合せで使用して、データ・インスタンスを検証およびテストできます。
この項の例では、エンティティ・リゾルバを使用して、問合せでスキーマをインポートする際に使用されるXMLスキーマを制御する方法を示します。
例7-11に、size.xsd
の内容を示します。
例7-12に、size.xq
の内容を示します。
例7-13に、スキーマをインポートする問合せを実行する方法を示します。
次の出力が生成されます。
S INVALID:big XL INVALID:42
問合せsize.xq
では、スキーマsize.xsd
で定義されたタイプshirt-size
を使用して値リストをテストします。
例7-11 size.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/size"> <xs:simpleType name="shirt-size"> <xs:restriction base="xs:string"> <xs:enumeration value="XS"/> <xs:enumeration value="S"/> <xs:enumeration value="M"/> <xs:enumeration value="L"/> <xs:enumeration value="XL"/> </xs:restriction> </xs:simpleType> </xs:schema>
例7-12 size.xq
import schema namespace ns = "http://example.com/size" at "size.xsd"; for $size in ("S", "big", "XL", 42) return if ($size castable as ns:shirt-size) then ns:shirt-size($size) else concat("INVALID:", $size)
例7-13 スキーマをインポートする問合せの実行
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URI; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQEntity; import oracle.xml.xquery.OXQEntityKind; import oracle.xml.xquery.OXQEntityLocator; import oracle.xml.xquery.OXQEntityResolver; import oracle.xml.xquery.OXQEntityResolverRequestOptions; import oracle.xml.xquery.OXQView; public class ResolveSchema { private static class MyEntityResolver extends OXQEntityResolver { @Override public OXQEntity resolveEntity(OXQEntityKind kind, OXQEntityLocator locator, OXQEntityResolverRequestOptions options) throws IOException { if (kind == OXQEntityKind.SCHEMA) { URI systemId = locator.getSystemIdAsURI(); if (systemId != null && "file".equals(systemId.getScheme())) { File file = new File(systemId); FileInputStream input = new FileInputStream(file); OXQEntity result = new OXQEntity(input); result.enlistCloseable(input); return result; } } return null; } } public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); // OXQView is used to access Oracle extensions on XQJ objects. OXQConnection ocon = OXQView.getConnection(con); ocon.setEntityResolver(new MyEntityResolver()); File query = new File("size.xq"); // Relative URIs are resolved against the base URI before invoking the entity resolver. // The relative URI 'math.xq' used in the query will be resolved against this URI. XQStaticContext ctx = con.getStaticContext(); ctx.setBaseURI(query.toURI().toString()); FileInputStream queryInput = new FileInputStream(query); XQPreparedExpression expr = con.prepareExpression(queryInput, ctx); queryInput.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
XDKには、ファイル・システムおよびHTTP解決などの一般的なタスクに使用できる、OXQEntityResolver
の実装がいくつか含まれています。ファイル・システムを使用してエンティティを解決する前述の例では、MyEntityResolver
をXDKで利用可能なファイル・エンティティ・リゾルバに置き換えることができます。
この項の例では、独自のエンティティ・リゾルバを実装せずに、例7-3の問合せを実行する方法を示します。
例7-14に、あらかじめ作成されたファイル・リゾルバを使用して問合せbooks.xq
を実行する方法を示します。
例7-14により、次の出力が生成されます。
<title>A Game of Thrones</title>
ファクトリoracle.xml.xquery.OXQFileResolverFactory
のインスタンスが接続から作成されます。次に、このファクトリを使用して、ファイル・システムに対してスキーマ、モジュールおよびドキュメントを解決するエンティティ・リゾルバを作成します。この例とは異なり、例7-4では、カスタム・エンティティ・リゾルバMyEntityResolver
を使用してファイル・システムに対してドキュメントのみを解決しています。
XDKには、次のエンティティ・リゾルバ・ファクトリが用意されています。
oracle.xml.xquery.OXQFileResolverFactory
: スキーマ、モジュールおよびドキュメントの場所の'file:' URIを解決するエンティティ・リゾルバを作成します。
oracle.xml.xquery.OXQHttpResolverFactory
: スキーマ、モジュールおよびドキュメントの場所の'http:' URIを解決するエンティティ・リゾルバを作成します。
oracle.xml.xquery.OXQCompositeResolverFactory
: リクエストを他のエンティティ・リゾルバに委任するエンティティ・リゾルバを作成します。どの種類のリクエストに対しても、リゾルバは委任したいずれかのリゾルバから受け取ったnull以外の最初の結果を返します。
oracle.xml.xquery.OXQJavaResolverFactory
: Java静的メソッドまたはクラスに対して外部関数およびモジュールを解決するエンティティ・リゾルバを作成します。
関連項目:
これらのファクトリ・インタフェースのAPI情報については、Oracle Database XML Java APIリファレンスのパッケージoracle.xml.xquery
に関する項を参照してください
例7-14 あらかじめ作成されたファイル・リゾルバを使用した問合せの実行
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConnection; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQFileResolverFactory; import oracle.xml.xquery.OXQView; public class ResolverFactory { public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); // OXQView is used to access Oracle extensions on XQJ objects. OXQConnection ocon = OXQView.getConnection(con); OXQFileResolverFactory factory = ocon.createEntityResolverFactory(OXQFileResolverFactory.class); ocon.setEntityResolver(factory.createResolver()); File query = new File("books.xq"); // Relative URIs are resolved against the base URI before invoking the entity resolver. // The relative URI 'books.xml' used in the query will be resolved against this URI. XQStaticContext ctx = con.getStaticContext(); ctx.setBaseURI(query.toURI().toString()); FileInputStream queryInput = new FileInputStream(query); XQPreparedExpression expr = con.prepareExpression(queryInput, ctx); queryInput.close(); XQSequence result = expr.executeQuery(); System.out.println(result.getSequenceAsString(null)); result.close(); expr.close(); con.close(); } }
XDK XQueryプロセッサには、アプリケーションのパフォーマンスとスケーラビリティを向上させるための機能がいくつか用意されています。
この項は、次のトピックで構成されています。
XDK XQuery Processor for Javaでは、多くのタイプの問合せのストリーミング評価をサポートしています。入力XMLが非常に大きい場合でも、ストリーミング評価では少量のメイン・メモリーしか必要ありません。
ストリーミング評価を簡略化するために、次のアクションが推奨されます。
静的コンテキストでバインディング・モードを遅延モードに設定します(Oracle Database XML Java APIリファレンスのjavax.xml.xquery.XQStaticContext.setBindingMode(int)
メソッドに関する項を参照)。バインディング・モードが遅延でない場合、バインドされる際に入力XMLは完全にマテリアライズされます。
入力XMLをjava.io.InputStream
、java.io.Reader
またはjavax.xml.stream.XMLStreamReader
のインスタンスとして提供します。入力XMLは、式にバインドするかエンティティ・リゾルバから返すことによって、問合せプロバイダに提供されます。
次のように、javax.xml.xquery.XQSequence
インスタンスが、マテリアライズが不要な方法で使用されるようにします。
文字列シリアライズ・メソッドgetSequenceAsString(...)
およびgetItemAsString(...)
では、データはメモリーに保持される文字列として生成されます。かわりに、writeSequence(...)
またはwriteItem(...)
メソッドを使用して、シーケンスをシリアライズしてください。
getNode()
メソッドでは、メモリーに保持されるDocument Object Model (DOM)ノードが構築されます。かわりに、getSequenceAsStream()
またはgetItemAsStream()
メソッドを使用してStreaming API for XML (StAX)ストリームを取得することを検討してください。
getItem()
メソッドでは、メモリー内で現在のアイテムがコピーされてマテリアライズされます。かわりに、java.xml.xquery.XQSequence
インスタンスで直接メソッドを使用して、現在のアイテムにアクセスしてください(Oracle Database XML Java APIリファレンスのインタフェースjavax.xml.xquery.XQItemAccessor
に関する項を参照)。
この項の例では、ストリーミング評価が妨げられない方法で、XQJを使用して問合せを起動します。
例7-15に、books2.xq
の内容を示します。
例7-16では、ストリーミング評価を有効にする問合せを設定します。
例7-16により、次の出力がファイルresults.xml
に書き込まれます。
<title>A Game of Thrones</title>
準備された式にバインドする際、books.xml
がマテリアライズされないように、バインディング・モードが値BINDING_MODE_DEFERRED
に設定されます。同様に、結果は出力ストリームに書き込まれ、マテリアライズされません。
例を簡略化するために、入力ファイルはbooks.xml
は小さくなっています。ファイルに何百万もの書籍が含まれる場合でも、メモリーには一度に1つの書籍要素しか保持されないため、問合せの評価では小さな最大ヒープ・サイズしか必要ありません。例7-3の問合せbooks.xq
とは異なり、問合せbooks2.xq
ではエンティティ・リゾルバを定義する必要はありません。例(books.xq
とbooks2.xq
)は両方ともストリーム可能です。
例7-15 books2.xq
declare variable $doc external; for $book in $doc/books/book where xs:decimal($book/price) gt 10.00 return $book/title
例7-16 ストリーミング評価の促進
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQConstants; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQDataSource; public class Streaming { public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); XQStaticContext ctx = con.getStaticContext(); ctx.setBindingMode(XQConstants.BINDING_MODE_DEFERRED); con.setStaticContext(ctx); FileInputStream input = new FileInputStream("books.xml"); FileInputStream query = new FileInputStream("books2.xq"); FileOutputStream output = new FileOutputStream("result.xml"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); expr.bindDocument(new QName("doc"), input, null, null); XQSequence result = expr.executeQuery(); result.writeSequence(output, null); result.close(); input.close(); output.close(); expr.close(); con.close(); } }
問合せによっては、プロセッサは問合せ評価中に入力XMLの一部をメイン・メモリーに格納しなければならないことがあります。このシナリオは、たとえば次のような場合に発生します。
シーケンスがソートされる場合。
変数にバインドされた値を、複数回使用する場合。
パス式が逆行軸ステップを使用する場合。
このような場合にメモリー使用量を削減するために、メイン・メモリーではなく外部ストレージを使用してXMLをマテリアライズするように、XQueryプロセッサを構成できます。外部ストレージを使用可能にするには、データ・ソース・プロパティOXQConstants.USE_EXTERNAL_STORAGE
をtrue
に設定し、動的コンテンツでoracle.xml.scalable.PageManager
インスタンスを設定します。
注意:
外部ストレージを使用すると、問合せ処理中に消費されるメイン・メモリーの容量を大幅に削減できます。ただし、パフォーマンスも低下する可能性があります。
例7-17に、XMLをマテリアライズする際に、XQueryプロセッサでメイン・メモリーではなくディスクベースのストレージを使用できるようにする方法を示します。
例7-17により、次の出力がファイルresults.xml
に書き込まれます。
<title>A Game of Thrones</title>
例7-17 外部ストレージを使用するようにXQuery Processorを構成
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQConstants; import javax.xml.xquery.XQException; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQSequence; import javax.xml.xquery.XQStaticContext; import oracle.xml.scalable.FilePageManager; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQPreparedExpression; import oracle.xml.xquery.OXQView; public class ExternalStorage { public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); ds.setProperty(OXQDataSource.USE_EXTERNAL_STORAGE, "true"); XQConnection con = ds.getConnection(); XQStaticContext ctx = con.getStaticContext(); ctx.setBindingMode(XQConstants.BINDING_MODE_DEFERRED); con.setStaticContext(ctx); FileInputStream input = new FileInputStream("books.xml"); FileInputStream query = new FileInputStream("books2.xq"); FileOutputStream output = new FileOutputStream("results.xml"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); expr.bindDocument(new QName("doc"), input, null, null); // Set a page manager that will be used by the XQuery processor if XML needs to be materialized OXQPreparedExpression oexpr = OXQView.getPreparedExpression(expr); File temporaryFile = File.createTempFile("books", ".pagefile"); temporaryFile.deleteOnExit(); oexpr.setPageManager(new FilePageManager(temporaryFile.getAbsolutePath())); XQSequence result = expr.executeQuery(); result.writeSequence(output, null); result.close(); input.close(); output.close(); expr.close(); con.close(); } }
OracleによるXQJの実装は、スレッド・セーフではありません。たとえば、javax.xml.xquery.XQSequence
のインスタンスには、1つのスレッドのみがアクセスする必要があります。ただし、javax.xml.xquery.XQConnection
のインスタンスを管理するために、制限された形式でのスレッド・セーフティがサポートされます。
XQConnection
のインスタンスは、XQExpression
、XQPreparedExpression
、XQItem
, XQSequence
、XQItemType
およびXQSequenceType
の各インスタンスの作成においてファクトリとして機能します。1つのスレッドが、他のスレッドで使用されるこれらのオブジェクトの作成を管理できます。たとえば、同じ接続によって1つのスレッドで作成されたXQPreparedExpression
インスタンスを、別のスレッドで使用できます。ただし、各XQPreparedExpression
インスタンスは、1つのスレッドによってのみ実行する必要があります。同じ接続の式が同時に評価される際、指定されたoracle.xml.xquery.OXQEntityResolver
の任意のユーザー定義実装はスレッド・セーフである必要があります。
XQConnection.close()
メソッドは、接続から取得されたすべてのXQExpression
およびXQPreparedExpression
インスタンスをクローズします。これらのインスタンスをクローズすると、式から取得されたすべてのXQResultSequence
およびXQResultItem
インスタンスがクローズされます。接続から取得された式が他のスレッドで処理されている間、XQConnection.close()
メソッドをコールできます。この場合、式によって保持されている登録済のすべてのリソース(java.io.InputStream
やjava.io.Reader
など)がクローズされます。この規定では、登録済のすべてのリソースが、スレッド・セーフなクローズ・メソッドをサポートしていると想定しています。たとえば、java.io.Closeable
の多くのJDK実装は、この要件を満たしています。しかし、javax.xml.stream.XMLStreamReader
の多くの実装には、スレッド・セーフなクローズ・メソッドはありません。これがサポートされていない実装を、2番目のスレッドがまだ読取りを実行中にクローズすると、予期しない結果が生じる可能性があります(Oracle Database XML Java APIリファレンスのインタフェースoracle.xml.xquery.OXQCloseable
に関する項を参照)。
関連項目:
Oracle Database XML Java APIリファレンスのメソッドoracle.xml.xquery.OXQConnection.copyExpression(XQPreparedExpression)
に関する項
XDKでは、問合せの更新を実行する機能によってXQJが拡張されています。XML文書をjavax.xml.xquery.XQItem
のインスタンスとして読み取った後、拡張機能XQuery Update Facilityを使用して変更できます。この機能はデフォルトで無効です。これは、動的コンテキストで更新モードをoracle.xml.xquery.OXQConstants.UPDATE_MODE_ENABLED
に設定することで、有効にできます。
更新する文書は、遅延モードでバインドされている必要があります(Oracle Database XML Java APIリファレンスのjavax.xml.xquery.XQStaticContext.setBindingMode(int)
メソッドに関する項を参照)。バインディング・モードが遅延に設定されていない場合、問合せ実行の前に、入力バインディングがコピーされます。このため、コピーのみが更新されます。
この項の各例では、XQuery Update Facilityを使用してXML文書を変更する方法を示します。
例7-18に、configuration.xml
の内容を示します。
例7-19に、update.xq
の内容を示します。
例7-20に、更新後のconfiguration.xm
の内容を示します。
例7-21に、問合せupdate.xq
の実行方法を示します。
例では、次のアクションが行われます。
XMLファイルconfiguration.xml
がjavax.xml.xquery.XQItem
のインスタンスとして読み取られます。
アイテムが問合せupdate.xq
の準備された式にバインドされます。
問合せupdate.xq
が実行されます。
変更された文書がファイルconfiguration.xml
に書き込まれます。
関連項目:
XQuery Update Facility 1.0はhttp://www.w3.org/TR/xquery-update-10/
にあります
Oracle Database XML Java APIリファレンスのインタフェースoracle.xml.xquery.OXQDynamicContext
に関する項
例7-18 configuration.xml
<configuration> <property> <name>hostname</name> <value>example.com</value> </property> <property> <name>timeout</name> <value>1000</value> </property> </configuration>
例7-19 update.xq
declare variable $doc external; let $timeout := $doc/configuration/property[name eq "timeout"] return replace value of node $timeout/value with 2 * xs:integer($timeout/value)
例7-20 更新されたファイルconfiguration.xml
<configuration> <property> <name>hostname</name> <value>example.com</value> </property> <property> <name>timeout</name> <value>2000</value> </property> </configuration>
例7-21 問合せupdate.xqの更新の実行
import java.io.FileInputStream; import java.io.IOException; import java.io.FileOutputStream; import javax.xml.namespace.QName; import javax.xml.xquery.XQConnection; import javax.xml.xquery.XQConstants; import javax.xml.xquery.XQException; import javax.xml.xquery.XQItem; import javax.xml.xquery.XQPreparedExpression; import javax.xml.xquery.XQStaticContext; import oracle.xml.xquery.OXQConstants; import oracle.xml.xquery.OXQDataSource; import oracle.xml.xquery.OXQView; public class UpdateDocument { public static void main(String[] args) throws XQException, IOException { OXQDataSource ds = new OXQDataSource(); XQConnection con = ds.getConnection(); XQStaticContext ctx = con.getStaticContext(); // Set the binding mode to deferred so the document // item is not copied when it is bound. ctx.setBindingMode(XQConstants.BINDING_MODE_DEFERRED); con.setStaticContext(ctx); FileInputStream input = new FileInputStream("configuration.xml"); XQItem doc = con.createItemFromDocument(input, null, null); input.close(); System.out.println("Before update: \n" + doc.getItemAsString(null)); FileInputStream query = new FileInputStream("update.xq"); XQPreparedExpression expr = con.prepareExpression(query); query.close(); expr.bindItem(new QName("doc"), doc); // Enable updates (disabled by default) OXQView.getDynamicContext(expr).setUpdateMode(OXQConstants.UPDATE_MODE_ENABLED); expr.executeQuery(); System.out.println("After update: \n" + doc.getItemAsString(null)); // Write the modified document back to the file FileOutputStream out = new FileOutputStream("configuration.xml"); doc.writeItem(out, null); expr.close(); con.close(); } }
XDK XQuery Processor for Javaは、次の標準および仕様に準拠しています。
XQuery 3.0:
http://www.w3.org/TR/xquery-30/
注意:
すべてのXQuery 1.0レベル機能がサポートされます。次を除くXQuery 3.0レベル機能がサポートされます: FLWORウィンドウ句、FLWORカウント句、名前空間コンストラクタ、10進フォーマット宣言、fn:format-number
、fn:format-integer
、fn:format-date
、fn:format-time
、fn:path
およびXQuery高階関数。XQuery Update Facility 1.0:
XML Syntax for XQuery 3.0 (XQueryX):
JSR 225: XQuery API for Java (XQJ):
https://jcp.org/aboutJava/communityprocess/final/jsr225/index.html
注意:
XDK XQuery processor for Javaは、Oracle XML DBのOracle XQJ実装を含め、他のXQJ実装とは相互運用できません。(相互運用可能の意味については、『JSR-225: XQuery API for Java』を参照してください。)
この項は、次のトピックで構成されています。
XQuery仕様では、特定の機能がオプションとして定義されています。表7-1に、XDKでサポートされるXQueryのオプションの機能を示します。
表7-1 XDKでサポートされるXQueryのオプションの機能
機能 | 参照先 |
---|---|
スキーマのインポート |
|
スキーマの検証 |
|
静的型指定 |
|
全軸のサポート |
|
モジュール |
|
シリアライズ |
XQJ仕様およびXQuery仕様では、特定分野の定義は実装によって異なり得るとしています。この項の各表で、XDKの実装定義項目について簡単に説明します。
表7-2に、XQJの実装定義項目をまとめます。
表7-2 XQJの実装定義項目
説明 | 動作 |
---|---|
|
|
|
なし。ユーザー名とパスワードは警告なしで無視されます。 |
JDBC接続のサポート |
JDBC接続はサポートされません。 |
コマンド |
サポートされません。 |
メソッド |
可 |
シリアライズ |
可 |
追加のStAXまたはSAXイベント |
サポート対象外 |
ユーザー定義スキーマ型 |
可 |
ノードが外部変数にバインドされている場合の、ノードID、文書順、ノード・コンテキストの完全保持 |
保持されません。 |
ログイン・タイムアウト |
サポートされません。 |
トランザクション |
サポートされません。トランザクション・メソッドがコールされると、例外がスローされます。 |
入力ノードが文書ノードでない場合の |
例外 |
匿名型の |
一意の名前。 |
|
型がXQJから作成される場合は、スキーマURIが返されます。そうでない場合はなし。 |
入力が整形式のXML文書でない場合の |
例外 |
クラス |
Oracle固有のエラー・コードの修飾名は、名前空間 |
|
なし |
|
JDBC接続はサポートされません。このメソッドがコールされると、例外がスローされます。 |
|
|
注意:
表7-2の機能のXDKサポートは、Oracle XML DBサポートとは異なります。
表7-3に、XQueryの実装定義項目をまとめます。
表7-3 XQueryの実装定義項目
項目 | 動作 |
---|---|
式の構成に使用されるUnicodeのバージョン |
4.0 |
静的に認識されている照合 |
Unicodeコード・ポイント照合およびクラス |
暗黙的なタイム・ゾーン。 |
メソッド |
警告が表示される状況および警告が処理される方法 |
サポート対象外 |
エラーが外部処理環境にレポートされるメソッド |
例外 |
実装がXML 1.0およびXML Namesのルール、またはXML 1.1およびXML Names 1.1のルールのどちらに基づいているか |
1.0 |
実装によって上書きまたは拡張された、静的コンテキストまたは動的コンテキストのすべてのコンポーネント |
表7-5を参照 |
全軸機能がサポートされていない場合に、実装でサポートされるオプションの軸 |
フル・サポート |
ORDER BY句(empty leastまたはempty greatest)で順序付けキー(sortspec)によって戻された空のシーケンスのデフォルト処理 |
|
実装によって認識された任意の拡張式(pragmas)の名前およびセマンティック |
サポート対象外 |
実装によって認識された任意のオプション宣言の名前およびセマンティック |
サポート対象外 |
パラメータを外部関数に渡し、関数の結果を起動中の問合せに戻すプロトコル(ある場合) |
XQJによって定義されます |
モジュール機能がサポートされる場合、モジュール・インポートでインポートする特定モジュールを識別するプロセス(処理する場所のヒントがある場合はそれも含む) |
エンティティ・リゾルバ |
静的型指定機能がサポートされる場合、実装でサポートされる静的型指定拡張機能 |
静的モード(サブタイプに基づく)およびオプティミスティック・モード(型交差に基づく)。オプティミスティック・モードがデフォルトです。 |
シリアライズ機能がサポートされる場合、シリアライズを起動する方法。 |
XQJによって定義されます |
シリアライズ機能がサポートされる場合、 |
Oracle Database XML Java APIリファレンスのインタフェース |
XQuery 1.0仕様の第5.3項に列挙されている、様々なデータ型の値範囲の制限 |
小数値および整数値は任意精度を持ちます。 |
表7-4に、XQuery Update Facilityの実装定義項目をまとめます。
表7-4 XQuery Update Facilityの実装定義項目
項目 | 動作 |
---|---|
この実装でサポートされる再検証モード。 |
|
この実装のデフォルトの再検証モード。 |
|
外部関数がXDMインスタンスまたは保留中の更新リスト、あるいはその両方を、起動中の問合せに戻すメカニズム(ある場合)。 |
外部関数から保留中の更新リストを戻すことは、サポートされていません。 |
この関数がオペランドとして受け入れるノードの種類を含む、 |
すべてのノード・タイプが受け入れられます。ノードのストレージは、エンティティ・リゾルバによって決定されます。エンティティの種類 |
表7-5に、静的コンテキストのデフォルトの初期値をまとめます。
表7-5 静的コンテキストのデフォルトの初期値
コンテキスト・コンポーネント | デフォルト値 |
---|---|
静的に認識されている名前空間 |
|
デフォルトの要素/タイプ名前空間 |
名前空間なし |
デフォルトの関数名前空間 |
|
有効範囲内のスキーマ・タイプ |
|
有効範囲内の要素宣言 |
サポート対象外 |
有効範囲内の属性宣言 |
サポート対象外 |
有効範囲内の変数 |
サポート対象外 |
コンテキスト項目の静的タイプ |
|
関数シグネチャ |
|
静的に認識されている照合 |
Unicodeコード・ポイント照合およびクラス |
デフォルトの照合 |
Unicodeコード・ポイント照合:
|
構成モード |
|
順序付けモード |
|
空のシーケンスのデフォルトの順序 |
|
境界スペース・ポリシー |
|
コピー名前空間モード |
|
ベースURI |
標準で定義されたとおり |
静的に認識されている文書 |
サポート対象外 |
静的に認識されているコレクション |
サポート対象外 |
静的に認識されているデフォルトのコレクション・タイプ |
|