25 XSQLページ・パブリッシング・フレームワークの使用: 高度なトピック

XSQLページ・パブリッシング・フレームワークの高度な機能の使用方法について説明します。

関連項目:

基本的な機能の説明は、XSQLページ・パブリッシング・フレームワークの使用を参照してください

25.1 XSQL構成ファイル名のカスタマイズ

デフォルトでは、XSQLページ・フレームワークの構成ファイルの名前はXSQLConfig.xmlです。開発用、テスト用、本番用というように、使用する環境に応じて構成ファイルのバージョンを簡単に切り替えられることができます。XSQL Page Processorで読み取る構成ファイルの名前をオーバーライドするには、システム・プロパティxsql.configを設定します。

サーブレット初期化パラメータxsql.configを定義することで、-Dxsql.config=MyConfigFile.xmlなどのJava仮想マシン(JVM)コマンドライン・フラグを指定するのが最も簡単な方法です。次に示すように、XSQLサーブレットを定義する<servlet>タグの一部として<init-param>要素をweb.xmlファイルに追加します。

<servlet>
  <servlet-name>XSQL</servlet-name>
  <servlet-class>oracle.xml.xsql.XSQLServlet</servlet-class>
  <init-param>
    <param-name>xsql.config</param-name>
    <param-value>MyConfigFile.xml</param-value>
    <description>
       Please Use MyConfigFile.xml instead of XSQLConfig.xml
    </description>
  </init-param>
</servlet>

サーブレット初期化パラメータを使用できるのは、XSQLエンジンをサーブレット・ベースで使用する場合のみです。XSQLCommandLineまたはXSQLRequestプログラム・インタフェースを使用する場合は、かわりにSystemパラメータを使用してください。

注意:

構成ファイルは、常にCLASSPATHから読み取られます。たとえば、MyConfigFile.xmlという名前のカスタム構成パラメータ・ファイルを指定すると、XSQL ProcessorはこのXMLファイルをCLASSPATHからのリソースとして読み取ろうとします。Java Platform, Enterprise Edition (Java EE)などのサーブレット環境では、MyConfigFile.xml.\WEB-INF\classesディレクトリ(またはCLASSPATHの別の最上位レベル・ディレクトリ)に配置する必要があります。サーブレット初期化パラメータとSystemパラメータの両方が指定されている場合は、サーブレット初期化パラメータの値が使用されます。

25.2 スタイルシートの処理方法の制御

このトピックでは、クライアントのスタイルシートの概要、コンテンツ・タイプの制御、スタイルシートの動的割当て、クライアントでのスタイルシートの処理、および複数のスタイルシートの提供について説明します。

25.2.1 クライアントのスタイルシートでのオーバーライド

リクエスト中の現在のXSQLページが許可する場合、リクエストでExtensible Stylesheet Language Transformation (XSLT)スタイルシートのURLを指定できます。この方法により、デフォルトのスタイルシートをオーバーライドしたり、デフォルトでスタイルシートが適用されない場合にスタイルシートを適用できます。

クライアントが起動するスタイルシートURLは、xml-stylesheetパラメータをリクエストの一部として指定することによって、指定されます。このパラメータに対する有効な値は次のとおりです。

  • 処理中のXSQLページに対して相対的に解析されるすべての相対URL。

  • HTTPプロトコル・スキームを使用し、XSQL構成ファイルの定義に従ってトラステッド・ホストを参照するすべての絶対URL。

  • リテラル値nonexml-stylesheet=noneの設定は、開発中、XSLTスタイルシートの処理を一時的に短絡させてスタイルシートが実際に参照しているXMLデータグラムを確認する場合に有用です。この方法は、スタイルシートで期待した結果が生成されない場合の理由確認に使用できます。

クライアントによるXSQLページ用スタイルシートのオーバーライドは、次の方法で行います。

  • XSQL構成ファイルでallow-client-style構成パラメータをnoに設定します。

  • XSQLページのドキュメント要素に対して、allow-client-style="no"属性を明示的に挿入します。

XSQL構成ファイルでクライアントによるスタイルシートのオーバーライドがデフォルトでグローバルに使用禁止にされている場合でも、すべてのページで、そのページのドキュメント要素に対してallow-client-style="yes"属性を挿入することによって、クライアントによるオーバーライドを明示的に使用可能にできます。

25.2.2 戻されたドキュメントのコンテンツ・タイプの制御

提供するデータのコンテンツ・タイプを設定することにより、リクエスト側クライアントは、戻されたデータを正しく解析できます。スタイルシートで<xsl:output>要素を使用する場合、XSQL Processorは、<xsl:output>media-type属性およびencoding属性から、戻されたドキュメントのメディア・タイプおよびエンコーディングを推測します。

例25-1のスタイルシートでは、<xsl:output>に対してmedia-type="application/vnd.ms-excel"属性を使用します。この命令により、hr.employees表に対する標準の問合せを含むXSQLページの結果をMicrosoft Excel形式に変換します。

次のXSQLページでは、例25-1のスタイルシートを使用します。

<?xml version="1.0"?>
<?xml-stylesheet href="empToExcel.xsl" type="text/xsl"?>
<xsql:query connection="hr" xmlns:xsql="urn:oracle-xsql">
  SELECT   employee_id, email, salary 
  FROM     employees 
  ORDER BY salary DESC
</xsql:query>

例25-1 empToExcel.xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" media-type="application/vnd.ms-excel"/>
  <xsl:template match="/">
   <html>
     <table>
       <tr><th>Id</th><th>Email</th><th>Salary</th></tr>
       <xsl:for-each select="ROWSET/ROW">
         <tr>
           <td><xsl:value-of select="EMPLOYEE_ID"/></td>
           <td><xsl:value-of select="EMAIL"/></td>
           <td><xsl:value-of select="SALARY"/></td>
         </tr>
       </xsl:for-each>
     </table>
   </html>
  </xsl:template>
</xsl:stylesheet>

25.2.3 スタイルシートの動的割当て

<?xml-stylesheet?>処理命令を.xsqlファイルの最上部に挿入すると、XSQL Page Processorは結果として生成されるXMLデータグラムの変換にそれを使用することを検討します。

例25-2emp_test.xsqlページについて考えてみます。

例25-2のページは、emp.xslスタイルシートを使用して、リクエスタにレスポンスを戻す前にemployees問合せの結果をサーバー層で変換します。このスタイルシートは、<?xml-stylesheet?>処理命令に対するhref擬似属性で指定されるURLによってアクセスされます。

たとえば、XSLTスタイルシートを、XSQLサーブレットに渡す引数に基づいて動的に変更するには、次のサンプル命令に示すように、xml-stylesheet処理命令のhref属性に字句パラメータを使用します。

<?xml-stylesheet type="text/xsl" href="{@filename}.xsl"?>

これで、filenameパラメータの値をURLリクエストの一部としてXSQLサーブレットに渡すことができます。

XSQLページの<xsql:set-page-param>要素を使用して、SQL問合せに基づいてパラメータの値を設定することもできます。たとえば、例25-3のXSQLページでは、ページのプライベート・パラメータの値を割り当てることによって、使用するスタイルシートの名前を表から選択します。

例25-2 emp_test.xsql

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="emp.xsl"?>
<page connection="demo" xmlns:xsql="urn:oracle-xsql">
  <xsql:query>
    SELECT   * 
    FROM     employees
    ORDER BY salary DESC
  </xsql:query>
</page>

例25-3 emp_test_dynamic.xsql

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="{@sheet}.xsl"?>
<page connection="demo" xmlns:xsql="urn:oracle-xsql">
  <xsql:set-page-param bind-params="UserCookie" name="sheet">
    SELECT stylesheet_name
    FROM   user_prefs
    WHERE  username = ?
  </xsql:set-page-param>
  <xsql:query>
    SELECT   * 
    FROM     employees 
    ORDER BY salary DESC
  </xsql:query>
</page>

25.2.4 クライアントでのXSLTスタイルシートの処理

クライアントでのXSLTスタイルシートの処理方法について説明します。

一部のブラウザは、クライアントでのXSLTスタイルシートの処理をサポートします。これらのブラウザは、<?xml-stylesheet?>処理命令を使用して、XML文書用に処理されるスタイルシートを認識します。この目的に<?xml-stylesheet?>を使用することは、1999年6月29日に公開されたW3C勧告「Associating Stylesheets with XML Documents, Version 1.0」の一部です。

デフォルトでは、XSQL Page ProcessorはXSLT変換をサーバーで実行します。ただし、client="yes"をXSQLページの<?xml-stylesheet?>処理命令に追加することにより、クライアントに対するXSLT処理を遅延できます。ドキュメントの最上部に現行の<?xml-stylesheet?>要素が挿入された状態で未加工のXMLデータグラムが提供されます。

25.2.5 複数のスタイルシートの提供

複数の<?xml-stylesheet?>処理命令をXSQLページの最上部に挿入できます。

この命令にはオプションのmedia擬似属性を指定できます。media擬似属性に値を指定すると、その値は大/小文字を区別してHTTPヘッダーのユーザー・エージェント文字列の値と比較されます。media擬似属性の値がユーザー・エージェント文字列の一部と一致した場合、プロセッサは現行の<?xml-stylesheet?>処理命令を選択して使用します。一致しなかった場合は、その処理命令を無視して、検索を続けます。ドキュメント内の順序で最初に一致した処理命令が使用されます。media擬似属性がない処理命令は、すべてのユーザー・エージェントと一致します。

例25-4に、XSQLファイルの最上部に複数の処理命令がある場合を示します。処理には、Lynxブラウザの場合はdoyouxml-lynx.xslを、Internet Explorer 5.0または5.5ブラウザの場合はdoyouxml-ie.xslを、および他のすべてのブラウザの場合はdoyouxml.xslを使用します。

表25-1に、<?xml-stylesheet?>処理命令に対して使用可能な、サポートされる擬似属性の概要を示します。

表25-1 <?xml-stylesheet?>の擬似属性

属性名 説明
type = "string"

関連付けられたスタイルシートのMultipurpose Internet Mail Extensions (MIME)タイプを示します。XSLTスタイルシートの場合、この属性は文字列text/xslに設定する必要があります。

serializer属性を使用する場合、この属性は、そのシリアライザをコールする前にXSLTスタイルシートを実行する必要があるかどうかによって、存在する場合存在しない場合があります。

href = "URL"

使用するXSLTスタイルシートへの相対URLまたは絶対URLを指定します。httpプロトコル・スキームを使用する絶対URLを指定する場合は、リソースのIPアドレスがXSQL構成ファイル(デフォルト名XSQLConfig.xml)に示されているトラステッド・ホストである必要があります。

media = "string"

リクエスト側デバイスが送信したHTTPヘッダーのUser-Agent文字列に対する大/小文字を区別しない一致検索を実行します。この属性はオプションです。現行の<?xml-stylesheet?>処理命令は、User-Agent文字列にmedia属性の値が含まれている場合にのみ使用されます。含まれていない場合は、無視されます。

client = "boolean"

yesに設定すると、関連付けられた、クライアントに対するXSLTスタイルシートの処理が遅延します。ドキュメントの最上部に現行の<?xml-stylesheet?>処理命令が挿入された状態で、未加工のXMLデータグラムがクライアントに送信されます。値を指定しない場合、デフォルトでは、変換がサーバーで実行されます。

serializer = "string"

デフォルトでは、XSQL Page Processorは次のものを使用します。

  • XML Document Object Model (DOM)シリアライザ(XSLTスタイルシートを使用しない場合)

  • XSLTプロセッサのシリアライザ(XSLTスタイルシートを使用する場合)

この擬似属性を指定すると、前述のコードのかわりにカスタム・シリアライザの実装を使用する必要があります。

有効値は、XSQL構成ファイルの<serializerdefs>セクションで定義されるカスタム・シリアライザの名前、または文字列java:fully.qualified.Classnameです。XSLTスタイルシートとserializer属性の両方が存在する場合は、まずXSLT変換が実行され、次にカスタム・シリアライザがコールされて最終結果がOutputStreamまたはPrintWriterにレンダリングされます。

例25-4 複数の<?xml-stylesheet?>処理命令

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" media="lynx" href="doyouxml-lynx.xsl" ?>
<?xml-stylesheet type="text/xsl" media="msie 5" href="doyouxml-ie.xsl" ?>
<?xml-stylesheet type="text/xsl" href="doyouxml.xsl" ?>
<page xmlns:xsql="urn:oracle-xsql" connection="demo">

25.3 配列値パラメータの使用

このトピックでは、パラメータでの配列値の使用、およびSQLまたはPL/SQLコードでのページまたはセッション・パラメータの使用について説明します

25.3.1 配列値パラメータの値のサポート

リクエスト・パラメータ、セッション・パラメータおよびページのプライベート・パラメータで、値に文字列の配列を使用できます。パラメータの値を配列として処理するには、パラメータの名前の最後に一対の空の大カッコを追加します。

たとえば、productidという名前の入力コントロールが4回出現するHTMLフォームをポストする場合、配列値であるproductidパラメータを参照するにはproductid[]という表記を使用します。配列値パラメータを、配列を示すカッコを付けずに参照すると、XSQLプロセッサにより最初の配列エントリの値が値として使用されます。

注意:

XSQLプロセッサでは、配列を示すカッコ内での数値の使用はサポートされていません。つまり、productidまたはproductid[]を参照することはできますが、productid[2]は参照できません。

アクション・ハンドラ属性値内またはアクション・ハンドラ要素のコンテンツ内のいずれかで、配列値パラメータを字句置換パラメータとして参照するとします。値は配列内での出現順序に従って、配列内でNULL以外の文字列および空以外の文字列のカンマ区切りのリストに変換されます。例25-5に、配列値パラメータを使用したXSQLページを示します。

XSQLコマンドライン・ユーティリティを起動して、次の方法でPage.xsqlproductidパラメータに複数の値を指定できます。

xsql Page.xsql productid=111 productid=222 productid=333 productid=444

前述のコマンドで、productid[]配列値パラメータの値を{"111","222","333","444"}に設定します。XSQL Page Processorによって、問合せの{@productid[]}式が文字列"111,222,333,444"に置き換えられます。

複数値のパラメータをプログラムで渡すには、名前付きパラメータのjava.util.Dictionaryを受け入れるXSQLRequestアプリケーション・プログラミング・インタフェース(API)を使用します。リクエストにString値パラメータを追加するには、Hashtableを使用し、そのput(name,value)メソッドを起動します。複数値のパラメータを追加する場合は、String型の値ではなくString[]型の値を使用します。

注意:

リクエスト・パラメータ、ページのプライベート・パラメータおよびセッション・パラメータでのみ、文字列配列を使用できます。<xsql:set-stylesheet-param>および<xsql:set-cookie>アクションでは、単純な文字列値としてのパラメータの使用のみサポートしています。XSLTスタイルシートで複数値のパラメータを参照するには、<xsql:include-param>を使用してXSQLデータページに複数値のパラメータを挿入し、次に同じスタイルシート内でXPath式を使用してデータページからの値を参照します。

例25-5 XSQLページでの配列値パラメータの使用

<page xmlns:xsql="urn:oracle-xsql">
  <xsql:query>
    SELECT description
    FROM product
    WHERE productid in ( {@productid[]} )  /* Using lexical parameter */
  </xsql:query>
</page>

25.3.2 文字列からの配列値ページまたはセッション・パラメータの設定

文字列から、ページのプライベート・パラメータまたはセッション・パラメータの値を設定できます。

次のように、配列を示すカッコを名前に使用することで、ページのプライベート・パラメータの値を文字列配列値に設定できます。

<!-- param name contains array brackets -->
<xsql:set-page-param name="names[]" value="Tom Jane Joe"/>

次の例に示すように、セッション・パラメータの値を同様に設定します。

<xsql:set-session-param name="dates[]" value="12-APR-1962 15-JUL-1968"/>

デフォルトでは、パラメータの名前に配列を示すカッコが追加されていると、XSQLプロセッサにより値は空白またはカンマ区切りのリストとして処理され、トークン化されます。

結果として得られる文字列配列値には、これらの区切られたトークンが含まれています。前述の例では、パラメータnames[]は文字列配列{"Tom", "Jane", "Joe"}で、パラメータdates[]は文字列配列{"12-APR-1962", "15-JUL-1968"}です。

空白を含む文字列を処理するために、トークン化アルゴリズムはまず文字列を調べてカンマが存在するかどうかを確認します。文字列内にカンマが1つ以上見つかった場合は、そのカンマをトークン・デリミタとして使用します。たとえば、次のアクションは、names[]パラメータの値を文字列配列{"Tom Jones", "Jane York"}に設定します。

<!-- param name contains array brackets -->
<xsql:set-page-param name="names[]" value="Tom Jones,Jane York"/>

デフォルトでは、名前の最後に配列を示すカッコがないパラメータを設定すると、文字列のトークン化は実行されません。したがって、次のアクションでは、namesパラメータをリテラル文字列"Tom Jones,Jane York"に設定します。

<!-- param name does NOT contain array brackets -->
<xsql:set-page-param name="names" value="Tom Jones,Jane York"/>

<xsql:set-page-param>アクションまたは<xsql:set-session-param>アクションにtreat-list-as-array="yes"属性を挿入し、文字列を強制的にトークン化することもできます。この属性を設定すると、パラメータにカンマ区切りのトークン化された値の文字列が割り当てられます。たとえば、次のアクションでは、namesパラメータをリテラル文字列"Tom,Jane,Joe"に設定します。

<!-- param name does NOT contain array brackets -->
<xsql:set-page-param name="names" value="Tom Jane Joe"
                     treat-list-as-array="yes"/>

単一の文字列値パラメータの値を設定し、treat-list-as-array="yes"を使用して値をトークン化するときに、quote-array-values="yes"属性を挿入してカンマ区切りの値を一重引用符で囲むという方法があります。したがって、次のアクションでは、namesパラメータにリテラル文字列値"'Tom Jones','Jane York','Jimmy'"を割り当てます。

<!--  param name does NOT contain array brackets -->
<xsql:set-page-param name="names" value="Tom Jones,Jane York,Jimmy"
                     treat-list-as-array="yes"
                     quote-array-values="yes"/>

25.3.3 SQL文およびPL/SQL文での配列値パラメータのバインド

文字列値のスカラー型バインド変数がサポートされているXSQLページでは、配列値パラメータをバインドすることもできます。それには、属性bind-paramsに指定するパラメータ名のリスト内で、配列パラメータ名(たとえば、myparam[])を使用します。この方法により、SQL文およびPL/SQLプロシージャ内で配列値パラメータを処理できます。

配列値パラメータは、XSQL_TABLE_OF_VARCHARという名前のネストした表のオブジェクト型としてバインドされます。この型は、次のDDL文を使用して現行のスキーマ内に作成する必要があります。

CREATE TYPE xsql_table_of_varchar AS TABLE OF VARCHAR2(2000);

型の名前をxsql_table_of_varchar以外に変更することはできませんが、VARCHAR2文字列の次元は必要に応じて変更できます。配列値文字列のパラメータを扱う文字列値と同じ長さにする必要があります。

例25-6のPL/SQLファンクションについて考えてみます。

例25-7のXSQLページに、testTableFunctionを使用するSQL文内で、2つの配列値パラメータをバインドする方法を示します。

例25-7のXSQLページを実行すると、次のデータグラムが生成されます。

<page someNames="aa,bb,cc" someValues="11,22,33">
  <ROWSET>
    <ROW num="1">
      <EXAMPLE>aa=11:bb=22:cc=33</EXAMPLE>
    </ROW>
  </ROWSET>
</page>

この方法は、配列値パラメータのsomeNames[]およびsomeValues[]が表のコレクション型としてバインドされていることを示します。値が繰り返され、連結された結果、PL/SQLファンクションの戻り値である"aa=11:bb=22:cc=33"文字列値が生成されます。

bind-paramsの文字列に、通常のパラメータと配列値パラメータを必要な数のみ混合して指定することができます。配列としてバインドするパラメータには、配列を示すカッコを追加します。

注意:

前述のXSQL_TABLE_OF_VARCHAR型を作成せずに例25-7のページを実行すると、次のようなエラーが戻されます。

<page someNames="aa,bb,cc" someValues="11,22,33">
  <xsql-error code="17074" action="xsql:query">
    <statement>
     select testTableFunction(?,?) as example from dual
    </statement>
    <message>
      invalid name pattern: SCOTT.XSQL_TABLE_OF_VARCHAR
    </message>
  </xsql-error>
</page>

配列パラメータはネストされた表のコレクション型としてXSQLプロセッサによりバインドされるため、SQL文内でTABLE()演算子とCAST()演算子を組み合せて使用し、ネストされた表のバインド変数値を値の表として扱うことができます。この表に問合せを行えます。この方法は、副問合せに特に有効です。例25-8のページは、従業員IDを含む配列値パラメータを使用して、行の問合せ先をhr.employeesに制限した例です。

例25-8のXSQLページを実行すると、次のようなデータグラムが生成されます。

<page>
  <ROWSET>
    <ROW num="1">
      <NAME>Alana Walsh</NAME>
      <SALARY>3100</SALARY>
    </ROW>
    <ROW num="2">
      <NAME>Kevin Feeny</NAME>
      <SALARY>3000</SALARY>
    </ROW>
  </ROWSET>
</page>

例25-7および例25-8では、<xsql:query>でのbind-paramsの使用方法を説明しましたが、これらの機能は<xsql:dml><xsql:include-owa><xsql:ref-cursor-function>、およびSQL文またはPL/SQL文を使用できるその他のアクションでも使用できます。

PL/SQLの索引付き表は、OCI JDBCドライバでは使用できますが、シンJDBCドライバでは使用できません。ネストした表のコレクション型であるXSQL_TABLE_OF_VARCHARを使用すると、配列値パラメータを両方のドライバで使用できます。これにより、PL/SQL内で値の配列を使用するというプログラム上の柔軟性が保たれます。

例25-6 testTableFunction

FUNCTION testTableFunction(p_name  XSQL_TABLE_OF_VARCHAR,
                           p_value XSQL_TABLE_OF_VARCHAR)
RETURN VARCHAR2 IS
  lv_ret     VARCHAR2(4000);
  lv_numElts INTEGER;
BEGIN
  IF p_name IS NOT NULL THEN
    lv_numElts := p_name.COUNT;
    FOR j IN 1..lv_numElts LOOP
      IF (j > 1) THEN
        lv_ret := lv_ret||':';
      END IF;
      lv_ret := lv_ret||p_name(j)||'='||p_value(j);
    END LOOP;
  END IF;
  RETURN lv_ret;
END;

例25-7 配列値パラメータを使用したXSQLページ

<page xmlns:xsql="urn:oracle-xsql" connection="demo"
      someNames="aa,bb,cc" someValues="11,22,33">
  <xsql:query bind-params="someNames[] someValues[]">
    SELECT testTableFunction(?,?) AS example 
    FROM dual
  </xsql:query>
</page>

例25-8 配列値パラメータによる行の制限

<page xmlns:xsql="urn:oracle-xsql" connection="hr">
  <xsql:set-page-param name="someEmployees[]" value="196,197"/>
  <xsql:query bind-params="someEmployees[]">
    SELECT first_name||' '||last_name AS name, salary
    FROM employees
    WHERE employee_id IN (
        SELECT * FROM TABLE(CAST( ? AS xsql_table_of_varchar))
     )
   </xsql:query>
</page>

25.4 組込みアクションでのエラー・パラメータの設定

組込みXSQLアクションで致命的でないエラーが報告された場合、そのアクションにページのプライベート・パラメータを設定できます。

XSQL Page Processorでは、アクションの実行中に、致命的ではないエラーが発生したかどうかが判別されます。たとえば、行の挿入またはストアド・プロシージャの起動がデータベース例外で失敗することがあり、この例外は <xsql-error>要素としてXSQLデータ・ページに挿入されます。

アクションで属性error-paramを使用すると、組込みXSQLアクションで致命的でないエラーが報告された場合に、そのアクションにページのプライベート・パラメータを設定できます。たとえば、アクション<xsql:dml>内の文でデータベース・エラーが発生した場合にパラメータdml-errorを設定するには、例25-9の方法を使用します。

<xsql:dml>アクションを実行したときにエラーが発生すると、dml-errorという名前のページのプライベート・パラメータが文字列"Error"にXSQLプロセッサにより設定されます。実行が成功した場合、XSQLプロセッサはエラー・パラメータに値は割り当てられません。例25-9では、ページのプライベート・パラメータdml-errorがすでに存在する場合、現行の値が維持されます。存在しない場合、このパラメータが出現することはありません。

例25-9 エラー・パラメータの設定

<xsql:dml error-param="dml-error" bind-params="val">
  INSERT INTO yourtable(somecol) 
    VALUES(?)
</xsql:dml>

25.4.1 エラー・パラメータでの条件付きロジックの使用

XSQLページ・テンプレートでの条件付き動作の実行方法について説明します。

このエラー・パラメータを<xsql:if-param>と組み合せて使用することで、XSQLページ・テンプレート内で条件付き動作を実行できます。たとえば、XSQL構成ファイル内で、接続demoの接続定義のAUTOCOMMITフラグをfalseに設定したとします。例25-10のXSQLページに、先行するアクションにおいて行った変更を、後続のアクションでエラーが発生した場合にどのようにロールバックするかを示します。

カスタム・アクション・ハンドラを作成済で、カスタム・アクションがreportMissingAttribute()reportError()またはreportErrorIncludingStatement()を起動して致命的でないアクション・エラーを通知する場合、この機能も自動的に使用されます。

例25-10 エラー・パラメータでの条件付き動作の実行

<!-- NOTE: Connection "demo" must not set to autocommit! -->
<page connection="demo" xmlns:xsql="urn:oracle-xsql">
  <xsql:dml error-param="dml-error" bind-params="val">
    INSERT INTO yourtable(somecol) 
      VALUES(?)
  </xsql:dml>
  <!-- This second statement will commit if it succeeds -->
  <xsql:dml commit="yes" error-param="dml-error" bind-params="val2">
    INSERT INTO anothertable(anothercol)
      VALUES(?)
  </xsql:dml>
  <xsql:if-param name="dml-error" exists="yes">
    <xsql:dml>
      ROLLBACK
    </xsql:dml>
  </xsql:if-param>
</page>

25.4.2 XSQLアクション・ハンドラ・エラーのフォーマット

XSQLアクション・ハンドラ要素の処理によって発生したエラーは、XML要素として決まった方法で通知されます。そのため、XSLTスタイルシートはエラーの存在を検出し、オプションでそれらをフォーマットして表示できます。

エラー内のアクション要素は、ページ内で次の要素に置き換えられます。

<xsql-error action="xxx"> 

エラーによっては、<xsql-error>要素に次のものが含まれます。

  • ネストした<message>要素

  • 違反SQL文を含む<statement>要素

例25-11では、次の情報を使用してエラー情報を画面上に表示するXSLTスタイルシートの例を示します。

例25-11 XSLTスタイルシート

<xsl:if test="//xsql-error">
     <table style="background:yellow">
        <xsl:for-each select="//xsql-error">
           <tr>
            <td><b>Action</b></td>
            <td><xsl:value-of select="@action"/></td>
            </tr>
            <tr valign="top">
            <td><b>Message</b></td>
            <td><xsl:value-of select="message"/></td>
           </tr>
          </xsl:for-each>
     </table>
</xsl:if>

25.5 XMLType問合せ結果のXSQLページへの反映

Oracle Databaseでは、XMLベースのデータベース・コンテンツの格納および問合せに、XMLTypeを使用できます。

データベースXML機能を使用して、次のいずれかの方法でXSQLページに挿入するXMLデータを生成できます。

  • <xsql:query>: XMLType型の列を含む問合せを処理します。ただし、CLOB列およびVARCHAR2列内のXMLマークアップはリテラル・テキストとして処理されます。

  • <xsql:include-xml>: 問合せから取得した1つのCLOBまたは文字列ベースのXML文書を解析し、挿入します。

前述の2つの方法には1つの相違点があります。<xsql:include-xml>は、必要に応じてCLOBまたは文字列値内のリテラルXMLを解析し、要素および属性のツリーとして表現します。これに対し、<xsql:query>は、CLOBまたは文字列の値列内のXMLマークアップをリテラル・テキストのままにしておく点が異なります。

もう1つの相違点は、<xsql:query>は任意の数の列および行の問合せ結果を処理しますが、<xsql:include-xml>は、1つの行の1つの列を処理するという点です。このため、<xsql:include-xml>を使用すると、そこに含まれるSELECT文は、1つの列を含む1つの行を戻します。この列は、整形式のXML文書を含むCLOBまたはVARCHAR2値です。このXML文書は、XSQLエンジンによって解析され、XSQLページに挿入されます。

例25-12では、ネストしたXmlAgg()関数を使用して、部門およびネストした従業員を含む動的に作成されたXML文書の結果を集計します。この関数は、結果を<DepartmentList>要素でラップして1つの結果文書に集計します。

別の例として、moviesというXMLTypeの表に多数の<Movie>というXML文書が格納されているとします。それぞれの文書は、例25-13のようになっているとします。

組込みXPath問合せ機能を使用すると、データベースに含まれるすべての映画から、アカデミー賞を受賞したすべての出演者の集計リストを抽出できます。例25-14に、サンプルの問合せを示します。

このXMLTypeの問合せ結果をXSQLページに挿入するには、<xsql:query>要素の中に問合せを貼り付けます。例25-15のように、必ず問合せ式の別名を挿入します。

XmlElement()XmlAgg()を組み合せて使用すると、データベースで、問合せで検出されたすべてのXMLフラグメントを1つの整形式XML文書に集計できます。関数によって次のような整形式の結果が生成されます。

<AwardedActors>
  <Actor>...</Actor>
  <Actress>...</Actress>
</AwardedActors>

バインド変数を式に連結する場合は、XPath式の途中で標準のXSQLバインド変数機能を使用することもできます。たとえば、値Oscaraward-fromという名前のパラメータにするには、XSQLページを例25-16のように使用します。

例25-12 動的に作成されたXML文書の集計

<xsql:query connection="hr" xmlns:xsql="urn:oracle-xsql">
  SELECT XmlElement("DepartmentList",
           XmlAgg(
             XmlElement("Department", 
               XmlAttributes(department_id AS "Id"),
               XmlForest(department_name AS "Name"),
               (SELECT XmlElement("Employees",
                         XmlAgg( 
                           XmlElement("Employee",
                             XmlAttributes(employee_id AS "Id"),
                             XmlForest(first_name||' '||last_name AS "Name",
                                       salary   AS "Salary",
                                       job_id   AS "Job")
                           )
                         )
                       )
                FROM employees e 
                WHERE e.department_id = d.department_id
               )
             )
           )
         ) AS result
  FROM departments d
  ORDER BY department_name
</xsql:query>

例25-13 Movie XML文書

<Movie Title="The Talented Mr.Ripley" RunningTime="139" Rating="R">
  <Director>
    <First>Anthony</First>
    <Last>Minghella</Last>
  </Director>
  <Cast>
    <Actor Role="Tom Ripley">
      <First>Matt</First>
      <Last>Damon</Last>
    </Actor>
    <Actress Role="Marge Sherwood">
      <First>Gwyneth</First>
      <Last>Paltrow</Last>
    </Actress>
    <Actor Role="Dickie Greenleaf">
      <First>Jude</First>
      <Last>Law</Last>
      <Award From="BAFTA" Category="Best Supporting Actor"/>
    </Actor>
  </Cast>
</Movie>

例25-14 XPathを使用した集計リストの抽出

SELECT XMLELEMENT("AwardedActors",
           XMLAGG(EXTRACT(VALUE(m),
                  '/Movie/Cast/*[Award[@From="Oscar"]]')))
FROM movies m

例25-15 XMLTypeの問合せ結果の挿入

<xsql:query connection="demo" xmlns:xsql="urn:oracle-xsql">
  SELECT XMLELEMENT("AwardedActors",
           XMLAGG(EXTRACT(VALUE(m),
                  '/Movie/Cast/*[Award[@From="Oscar"]]'))) AS result
  FROM movies m
</xsql:query>

例25-16 XPath式でのXSQLバインド変数の使用

<xsql:query connection="orcl92" xmlns:xsql="urn:oracle-xsql"
            award-from="Oscar"  bind-params="award-from">
  /* Using a bind variable in an XPath expression */
  SELECT XMLELEMENT("AwardedActors",
           XMLAGG(EXTRACT(VALUE(m),
                  '/Movie/Cast/*[Award[@From="'|| ? ||'"]]'))) AS result
  FROM movies m
</xsql:query>

25.6 ポストされたXMLコンテンツの処理

XSQLページ・フレームワークは、XMLコンテンツの作成および変換を簡略化するだけでなく、ポストされたXMLコンテンツの処理にも役立ちます。

組込みアクションの利点は次のとおりです。

  • XML文書形式およびHTML形式のポストされたデータの処理が簡単になります。

  • XSUを使用してデータをデータベース表に直接ポストできます。

XSUは、ターゲット表またはビューに必要な正規の形式のXML文書のコンテンツに基づいて、データベースの挿入、更新および削除機能を実行します。特定のデータベース表では、そのデータの正規のXML形式は、SELECT *問合せからのXML出力の1行によって指定されます。この形式のXML文書では、XSUはDML操作を自動化できます。

XSUとXSLTを組み合せると、すべての形式のXMLを特定の表に対して適切な正規の形式に変換できます。変換後、結果として戻る正規のXMLに対してXSUでDMLを実行できます。

次の組込みXSQLアクションを使用すると、この機能をXSQLページ内から使用できます。

  • <xsql:insert-request>

    リクエストでポストされ、オプションで変換されたXML文書を表に挿入します。

  • <xsql:update-request>

    リクエストでポストされ、オプションで変換されたXML文書を表またはビューに更新します。

  • <xsql:delete-request>

    リクエストでポストされ、オプションで変換されたXML文書を表またはビューから削除します。

  • <xsql:insert-param>

    リクエスト・パラメータの値としてポストされ、オプションで変換されたXML文書を表またはビューに挿入します。

データベース・ビューを挿入のターゲットにする場合、そのビューに対するINSTEAD OF INSERTトリガーを作成し、ポストされた情報の処理をさらに自動化することができます。たとえば、ビューのINSTEAD OF INSERTトリガーは、PL/SQLを使用してレコードの有無を確認し、その確認結果に応じてINSERTまたはUPDATEのどちらを実行するかを効果的に選択できます。

25.6.1 XMLポスト・オプションの理解

XMLポスト・オプションの概要を示します。

XSQLページ・フレームワークでは、ポストされたデータを次のように処理できます。

  • クライアント・プログラムは、XSQLページをターゲットとするHTTP POSTメッセージを送信します。リクエストの本体にはXML文書を含み、HTTPヘッダーに"text/xml"のContentTypeを指定します。

    この場合、<xsql:insert-request><xsql:update-request>または<xsql:delete-request>を使用して、ポストされたXMLのコンテンツをターゲット表で挿入、更新または削除できます。XSLT変換を使用してポストされたXML文書を変換する場合、ポストされた文書がこの変換のソース・ドキュメントです。

  • クライアント・プログラムは、パラメータの1つにXML文書を含む、XSQLページに対するHTTP GETリクエストを送信します。

    この場合、<xsql:insert-param>アクションを使用して、ポストされたXMLパラメータ値のコンテンツをターゲット表に挿入できます。XSLTを使用してポストされたXML文書を変換する場合、パラメータ値内のXML文書がこの変換のソース・ドキュメントです。

  • ブラウザは、アクションがXSQLページをターゲットとする、method="POST"が設定されたHTMLフォームを送信します。HTTP POSTメッセージのリクエスト本体は、エンコードされたフォーム・フィールドおよびその値を含み、ContentTypeを"application/x-www-form-urlencoded"に指定します。

    この場合、このリクエストはXML文書を含まず、エンコードされたフォーム・パラメータを含みます。ただし、これらの3つの場合を同等にするために、XSQL Page Processorは(必要に応じて)リクエストに含まれるフォーム・パラメータ、セッション変数およびCookieからXML文書を生成します。この動的マテリアライズドXML文書は、<xsql:insert><xsql:update-request>または<xsql:delete-request>を使用して、DML用に正規の形式に変換されます。

ポストされたHTMLフォームを使用する場合、動的マテリアライズドXML文書は例25-17に示す形式になります。

複数のパラメータが同じ名前でポストされた場合、複数の<row>要素が自動的に作成され、それ以降の処理が簡単になります。次のパラメータおよび値をポストまたは挿入するリクエストを想定します。

  • id = 101

  • name = Steve

  • id = 102

  • name = Sita

  • operation = update

XSQLページ・プロセッサによって、次のパラメータが作成されます。

<request>
  <parameters>
    <row>
      <id>101</id>
      <name>Steve</name>
    </row>
    <row>
      <id>102</id>
      <name>Sita</name>
    </row>
    <operation>update</operation>
  </parameters>
  ...
</request>

リクエスト・パラメータを含むこのマテリアライズされたXML文書をターゲット表の正規の形式に変換するために、XSLTスタイルシートの指定が必要になります。これにより、次のようなXSQLページを作成できます。

<!-- 
 | ShowRequestDocument.xsql
 | Show Materialized XML Document for an HTML Form
 +-->
<xsql:include-request-params xmlns:xsql="urn:oracle-xsql"/>

このページを適切に使用すると、HTMLフォームを一時的に変更して、ShowRequestDocument.xsqlページにポストできます。また、ブラウザで、マテリアライズドXMLリクエスト文書の未加工のXMLが表示されます。このXMLは、保存してXSL変換を展開するために使用できます。

例25-17 HTMLフォームから生成されたXML文書

<request>
  <parameters>
    <firstparamname>firstparamvalue</firstparamname>
     ... 
    <lastparamname>lastparamvalue</lastparamname>
  </parameters>
  <session>
    <firstparamname>firstsessionparamvalue</firstparamname>
      ...
    <lastparamname>lastsessionparamvalue</lastparamname>
  </session>
  <cookies>
    <firstcookie>firstcookievalue</firstcookiename>
       ... 
    <lastcookie>firstcookievalue</lastcookiename>
  </cookies>
</request>

25.7 FOPシリアライザを使用したPDF出力の生成

XSQLページ・フレームワークによるカスタム・シリアライザのサポートを使用すると、oracle.xml.xsql.serializers.XSQLFOPSerializerクラスでApache Formatting Objects Processor (FOP).と統合できます。FOPプロセッサは、XSL Formatting Objectsを含むXML文書からPDFドキュメントをレンダリングします。

表24-1に示すように、デモ・ディレクトリにはemptablefo.xslスタイルシートとemptable.xsqlページが存在します。FOPシリアライザを使用する際にエラーが発生した場合、必要なすべてのJARファイルがCLASSPATHに指定されていないことが原因と考えられます。XSQLFOPSerializerクラスは別のxml.jarファイルに存在しますが、FOPの統合を使用するには、CLASSPATH内に指定する必要があります。また、CLASSPATHに次のJavaアーカイブを追加する必要があります。

  • fop.jar - Apacheバージョン0.20.3以降のJavaアーカイブ

  • batik.jar - FOP配布パッケージに含まれるJavaアーカイブ

  • avalon-framework-4.0.jar - FOP配布パッケージに含まれるJavaアーカイブ

  • logkit-1.0.jar - FOP配布パッケージに含まれるJavaアーカイブ

実装をカスタマイズする際の参考として、このリリースに提供されているFOPシリアライザのソース・コードを例25-18に示します。

関連項目:

Apache FOP

例25-18 FOPシリアライザのソース・コード

package oracle.xml.xsql.serializers;
import org.w3c.dom.Document;
import org.apache.log.Logger;
import org.apache.log.Hierarchy;
import org.apache.fop.messaging.MessageHandler;
import org.apache.log.LogTarget;
import oracle.xml.xsql.XSQLPageRequest;
import oracle.xml.xsql.XSQLDocumentSerializer;
import org.apache.fop.apps.Driver;
import org.apache.log.output.NullOutputLogTarget;
/**
 * Tested with the FOP 0.20.3RC release from 19-Jan-2002
 */
public class XSQLFOPSerializer implements XSQLDocumentSerializer {
  private static final String PDFMIME = "application/pdf";
  public void serialize(Document doc, XSQLPageRequest env) throws Throwable {
    try { 
      // First make sure we can load the driver
      Driver FOPDriver = new Driver();
      // Tell FOP not to spit out any messages by default.
      // You can modify this code to create your own FOP Serializer
      // that logs the output to one of many different logger targets
      // using the Apache LogKit API
      Logger logger=Hierarchy.getDefaultHierarchy().getLoggerFor("XSQLServlet");
      logger.setLogTargets(new LogTarget[]{new NullOutputLogTarget()});
      FOPDriver.setLogger(logger);
      // Some of FOP's messages appear to still use MessageHandler.
      MessageHandler.setOutputMethod(MessageHandler.NONE);
      // Then set the content type before getting the reader
      env.setContentType(PDFMIME);
      FOPDriver.setOutputStream(env.getOutputStream());
      FOPDriver.setRenderer(FOPDriver.RENDER_PDF); FOPDriver.render(doc);
    }
    catch (Exception e) {
      // Cannot write PDF output for the error anyway.
      // So maybe this stack trace will be useful info
      e.printStackTrace(System.err);
    }
  }
}

25.8 XSQLのカスタマイズの実行

XSQLのカスタマイズに関するトピックを示します。

25.8.1 カスタムXSQLアクション・ハンドラの作成

XSQLページ・エンジンでは、xsql名前空間からアクション・ハンドラ要素を検索し、適切なアクション・ハンドラ要素ハンドラ・クラスをコールして各アクションを処理することにより、XSQLページが処理されます。XSQLActionHandlerインタフェースを実装するすべてのアクションがサポートされています。すべての組込みアクションは、このインタフェースを実装します。

タスクの実行にカスタム処理が必要であり、そのニーズに合う組込みアクションが表33-2にない場合は、独自のアクションを作成できます。

XSQLエンジンは、ページ内のアクションを次の方法で処理します。ページ内のアクションごとに、次のステップを実行します。

  1. デフォルトのコンストラクタを使用して、アクション・ハンドラ・クラスのインスタンスを作成します。
  2. メソッドinit(Element actionElt,XSQLPageRequest context)をコールして、アクション・ハンドラ要素オブジェクトおよびXSQL Page Processorコンテキストを含むハンドラ・インスタンスを初期化します。
  3. メソッドhandleAction (Node result)を起動して、ハンドラがアクションを処理できるようにします。

組込みアクションの場合、XSQLエンジンは、そのアクション・ハンドラを実装するJavaクラスへのXSQLアクション・ハンドラ要素名をマップできます。表33-2に、組込みアクションとそのアクションに対応するクラスを示しています。

ユーザー定義のアクションの場合は、次の組込みアクションを使用します。fully.qualified.Classnameの部分は使用するクラス名に置き換えてください。

<xsql:action handler="fully.qualified.Classname" ... />

handler属性は、そのカスタム・アクション・ハンドラを実装するJavaクラスの完全修飾名を指定します。

25.8.1.1 XSQLActionHandlerインタフェースの実装

カスタム・アクション・ハンドラを作成するには、oracle.xml.xsql.XSQLActionHandlerインタフェースを実装するクラスを作成します。ほぼすべてのカスタム・アクション・ハンドラは、init()メソッドのデフォルト実装および有用なヘルパー・メソッドを提供するoracle.xml.xsql.XSQLActionHandlerImplを拡張します。

XSQLページ・プロセッサがアクション・ハンドラのhandleAction()メソッドをコールすると、DOMフラグメントがアクション実装に渡されます。アクション・ハンドラは、ページに戻された、動的に作成されたXMLコンテンツをルート・ノードに追加します。

XSQLプロセッサによって、XSQLページ内のアクション要素は、概念的にこのドキュメント・フラグメントのコンテンツに置き換えられます。ページに追加するXMLコンテンツがない場合、アクション・ハンドラはこのフラグメントに何も追加しません。

カスタム・アクション・ハンドラを作成する場合、XSQLActionHandlerImplクラスのいくつかのメソッドが役に立ちます。表25-2に、これらのメソッドを示します。

表25-2 XSQLActionHandlerImplクラスの有用なメソッド

メソッド名 説明
getActionElement

処理中の現行のアクション・ハンドラ要素を戻します。

getActionElementContent

すべての字句パラメータを適切に置き換えて、現行のアクション・ハンドラ要素のテキスト・コンテンツを戻します。

getPageRequest

現行のXSQLページ・プロセッサのコンテキストを戻します。このオブジェクトを使用して、次のことを行います。

  • setPageParam()

    ページ・パラメータ値を設定します。

  • getPostedDocument()/setPostedDocument()

    ポストされたXML文書を取得または設定します。

  • translateURL()

    相対URLを絶対URLに変換します。

  • getRequestObject()/setRequestObject()

    単一のページのアクション間で共有できるページ・リクエスト・コンテキスト内のオブジェクトを取得または設定します。

  • getJDBCConnection()

    このページが使用中のJDBC接続(使用中の接続がない場合はnull)を取得します。

  • getRequestType()

    Servlet、Command LineまたはProgrammaticのいずれのコンテキストで実行中かを検出します。たとえば、リクエストのタイプがServletの場合は、XSQLPageRequestオブジェクトをより固有のXSQLServletPageRequestにキャストし、getHttpServletRequestgetHttpServletResponsegetServletContextなどのサーブレット固有のメソッドにアクセスできます。

getAttributeAllowingParam

属性値で使用されているすべてのXSQL字句パラメータ参照を解決し、要素から属性値を取得します。通常、このメソッドはアクション・ハンドラ要素自体に適用されますが、サブ要素の属性にアクセスすることも有効です。字句パラメータを許可せずに属性値にアクセスするには、DOMのElementインタフェースに対して標準のgetAttribute()メソッドを使用します。

appendSecondaryDocument

外部XML文書のコンテンツをアクション・ハンドラの結果コンテンツのルートに追加します。

addResultElement

テキスト・コンテンツを含む単一の要素をアクション・ハンドラの結果コンテンツのルートに追加する操作を簡単にします。

firstColumnOfFirstRow

SQL文の最初の行にある最初の列値を戻します。現行のページのドキュメント要素に接続属性が含まれている必要があります。含まれていない場合は、エラーが戻されます。

getBindVariableCount

空白で区切られたbind-paramsのリスト内にあるトークンの数を戻します。この値は、パラメータにバインドされるバインド変数の数を示します。

handleBindVariables

現行のアクション・ハンドラ要素のbind-params属性で指定されるパラメータ値を使用して、プリコンパイルされたSQL文で使用されるJDBCバインド変数のバインディングを管理します。このメソッドを起動する前にSQL文がすでに複数のバインド変数を使用している場合は、使用中である既存のバインド変数スロットの数も渡すことができます。

reportErrorIncludingStatement

エラーを報告します。エラーには問題の原因である違反(SQL)文が含まれます。オプションで、エラーに数値エラー・コードが含まれる場合もあります。

reportFatalError

致命的エラーを報告します。

reportMissingAttribute

<xsql-error>要素を使用して、必須のアクション・ハンドラ属性が欠落していることを示すエラーを報告します。

reportStatus

<xsql-status>要素を使用して、アクション・ハンドラの状態を報告します。

requiredConnectionProvided

このリクエストに使用できる接続の有無を確認し、使用可能な接続がない場合はページにエラーグラムを出力します。

variableValue

字句パラメータのデフォルト値を決定する場合があるすべての有効範囲決定規則を考慮して、字句パラメータの値を戻します。

例25-19に、組込みアクション・ハンドラを使用するカスタム・アクション・ハンドラMyIncludeXSQLHandlerを示します。これは、任意のJavaコードを使用し、そのハンドラによって戻されたXMLフラグメントを変更してから、その結果をXSQLページに追加します。

ページがXSQLサーブレット、XSQLコマンドライン・ユーティリティまたはプログラムでXSQLRequestクラスを介してリクエストされているかどうかに基づいて、異なる動作をするカスタム・アクション・ハンドラを作成する場合、アクション・ハンドラの実装で、getPageRequest()を起動して、現行のページ・リクエスト用の XSQLPageRequestインタフェースを参照できます。XSQLPageRequestオブジェクトに対してgetRequestType()を起動すると、サーブレット、コマンドラインまたはプログラムのいずれからリクエストを受信しているかを確認できます。戻り値がServletの場合、例25-20の構文によって、HTTPサーブレットのリクエスト、レスポンスおよびサーブレット・コンテキスト・オブジェクトにアクセスできます。

例25-19 MyIncludeXSQLHandler.java

import oracle.xml.xsql.*;
import oracle.xml.xsql.actions.XSQLIncludeXSQLHandler;
import org.w3c.dom.*;
import java.sql.SQLException;
public class MyIncludeXSQLHandler extends XSQLActionHandlerImpl {
  XSQLActionHandler nestedHandler = null;
  public void init(XSQLPageRequest req, Element action) {
    super.init(req, action);
    // Create an instance of an XSQLIncludeXSQLHandler and init() the handler by 
    // passing the current request/action. This assumes the XSQLIncludeXSQLHandler 
    // will pick up its href="xxx.xsql" attribute from the current action element.
    nestedHandler = new XSQLIncludeXSQLHandler();
    nestedHandler.init(req,action);
  }
  public void handleAction(Node result) throws SQLException {
    DocumentFragment df=result.getOwnerDocument().createDocumentFragment();
    nestedHandler.handleAction(df);
    // Custom Java code here can work on the returned document fragment
    // before appending the final, modified document to the result node.
    // For example, add an attribute to the first child.
    Element e = (Element)df.getFirstChild();
    if (e != null) {
      e.setAttribute("ExtraAttribute","SomeValue");
    }
    result.appendChild(df);
  }
}

例25-20 サーブレット・リクエストのテスト

XSQLServletPageRequest xspr = (XSQLServletPageRequest)getPageRequest();
if (xspr.getRequestType().equals("Servlet")) {
  HttpServletRequest     req  = xspr.getHttpServletRequest();
  HttpServletResponse   resp  = xspr.getHttpServletResponse();
  ServletContext        cont  = xspr.getServletContext();
  // Do something here with req, resp, or cont. Note that writing to the response 
  // directly from a handler produces unexpected results. All the servlet or your 
  // custom Serializer to write to the servlet response output stream at the right 
  // moment later when all action elements have been processed.
}
25.8.1.2 カスタムXSQLアクション内での複数値パラメータの使用

XSQLActionHandlerImplはカスタムXSQLアクションのベース・クラスです。

次のものがサポートされます。

  • 配列名を使用した字句パラメータ置換

  • 配列名を使用したバインド変数

  • 単一値のパラメータ

カスタム・アクションでこの基本クラスからのメソッド、たとえばgetAttributeAllowingParam()getActionElementContent()またはhandleBindVariables()などを使用する場合は、カスタム・アクションで複数値のパラメータの機能を使用できます。

パラメータ値をString[]として明示的に取得するには、XSQLPageRequestインタフェースでgetParameterValues()メソッドを使用します。XSQLActionHandlerImplのヘルパー・メソッドvariableValues()を使用すると、プログラムで必要な場合にカスタム・アクション・ハンドラ内からこの機能を使用できます。

25.8.2 カスタムXSQLシリアライザの実装

ユーザー定義のシリアライザ・クラスを実装し、最終XSQLデータページをテキストまたはバイナリ・ストリームにシリアライズする方法を制御できます。ユーザー定義のシリアライザには、インタフェースoracle.xml.xsql.XSQLDocumentSerializerを実装する必要があります。

インタフェースoracle.xml.xsql.XSQLDocumentSerializerには次の単一メソッドが含まれています。

void serialize(org.w3c.dom.Document doc, XSQLPageRequest env) throws Throwable;

DOMベースのシリアライザのみがサポートされます。カスタム・シリアライザ・クラスでは、次のステップを実行する必要があります。

  1. 出力PrintWriter(またはOutputStream)に内容を出力する前に、シリアライズされたストリームのコンテンツ・タイプを設定します。

    シリアライザに渡されたXSQLPageRequestに対してsetContentType()を起動し、型を設定します。コンテンツ・タイプを設定する場合は、次のようにMIMEタイプを設定できます。

    env.setContentType("text/html");
    

    または、次のように明示的に出力エンコーディング・キャラクタ・セットを指定してMIMEタイプを設定することもできます。

    env.setContentType("text/html;charset=Shift_JIS");
    
  2. XSQLPageRequestに対してgetWriter()またはgetOutputStream()のどちらかを起動し(両方は不可)、それぞれ適切なPrintWriterまたはOutputStreamを取得して、コンテンツのシリアライズに使用します。

例25-21のカスタム・シリアライザは、現行のXSQLデータ・ページのドキュメント要素名を含むHTML文書をシリアライズする単純な実装を示します。

例25-21 カスタム・シリアライザ

package oracle.xml.xsql.serializers;
import org.w3c.dom.Document;
import java.io.PrintWriter;
import oracle.xml.xsql.*;

public class XSQLSampleSerializer implements XSQLDocumentSerializer {
  public void serialize(Document doc, XSQLPageRequest env) throws Throwable {
    String encoding = env.getPageEncoding();  // Use same encoding as XSQL page
                                              // template. Set to specific
                                              // encoding if necessary
    String mimeType = "text/html"; // Set this to the appropriate content type
    // (1) Set content type using the setContentType on the XSQLPageRequest
    if (encoding != null && !encoding.equals("")) {
      env.setContentType(mimeType+";charset="+encoding);
    }
    else {
      env.setContentType(mimeType);
    }
    // (2) Get the output writer from the XSQLPageRequest
    PrintWriter e = env.getWriter();
    // (3) Serialize the document to the writer
    e.println("<html>Document element is <b>"+
              doc.getDocumentElement().getNodeName()+"</b></html>");
  }
}
25.8.2.1 カスタム・シリアライザの使用方法

カスタム・シリアライザを使用するには、シリアライズの前にXSLT変換を実行する必要があるかどうかによって、2つの方法があります。

カスタム・シリアライザを使用する前にXSLT変換を実行するには、ページの最上部にある<?xml-stylesheet?>処理命令内にserializer="java:fully.qualified.ClassName"を追加します。次の例に、この方法を示します。

<?xml version="1.0?>
<?xml-stylesheet type="text/xsl" href="mystyle.xsl"
                 serializer="java:my.pkg.MySerializer"?>

カスタム・シリアライザのみが必要である場合は、type属性およびhref属性を省略します。次の例に、この方法を示します。

<?xml version="1.0?>
<?xml-stylesheet serializer="java:my.pkg.MySerializer"?>
25.8.2.2 カスタム・シリアライザへの短縮名の割当て

また、XSQL構成ファイルの<serializerdefs>セクションでカスタム・シリアライザに短縮名を割り当てることもできます。これにより、serializer属性でその短縮名を使用して、入力作業を省くことができます。短縮名では大文字と小文字が区別されます。

XSQL構成ファイルに例25-22に示す情報が指定されているとします。スタイルシートの命令に短縮名"Sample"または"FOP"を使用できます。

<?xml-stylesheet type="text/xsl" href="emp-to-xslfo.xsl" serializer="FOP"?>
<?xml-stylesheet serializer="Sample"?>

XSQLPageRequestインタフェースは、getWriter()メソッドとgetOutputStream()メソッドの両方をサポートします。カスタム・シリアライザは、getOutputStream()を起動して、OutputStreamインスタンスを戻します。バイナリ・データは、このインスタンスにシリアライズできます。XSQLサーブレットを使用する場合は、この出力ストリームに出力すると、バイナリ情報がサーブレットの出力ストリームに出力されます。

例25-23のシリアライザは、動的GIFイメージを出力する例を示します。この例では、GIFイメージは静的な「OK」アイコンですが、より高度なイメージ・シリアライザで使用する必要がある基本的な方法を示します。

XSQLコマンドライン・ユーティリティを使用する場合は、バイナリ情報がターゲット出力ファイルに出力されます。XSQLRequest APIを使用する場合は、2つのコンストラクタが存在します。これらのコンストラクタは、コール元がページ処理の結果用に使用するターゲットOutputStreamを提供できるようにします。

シリアライザは、getWriter() (テキスト出力用)またはgetOutputStream() (バイナリ出力用)のどちらかを起動する必要があります。ただし、これらの両方を起動することはできません。同一のリクエストで両方を起動すると、エラーが発生します。

例25-22 カスタム・シリアライザへの短縮名の割当て

<XSQLConfig>
  <!--and so on. -->
  <serializerdefs>
    <serializer>
      <name>Sample</name>
      <class>oracle.xml.xsql.serializers.XSQLSampleSerializer</class>
    </serializer>
    <serializer>
      <name>FOP</name>
      <class>oracle.xml.xsql.serializers.XSQLFOPSerializer</class>
    </serializer>
  </serializerdefs>
</XSQLConfig>

例25-23 動的GIFイメージの出力

package oracle.xml.xsql.serializers;
import org.w3c.dom.Document;
import java.io.*;
import oracle.xml.xsql.*;

public class XSQLSampleImageSerializer implements XSQLDocumentSerializer {
   // Byte array representing a small "ok" GIF image
   private static byte[] okGif =
     {(byte)0x47,(byte)0x49,(byte)0x46,(byte)0x38,
      (byte)0x39,(byte)0x61,(byte)0xB,(byte)0x0,
      (byte)0x9,(byte)0x0,(byte)0xFFFFFF80,(byte)0x0,
      (byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
      (byte)0xFFFFFFFF,(byte)0xFFFFFFFF,(byte)0xFFFFFFFF,(byte)0x2C,
      (byte)0x0,(byte)0x0,(byte)0x0,(byte)0x0,
      (byte)0xB,(byte)0x0,(byte)0x9,(byte)0x0,
      (byte)0x0,(byte)0x2,(byte)0x14,(byte)0xFFFFFF8C,
      (byte)0xF,(byte)0xFFFFFFA7,(byte)0xFFFFFFB8,(byte)0xFFFFFF9B,
      (byte)0xA,(byte)0xFFFFFFA2,(byte)0x79,(byte)0xFFFFFFE9,
      (byte)0xFFFFFF85,(byte)0x7A,(byte)0x27,(byte)0xFFFFFF93,
      (byte)0x5A,(byte)0xFFFFFFE3,(byte)0xFFFFFFEC,(byte)0x75,
      (byte)0x11,(byte)0xFFFFFF85,(byte)0x14,(byte)0x0,
      (byte)0x3B};

  public void serialize(Document doc, XSQLPageRequest env) throws Throwable {
    env.setContentType("image/gif");
    OutputStream os = env.getOutputStream();
    os.write(okGif,0,okGif.length);
    os.flush();
  }
}

25.8.3 JDBCデータソースに対するカスタムXSQL Connection Managerの使用

XSQL構成ファイル内に自分が使用する接続を名前を付けて定義するという方法の他に、提供されている2つのXSQLConnectionManager実装のいずれかを使用するという方法があります。これにより、サーブレット・コンテナのJDBCデータソース実装および関連する接続プーリング機能を使用できます。

XSQLページ・フレームワークには、代替として使用できる次のConnection Manager実装が付属しています。

  • oracle.xml.xsql.XSQLDatasourceConnectionManager

    サーブレット・コンテナのデータソース実装がOracle JDBCドライバを使用しない場合は、この接続マネージャを使用することを検討してください。Oracle JDBCドライバを使用していないと、<xsql:ref-cursor-function><xsql:include-owa>などのXSQLページ・システムの一部の機能が使用できなくなります。

  • oracle.xml.xsql.XSQLOracleDatasourceConnectionManager

    データソース実装が、それぞれoracle.jdbc.PreparedStatementインタフェースおよびoracle.jdbc.CallableStatementインタフェースを実装するJDBCのPreparedStatementオブジェクトおよびCallableStatementオブジェクトを戻す場合は、このConnection Managerを使用することをお薦めします。Oracle WebLogic Serverには、このタスクを実行するデータソース実装が含まれています。

前述の代替Connection Manager実装のいずれかを使用するとき、XSQLページ・テンプレート内の接続属性の値は、必要なデータソースの検索に使用するJava Naming and Directory Interface (JNDI)名です。接続属性の値の例を次に示します。

  • jdbc/scottDS

  • java:comp/env/jdbc/MyDatasource

デフォルトのXSQLページConnection Managerを使用しない場合は、代替のConnection Manager実装を使用して必要な接続プーリング機能を提供する必要があります。JDBCデータソースに基づく前述の2つのオプションでは、サーブレット・コンテナを適切に構成し、接続プーリングを提供する必要があります。プールされた接続を提供するためにデータソースを適切に構成する方法については、使用しているサーブレット・コンテナのドキュメントを参照してください。

25.8.4 カスタムXSQL Connection Managerの作成

カスタムConnection Managerを作成し、組込みConnection Managementメカニズムを置き換えることができます。

カスタムConnection Managerの実装を提供するには、次のステップを実行する必要があります。

  1. oracle.xml.xsql.XSQLConnectionManagerFactoryインタフェースを実装するConnection Managerファクトリ・クラスを作成します。

  2. oracle.xml.xsql.XSQLConnectionManagerインタフェースを実装するConnection Managerクラスを作成します。

  3. XSQL構成ファイル内のXSQLConnectionManagerFactoryクラスの名前を変更します。

XSQLサーブレットでは、XSQLページのデフォルト・スキームではなく、定義した接続管理スキームが使用されます。

XSQL構成ファイルにクラス名を指定すると、カスタムConnection ManagerファクトリをデフォルトのConnection Managerファクトリとして使用するように設定できます。次のセクションでファクトリを設定します。

<!--
 | Set the name of the XSQL Connection Manager Factory
 | implementation. The class must implement the
 | oracle.xml.xsql.XSQLConnectionManagerFactory interface.
 | If unset, the default is to use the built-in connection
 | manager implementation in 
 | oracle.xml.xsql.XSQLConnectionManagerFactoryImpl
+-->
  <connection-manager>
      <factory>oracle.xml.xsql.XSQLConnectionManagerFactoryImpl</factory>
  </connection-manager>

デフォルトのConnection Managerファクトリを指定する他に、指定されたAPIを使用して、カスタム接続ファクトリをXSQLRequestオブジェクトに関連付けることもできます。

XSQLConnectionManagerFactoryは、現行のリクエストが使用するXSQLConnectionManagerのインスタンスを戻します。サーブレット・エンジンなどのマルチスレッド環境では、XSQLConnectionManagerオブジェクトが、2つの異なるスレッドによって単一のXSQLConnectionインスタンスが使用されていないことを保証する必要があります。そのために、getConnection()メソッドの起動からreleaseConnection()メソッドの起動までの間、接続は使用中としてマークされます。デフォルトのXSQL Connection Manager実装は、名前付き接続を自動的にプールし、このスレッド・セーフ・ポリシーに従います。

XSQLConnectionManagerのカスタム実装で、オプションのoracle.xml.xsql.XSQLConnectionManagerCleanupインタフェースも実装する場合は、Connection Managerで、割当て済のリソースをクリーンアップできます。たとえば、サーブレット・コンテナがXSQLServletサーブレットに対してdestroy()メソッドを起動すると(サーブレットのオンライン管理中などに発生)、Connection Managerはサーブレットの破棄プロセスの一部として、リソースをクリーンアップできます。

25.8.4.1 カスタムConnection Managerの認証情報にアクセスする方法

HTTP認証メカニズムを使用して、データベースに接続するためのユーザー名およびパスワードを取得するには、カスタマイズしたConnection Managerを作成します。これにより、getConnection()メソッドを起動して必要な情報を取得できます。

Javaプログラムを作成するには、次のステップを実行します。

  1. oracle.xml.xsql.XSQLPageRequestインタフェースのインスタンスをgetConnection()メソッドに渡します。
  2. getRequestType()を起動して、リクエストのタイプがServletであることを確認します。
  3. XSQLPageRequestオブジェクトをXSQLServletPageRequestにキャストします。
  4. 前述のステップの結果に対してgetHttpServletRequest()を起動します。
  5. 前述の起動で戻されたjavax.servlet.http.HttpServletResponseオブジェクトから認証情報を取得します。

25.8.5 カスタムXSQLErrorHandlerの実装

インタフェースoracle.xml.xsql.XSQLErrorHandlerを実装することにより、使用不能な接続などの重大なページ・プロセッサ・エラーの報告方法を制御できます。

このインタフェースには次の単一のメソッド・シグネチャが含まれています。

public interface XSQLErrorHandler {
  public void handleError( XSQLError err, XSQLPageRequest env);
}

XSQLErrorHandlerインタフェースを実装するクラスを提供すると、XSQLページ・プロセッサによるエラー・メッセージの出力方法をカスタマイズできます。新しいXSQLErrorオブジェクトはエラー情報をカプセル化し、エラー・コード、フォーマットされたエラー・メッセージなどへのアクセスを提供します。

例25-24では、XSQLErrorHandlerの実装の例を示します。

使用するカスタムXSQLErrorHandler実装を、次の方法で制御できます。

  • カスタムXSQLErrorHandler実装クラスの名前をXSQL構成ファイルに定義します。エラー・ハンドラ・クラスの完全修飾クラス名を/XSQLConfig/processor/error-handler/classエントリの値として指定する必要があります。

    XSQLページ・プロセッサがこのクラスをロードし、XSQLErrorHandlerインタフェースを正しく実装すると、このクラスはシングルトンとして使用され、ページ・プロセッサのエラーが通知された場合にデフォルトの実装をグローバルに置換します。

  • ページのドキュメント要素に対してerrorHandler(またはxsql:errorHandler)属性を使用して、ページごとにエラー・ライターをオーバーライドします。この属性の値は、XSQLErrorHandlerインタフェースを実装するクラスの完全修飾クラス名です。このクラスは現行のページで発生したエラーのみを通知します。このクラスは、Page Engineによってページ・リクエストごとにインスタンス化されます。

前述の方法は、必要に応じて組み合せて使用できます。

例25-24 myErrorHandlerクラス

package example;
import oracle.xml.xsql.*;
import java.io.*;
public class myErrorHandler implements XSQLErrorHandler {
  public void logError( XSQLError err, XSQLPageRequest env) {
    // Must set the content type before writing anything out
    env.setContentType("text/html");
    PrintWriter pw = env.getErrorWriter();
    pw.println("<H1>ERROR</H1><hr>"+err.getMessage());    
  }
}

25.8.6 カスタムXSQLログ出力実装の提供

各XSQLページ・リクエストの開始と終了のロギングを処理するカスタム・コードをオプションで登録できます。カスタム・ログ出力コードでは、インタフェースoracle.xml.xsql.XSQLLoggerFactoryおよびoracle.xml.xsql.XSQLLoggerの実装を提供する必要があります。

XSQLLoggerFactoryインタフェースには次の単一メソッドが含まれています。

public interface XSQLLoggerFactory {
  public XSQLLogger create( XSQLPageRequest env);
}

XSQLLoggerFactoryインタフェースを実装するクラスを提供し、ロギング用にXSQLLoggerオブジェクトを作成(または再利用)する方法を決定できます。XSQLプロセッサは、ページ・リクエストの存続期間中ファクトリによって戻されるXSQLLoggerオブジェクトへの参照を保持します。プロセッサはこの参照を使用して、logRequestStart()メソッドおよびlogRequestEnd()メソッドを起動することで、各ページ・リクエストの開始と終了をログに記録します。

XSQLLoggerインタフェースは次のとおりです。

public interface XSQLLogger {
   public void logRequestStart(XSQLPageRequest env) ;
   public void logRequestEnd(XSQLPageRequest env);
}

例25-25および例25-26のクラスは、カスタム・ログ出力の一般的な実装を示します。例25-25XSQLLogger実装では、ページ・リクエストの開始時刻を記録します。また、ページ・リクエストの名前と経過時間をSystem.outに出力して、ページ・リクエストの終了時刻を記録します。

例25-26に、ファクトリの実装を示します。

カスタム・ログ出力ファクトリを登録するには、XSQLConfig.xmlファイルを編集し、カスタム・ログ出力ファクトリ・クラスの名前を/XSQLConfig/processor/logger/factory要素のコンテンツとして指定します。例25-27に、この方法を示します。

デフォルトでは、<logger>セクションはコメント・アウトされています。デフォルトのログ出力はありません。

例25-25 SampleCustomLoggerクラス

package example;
import oracle.xml.xsql.*;
public class SampleCustomLogger implements XSQLLogger  {
  long start = 0;
  public void logRequestStart(XSQLPageRequest env) {
    start = System.currentTimeMillis();
  }
  public void logRequestEnd(XSQLPageRequest env) {
    long secs = System.currentTimeMillis() - start;
    System.out.println("Request for " + env.getSourceDocumentURI()
                        + " took "+ secs + "ms");
  }
}

例25-26 SampleCustomLoggerFactoryクラス

package example;
import oracle.xml.xsql.*;
public class SampleCustomLoggerFactory implements XSQLLoggerFactory {
  public XSQLLogger create(XSQLPageRequest env) {
    return new SampleCustomLogger();
  }
}

例25-27 カスタム・ログ出力ファクトリの登録

<XSQLConfig>
    :
  <processor>
         :
      <logger>
         <factory>example.SampleCustomLoggerFactory</factory>
      </logger>
         :
   </processor>
</XSQLConfig>