プライマリ・コンテンツに移動
Oracle® XML Developer's Kitプログラマーズ・ガイド
12c リリース1 (12.1) B71283-04
目次へ移動
目次
索引へ移動
索引

前
次

7 XQuery Processor for Javaの使用

この章では、Oracle XML Developer's Kit (XDK) XQuery Processor for Javaの使用方法について説明します。

内容は次のとおりです。

7.1 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の一般的な情報についてはとりあげません。

関連項目:

注意:

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

7.2 エンティティの解決

XDKでは、問合せ処理中にドキュメント、スキーマ、モジュール、照合および外部関数を取得する方法を制御するために、エンティティ・リゾルバ・フレームワークによってXQJを拡張しています。この項の各例で、複数のタイプのエンティティにエンティティ・リゾルバを使用する方法を示します。問合せプロセッサがリクエストできるエンティティ・タイプの完全なリストについては、Oracle Database XML Java APIリファレンスoracle.xml.xquery.OXQEntityクラスに関する項を参照してください。

この項は、次のトピックで構成されています。

7.2.1 ドキュメントの解決

この項の例では、エンティティ・リゾルバを使用して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();
    }
}

7.2.2 外部関数の解決

問合せで宣言される外部関数ごとに、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();
    }
}

7.2.3 モジュールの解決

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

7.2.4 スキーマの解決

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

7.2.5 あらかじめ作成されたエンティティ・リゾルバ

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

7.3 パフォーマンスとスケーラビリティ

XDK XQueryプロセッサには、アプリケーションのパフォーマンスとスケーラビリティを向上させるための機能がいくつか用意されています。

この項は、次のトピックで構成されています。

7.3.1 ストリーミング問合せ評価

XDK XQuery Processor for Javaでは、多くのタイプの問合せのストリーミング評価をサポートしています。入力XMLが非常に大きい場合でも、ストリーミング評価では少量のメイン・メモリーしか必要ありません。

ストリーミング評価を簡略化するために、次のアクションが推奨されます。

  • 静的コンテキストでバインディング・モードを遅延モードに設定します(Oracle Database XML Java APIリファレンスjavax.xml.xquery.XQStaticContext.setBindingMode(int)メソッドに関する項を参照)。バインディング・モードが遅延でない場合、バインドされる際に入力XMLは完全にマテリアライズされます。

  • 入力XMLをjava.io.InputStreamjava.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.xqbooks2.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();
    }
}

7.3.2 外部ストレージ

問合せによっては、プロセッサは問合せ評価中に入力XMLの一部をメイン・メモリーに格納しなければならないことがあります。このシナリオは、たとえば次のような場合に発生します。

  • シーケンスがソートされる場合。

  • 変数にバインドされた値を、複数回使用する場合。

  • パス式が逆行軸ステップを使用する場合。

このような場合にメモリー使用量を削減するために、メイン・メモリーではなく外部ストレージを使用してXMLをマテリアライズするように、XQueryプロセッサを構成できます。外部ストレージを使用可能にするには、データ・ソース・プロパティOXQConstants.USE_EXTERNAL_STORAGEtrueに設定し、動的コンテンツで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();
    }
}

7.3.3 スレッド・セーフティ

OracleによるXQJの実装は、スレッド・セーフではありません。たとえば、javax.xml.xquery.XQSequenceのインスタンスには、1つのスレッドのみがアクセスする必要があります。ただし、javax.xml.xquery.XQConnectionのインスタンスを管理するために、制限された形式でのスレッド・セーフティがサポートされます。

  • XQConnectionのインスタンスは、XQExpressionXQPreparedExpressionXQItem, XQSequenceXQItemTypeおよびXQSequenceTypeの各インスタンスの作成においてファクトリとして機能します。1つのスレッドが、他のスレッドで使用されるこれらのオブジェクトの作成を管理できます。たとえば、同じ接続によって1つのスレッドで作成されたXQPreparedExpressionインスタンスを、別のスレッドで使用できます。ただし、各XQPreparedExpressionインスタンスは、1つのスレッドによってのみ実行する必要があります。同じ接続の式が同時に評価される際、指定されたoracle.xml.xquery.OXQEntityResolverの任意のユーザー定義実装はスレッド・セーフである必要があります。

  • XQConnection.close()メソッドは、接続から取得されたすべてのXQExpressionおよびXQPreparedExpressionインスタンスをクローズします。これらのインスタンスをクローズすると、式から取得されたすべてのXQResultSequenceおよびXQResultItemインスタンスがクローズされます。接続から取得された式が他のスレッドで処理されている間、XQConnection.close()メソッドをコールできます。この場合、式によって保持されている登録済のすべてのリソース(java.io.InputStreamjava.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)に関する項

7.4 更新の実行

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の実行方法を示します。

例では、次のアクションが行われます。

  1. XMLファイルconfiguration.xmljavax.xml.xquery.XQItemのインスタンスとして読み取られます。

  2. アイテムが問合せupdate.xqの準備された式にバインドされます。

  3. 問合せupdate.xqが実行されます。

  4. 変更された文書がファイル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();
    }
}

7.5 標準と仕様 - XQuery Processor for Java

XDK XQuery Processor for Javaは、次の標準および仕様に準拠しています。

注意:

XDK XQuery processor for Javaは、Oracle XML DBのOracle XQJ実装を含め、他のXQJ実装とは相互運用できません。(相互運用可能の意味については、『JSR-225: XQuery API for Java』を参照してください。)

この項は、次のトピックで構成されています。

7.5.1 オプションの機能

XQuery仕様では、特定の機能がオプションとして定義されています。表7-1に、XDKでサポートされるXQueryのオプションの機能を示します。

7.5.2 実装定義の項目

XQJ仕様およびXQuery仕様では、特定分野の定義は実装によって異なり得るとしています。この項の各表で、XDKの実装定義項目について簡単に説明します。

表7-2に、XQJの実装定義項目をまとめます。

表7-2 XQJの実装定義項目

説明 動作

XQDataSource実装のクラス名

oracle.xml.xquery.OXQDataSource

OXQDataSourceで定義されたプロパティ

なし。ユーザー名とパスワードは警告なしで無視されます。

JDBC接続のサポート

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

コマンド

サポートされません。

メソッドXQPreparedExpression.cancel()での問合せ実行の取消し

シリアライズ

追加のStAXまたはSAXイベント

サポート対象外

ユーザー定義スキーマ型

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

保持されません。

ログイン・タイムアウト

サポートされません。

トランザクション

サポートされません。トランザクション・メソッドがコールされると、例外がスローされます。

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

例外

匿名型のXQItemType.getTypeName()メソッド

一意の名前。

XQItemType.getSchemaURI()メソッド

型がXQJから作成される場合は、スキーマURIが返されます。そうでない場合はなし。

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

例外

クラスXQQueryExceptionによって戻される追加のエラー・コード

Oracle固有のエラー・コードの修飾名は、名前空間http://xmlns.oracle.com/xdk/xquery/errorsにあります

ConnectionPoolXQDataSourcePooledXQConnectionXQConnectionEventXQConnectionEventListenerインタフェース

なし

XQDataSource.getConnection(java.sql.Connection)

JDBC接続はサポートされません。このメソッドがコールされると、例外がスローされます。

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

getConnection()と同じ。パラメータは無視されます。

注意:

表7-2の機能のXDKサポートは、Oracle XML DBサポートとは異なります。

表7-3に、XQueryの実装定義項目をまとめます。

表7-3 XQueryの実装定義項目

項目 動作

式の構成に使用されるUnicodeのバージョン

4.0

静的に認識されている照合

Unicodeコード・ポイント照合およびクラスjava.text.Collatorまたはoracle.i18n.text.OraCollatorから導出された照合

暗黙的なタイム・ゾーン。

メソッドjava.util.Calendar.getInstance()で決定されたデフォルトのタイム・ゾーンを使用

警告が表示される状況および警告が処理される方法

サポート対象外

エラーが外部処理環境にレポートされるメソッド

例外javax.xml.xquery.XQException

実装がXML 1.0およびXML Namesのルール、またはXML 1.1およびXML Names 1.1のルールのどちらに基づいているか

1.0

実装によって上書きまたは拡張された、静的コンテキストまたは動的コンテキストのすべてのコンポーネント

表7-5を参照

全軸機能がサポートされていない場合に、実装でサポートされるオプションの軸

フル・サポート

ORDER BY句(empty leastまたはempty greatest)で順序付けキー(sortspec)によって戻された空のシーケンスのデフォルト処理

least

実装によって認識された任意の拡張式(pragmas)の名前およびセマンティック

サポート対象外

実装によって認識された任意のオプション宣言の名前およびセマンティック

サポート対象外

パラメータを外部関数に渡し、関数の結果を起動中の問合せに戻すプロトコル(ある場合)

XQJによって定義されます

モジュール機能がサポートされる場合、モジュール・インポートでインポートする特定モジュールを識別するプロセス(処理する場所のヒントがある場合はそれも含む)

エンティティ・リゾルバ

静的型指定機能がサポートされる場合、実装でサポートされる静的型指定拡張機能

静的モード(サブタイプに基づく)およびオプティミスティック・モード(型交差に基づく)。オプティミスティック・モードがデフォルトです。

シリアライズ機能がサポートされる場合、シリアライズを起動する方法。

XQJによって定義されます

シリアライズ機能がサポートされる場合、byte-order-markencodingmedia-typenormalization-formomit-xml-declarationstandaloneおよびversionパラメータのデフォルト値

Oracle Database XML Java APIリファレンスのインタフェースoracle.xml.xquery.OXQSerializationParametersに関する項を参照してください。

XQuery 1.0仕様の第5.3項に列挙されている、様々なデータ型の値範囲の制限

小数値および整数値は任意精度を持ちます。

表7-4に、XQuery Update Facilityの実装定義項目をまとめます。

表7-4 XQuery Update Facilityの実装定義項目

項目 動作

この実装でサポートされる再検証モード。

skip

この実装のデフォルトの再検証モード。

skip

外部関数がXDMインスタンスまたは保留中の更新リスト、あるいはその両方を、起動中の問合せに戻すメカニズム(ある場合)。

外部関数から保留中の更新リストを戻すことは、サポートされていません。

この関数がオペランドとして受け入れるノードの種類を含む、fn:put()のセマンティック。

すべてのノード・タイプが受け入れられます。ノードのストレージは、エンティティ・リゾルバによって決定されます。エンティティの種類UPD_PUTのドキュメントについては、Oracle Database XML Java APIリファレンスoracle.xml.xquery.OXQEntityクラスに関する項を参照してください。

表7-5に、静的コンテキストのデフォルトの初期値をまとめます。

表7-5 静的コンテキストのデフォルトの初期値

コンテキスト・コンポーネント デフォルト値

静的に認識されている名前空間

fn=http://www.w3.org/2005/xpath-functions

xml=http://www.w3.org/XML/1998/namespace

xs=http://www.w3.org/2001/XMLSchema

xsi=http://www.w3.org/2001/XMLSchema-instance

local=http://www.w3.org/2005/xquery-local-functions

ora-ext=http://xmlns.oracle.com/xdk/xquery/extension

ora-java=http://xmlns.oracle.com/xdk/xquery/java

ora-xml=http://xmlns.oracle.com/xdk/xquery/xml

ora-fn=http://xmlns.oracle.com/xdk/xquery/function

ora-で始まる接頭辞は、Oracleでの使用が予約されています。今後のリリースで、ora-で始まる追加の接頭辞が、デフォルトの静的に認識されている名前空間に追加される可能性があります。

デフォルトの要素/タイプ名前空間

名前空間なし

デフォルトの関数名前空間

fn

有効範囲内のスキーマ・タイプ

xsのビルトイン・タイプ

有効範囲内の要素宣言

サポート対象外

有効範囲内の属性宣言

サポート対象外

有効範囲内の変数

サポート対象外

コンテキスト項目の静的タイプ

item()

関数シグネチャ

fn名前空間の関数およびビルトイン・アトミック・タイプのコンストラクタ

静的に認識されている照合

Unicodeコード・ポイント照合およびクラスjava.text.Collatorまたはoracle.i18n.text.OraCollatorから導出された照合

デフォルトの照合

Unicodeコード・ポイント照合:

http://www.w3.org/2005/xpath-functions/collation/codepoint

構成モード

preserve

順序付けモード

ordered

空のシーケンスのデフォルトの順序

least

境界スペース・ポリシー

strip

コピー名前空間モード

preserve, no-inherit

ベースURI

標準で定義されたとおり

静的に認識されている文書

サポート対象外

静的に認識されているコレクション

サポート対象外

静的に認識されているデフォルトのコレクション・タイプ

node()*