この章では、XSQLページに関する次の高度なトピックについて説明します。
デフォルトでは、XSQLページ・フレームワークの構成ファイルの名前はXSQLConfig.xmlです。開発用、テスト用、本番用というように、使用する環境に応じてXSQL構成ファイルのバージョンを簡単に切り替えられることができます。XSQL Page Processorで読み取る構成ファイルの名前をオーバーライドするには、Javaシステム・プロパティxsql.configを設定します。
サーブレット初期化パラメータxsql.configを定義することで、-Dxsql.config=MyConfigFile.xmlなどの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からのリソースとして読み取ろうとします。したがって、J2EE形式のサーブレット環境では、MyConfigFile.xmlを.\WEB-INF\classesディレクトリ(またはCLASSPATHで検出される最上位ディレクトリ)に格納する必要があります。サーブレット初期化パラメータとSystemパラメータの両方が指定されている場合は、サーブレット初期化パラメータの値が使用されます。 |
この項の内容は次のとおりです。
リクエスト中の現行のXSQLページが許可する場合、リクエストでXSLTスタイルシートのURLを指定できます。この方法で、デフォルトのスタイルシートをオーバーライドしたり、デフォルトでスタイルシートが適用されない場合にスタイルシートを適用できます。クライアントが起動するスタイルシートURLは、xml-stylesheetパラメータをリクエストの一部として指定することによって、指定されます。このパラメータの有効値は次のとおりです。
処理中のXSQLページに対して相対的に解析されるすべての相対URL
HTTPプロトコル・スキームを使用し、XSQL構成ファイルの定義に従ってトラステッド・ホストを参照するすべての絶対URL
リテラル値none。xml-stylesheet=noneの設定は、開発中、XSLTスタイルシートの処理を一時的に短絡させてスタイルシートが実際に参照しているXMLデータグラムを確認する場合に有用です。この方法は、スタイルシートで期待した結果が生成されない場合の理由確認に使用できます。
クライアントによるXSQLページ用スタイルシートのオーバーライドは、次の方法で行います。
XSQL構成ファイルでallow-client-style構成パラメータをnoに設定します。
XSQLページのドキュメント要素に対して、allow-client-style="no"属性を明示的に挿入します。
XSQL構成ファイルでクライアントによるスタイルシートのオーバーライドがデフォルトでグローバルに使用禁止にされている場合でも、すべてのページで、そのページのドキュメント要素に対してallow-client-style="yes"属性を挿入することによって、クライアントによるオーバーライドを明示的に使用可能にできます。
提供するデータのコンテンツ・タイプを設定することにより、リクエスト側クライアントは、戻されたデータを正しく解析できます。スタイルシートで<xsl:output>要素を使用する場合、XSQL Page Processorは、<xsl:output>のmedia-type属性およびencoding属性から、戻されたドキュメントのメディア・タイプおよびエンコーディングを推測します。
例15-1のスタイルシートでは、<xsl:output>に対してmedia-type="application/vnd.ms-excel"属性を使用します。この命令により、hr.employees表に対する標準の問合せを含むXSQLページの結果をMicrosoft Excel形式に変換します。
例15-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>
次のXSQLページでは、例15-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>
<?xml-stylesheet?>処理命令を.xsqlファイルの最上部に挿入すると、XSQL Page Processorは結果として生成されるXMLデータグラムの変換にそれを使用することを検討します。例15-2のemp_test.xsqlページについて考えてみます。
例15-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>
例15-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問合せに基づいてパラメータの値を設定することもできます。たとえば、例15-3のXSQLページでは、ページのプライベート・パラメータの値を割り当てることによって、使用するスタイルシートの名前を表から選択します。
例15-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>
一部のブラウザは、クライアントでの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データグラムが提供されます。
複数の<?xml-stylesheet?>処理命令をXSQLページの最上部に挿入できます。この命令にはオプションのmedia擬似属性を指定できます。media擬似属性に値を指定すると、その値は大/小文字を区別してHTTPヘッダーのユーザー・エージェント文字列の値と比較されます。media擬似属性の値がユーザー・エージェント文字列の一部と一致した場合、プロセッサは現行の<?xml-stylesheet?>処理命令を選択して使用します。一致しなかった場合は、その処理命令を無視して、検索を続けます。ドキュメント内の順序で最初に一致した処理命令が使用されます。media擬似属性がない処理命令は、すべてのユーザー・エージェントと一致します。
例15-4に、XSQLファイルの最上部に複数の処理命令がある場合を示します。処理には、Lynxブラウザの場合はdoyouxml-lynx.xslを、Internet Explorer 5.0または5.5ブラウザの場合はdoyouxml-ie.xslを、および他のすべてのブラウザの場合はdoyouxml.xslを使用します。
例15-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">
表15-1に、<?xml-stylesheet?>処理命令に対して使用可能な、サポートされる擬似属性の概要を示します。
表15-1 <?xml-stylesheet?>の擬似属性
| 属性名 | 説明 |
|---|---|
type = "string" |
対応付けられたスタイルシートのMIMEタイプを指定します。XSLTスタイルシートの場合、この属性は文字列
|
href = "URL" |
使用するXSLTスタイルシートへの相対URLまたは絶対URLを指定します。 |
media = "string" |
リクエスト側デバイスが送信したHTTPヘッダーの |
client = "boolean" |
|
serializer = "string" |
デフォルトでは、XSQL Page Processorは次のシリアライザを使用します。
この擬似属性を指定すると、前述のコードのかわりにカスタム・シリアライザの実装を使用する必要があります。 有効値は、XSQL構成ファイルの |
この項の内容は次のとおりです。
リクエスト・パラメータ、セッション・パラメータおよびページのプライベート・パラメータで、値に文字列の配列を使用できます。パラメータの値を配列として処理するには、パラメータの名前の最後に一対の空の大カッコを追加します。たとえば、productidという名前の入力コントロールが4回出現するHTMLフォームをポストする場合、配列値であるproductidパラメータを参照するにはproductid[]という表記を使用します。配列値パラメータを、配列を示すカッコを付けずに参照すると、最初の配列エントリの値が値として使用されます。
|
注意: 配列を示すカッコ内での数値の使用はサポートされていません。つまり、productidまたはproductid[]を参照することはできますが、productid[2]は参照できません。 |
アクション・ハンドラ属性値内またはアクション・ハンドラ要素のコンテンツ内のいずれかで、配列値パラメータを字句置換パラメータとして参照するとします。値は配列内での出現順序に従って、配列内でNULL以外の文字列および空以外の文字列のカンマ区切りのリストに変換されます。例15-5に、配列値パラメータを使用したXSQLページを示します。
例15-5 XSQLページでの配列値パラメータの使用
<page xmlns:xsql="urn:oracle-xsql">
<xsql:query>
SELECT description
FROM product
WHERE productid in ( {@productid[]} ) /* Using lexical parameter */
</xsql:query>
</page>
XSQLコマンドライン・ユーティリティを起動して、次の方法でPage.xsqlのproductidパラメータに複数の値を指定できます。
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式を使用してデータページからの値を参照します。 |
次のように、配列を示すカッコを名前に使用することで、ページのプライベート・パラメータまたはセッション・パラメータの値を文字列配列値に設定できます。
<!-- 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"/>
デフォルトでは、パラメータの名前に配列を示すカッコが追加されていると、値は空白またはカンマ区切りのリストとして処理され、トークン化されます。
結果として得られる文字列配列値には、これらの区切られたトークンが含まれています。前述の例では、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"/>
文字列値のスカラー型バインド変数がサポートされている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文字列の次元は必要に応じて変更できます。その場合は、配列値文字列のパラメータを扱う文字列値と同じ長さにする必要があります。
例15-6のPL/SQLファンクションについて考えてみます。
例15-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;
例15-7のXSQLページに、testTableFunctionを使用するSQL文内で、2つの配列値パラメータをバインドする方法を示します。
例15-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>
例15-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型を作成せずに例15-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>
|
配列パラメータはネストされた表のコレクション型としてバインドされるため、SQL文内でTABLE()演算子とCAST()演算子を組み合せて使用し、ネストされた表のバインド変数値を値の表として扱うことができます。この表に問合せを行えます。この方法は、副問合せに特に有効です。例15-8のページは、従業員IDを含む配列値パラメータを使用して、行の問合せ先をhr.employeesに制限した例です。
例15-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>
例15-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>
例15-7および例15-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内で値の配列を使用するというプログラム上の柔軟性が保たれます。
アクションの実行中に、致命的ではないエラーが発生したかどうかが判別されます。たとえば、行の挿入またはストアド・プロシージャのコールがデータベース例外で失敗することがあります。これは、<xsql-error>要素としてXSQLデータページに挿入することができます。
組込みXSQLアクションで致命的でないエラーが報告された場合、そのアクションにページのプライベート・パラメータを設定できます。この機能を有効にするには、アクションでerror-param属性を使用します。たとえば、<xsql:dml>アクション内の文でデータベース・エラーが発生した場合にパラメータ"dml-error"を設定するには、例15-9の方法を使用します。
例15-9 エラー・パラメータの設定
<xsql:dml error-param="dml-error" bind-params="val">
INSERT INTO yourtable(somecol)
VALUES(?)
</xsql:dml>
<xsql:dml>アクションを実行したときにエラーが発生すると、dml-errorという名前のページのプライベート・パラメータが文字列"Error"に設定されます。実行が成功した場合、エラー・パラメータに値は割り当てられません。例15-9では、ページのプライベート・パラメータdml-errorがすでに存在する場合、現行の値が維持されます。存在しない場合、このパラメータが出現することはありません。
このエラー・パラメータを<xsql:if-param>と組み合せて使用することで、XSQLページ・テンプレート内で条件付き動作を実行できます。たとえば、XSQL構成ファイル内で、接続demoの接続定義のAUTOCOMMITフラグをfalseに設定したとします。例15-10のXSQLページに、先行するアクションにおいて行った変更を、後続のアクションでエラーが発生した場合にどのようにロールバックするかを示します。
例15-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>
カスタム・アクション・ハンドラを作成済で、カスタム・アクションがreportMissingAttribute()、reportError()またはreportErrorIncludingStatement()をコールして致命的でないアクション・エラーを通知する場合、この機能も自動的に使用されます。
XSQLアクション・ハンドラ要素の処理によって発生したエラーは、XML要素として決まった方法で通知されます。そのため、XSLTスタイルシートはエラーの存在を検出し、オプションでそれらをフォーマットして表示できます。
エラーが発生したアクション・ハンドラ要素は、ページ内で次の要素に置き換えられます。
<xsql-error action="xxx">
エラーによっては、<xsql-error>要素に次のものが含まれます。
ネストした<message>要素
違反SQL文を含む<statement>要素
例15-11では、次の情報を使用してエラー情報を画面上に表示するXSLTスタイルシートの例を示します。
例15-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>
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文書は、XMLエンジンによって解析され、XSQLページに挿入されます。
例15-12では、ネストしたXmlAgg()関数を使用して、部門およびネストした従業員を含む動的に作成されたXML文書の結果を集計します。この関数は、結果を<DepartmentList>要素でラップして1つの結果文書に集計します。
例15-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>
別の例として、moviesというXMLTypeの表に多数の<Movie>というXML文書が格納されているとします。それぞれの文書は、例15-13のようになっているとします。
例15-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>
組込みXPath問合せ機能を使用すると、データベースに含まれるすべての映画から、アカデミー賞を受賞したすべての出演者の集計リストを抽出できます。例15-14に、サンプルの問合せを示します。
例15-14 XPathを使用した集計リストの抽出
SELECT XMLELEMENT("AwardedActors",
XMLAGG(EXTRACT(VALUE(m),
'/Movie/Cast/*[Award[@From="Oscar"]]')))
FROM movies m
このXMLTypeの問合せ結果をXSQLページに挿入するには、<xsql:query>要素の中に問合せを貼り付けます。例15-15のように、必ず問合せ式の別名を挿入します。
例15-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>
XmlElement()とXmlAgg()を組み合せて使用すると、データベースで、問合せで検出されたすべてのXMLフラグメントを1つの整形式XML文書に集計できます。この2つの関数を使用すると、次のような整形式の結果が生成されます。
<AwardedActors> <Actor>...</Actor> <Actress>...</Actress> </AwardedActors>
バインド変数を式に連結する場合は、XPath式の途中で標準のXSQLバインド変数機能を使用することもできます。たとえば、値Oscarをaward-fromという名前のパラメータにするには、XSQLページを例15-16のように使用します。
例15-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>
XSQLページ・フレームワークは、XMLコンテンツの作成および変換のみでなく、ポストされたXMLコンテンツの処理も簡単にします。組込みアクションの利点は次のとおりです。
XML文書形式およびHTML形式のポストされたデータの処理が簡単になります。
XSUを使用してデータをデータベース表に直接ポストできます。
XSUは、ターゲット表またはビューに必要な正規の形式のXML文書のコンテンツに基づいて、データベースの挿入、更新および削除機能を実行します。特定のデータベース表では、そのデータの正規のXML形式は、SELECT *問合せからのXML出力の1行によって指定されます。この形式のXML文書では、XSUはDML操作を自動化できます。
XSUとXSLTを組み合せると、すべての形式のXMLを特定の表に対して適切な正規の形式に変換できます。変換後、結果として戻る正規のXMLに対してXSUでDMLを実行できます。
次の組込みXSQLアクションを使用すると、この機能をXSQLページ内から使用できます。
リクエストでポストされ、オプションで変換されたXML文書を表に挿入します。
リクエストでポストされ、オプションで変換されたXML文書を表またはビューに更新します。
リクエストでポストされ、オプションで変換されたXML文書を表またはビューから削除します。
リクエスト・パラメータの値としてポストされ、オプションで変換されたXML文書を表またはビューに挿入します。
データベース・ビューを挿入のターゲットにする場合、そのビューに対するINSTEAD OF INSERTトリガーを作成し、ポストされた情報の処理をさらに自動化することができます。たとえば、ビューのINSTEAD OF INSERTトリガーは、PL/SQLを使用してレコードの有無を確認し、その確認結果に応じてINSERTまたはUPDATEのどちらを実行するかを効果的に選択できます。
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文書は例15-17に示す形式になります。
例15-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>
複数のパラメータが同じ名前でポストされた場合、複数の<row>要素が自動的に作成され、それ以降の処理が簡単になります。次のパラメータおよび値をポストまたは挿入するリクエストを想定します。
id = 101
name = Steve
id = 102
name = Sita
operation = update
次のパラメータが作成されます。
<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変換を展開するために使用できます。
XSQLページ・フレームワークによるカスタム・シリアライザのサポートを使用すると、oracle.xml.xsql.serializers.XSQLFOPSerializerクラスでApacheのFOPプロセッサと統合できます。FOPプロセッサは、XSL Formatting Objectsを含むXML文書からPDFドキュメントをレンダリングします。
表14-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シリアライザのソース・コードを例15-18に示します。
例15-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);
}
}
}
この項の内容は次のとおりです。
タスクの実行にカスタム処理が必要であり、そのニーズに合う組込みアクションが表30-2「XSQL構成ファイルの設定」にない場合は、独自のアクションを作成できます。
XSQLページ・エンジンでは、xsql名前空間からアクション・ハンドラ要素を検索し、適切なアクション・ハンドラ要素ハンドラ・クラスをコールして各アクションを処理することにより、XSQLページが処理されます。XSQLActionHandlerインタフェースを実装するすべてのアクションがサポートされています。すべての組込みアクションは、このインタフェースを実装します。
XSQLエンジンは、ページ内のアクションを次の方法で処理します。ページ内のアクションごとに、次の手順を実行します。
デフォルトのコンストラクタを使用して、アクション・ハンドラ・クラスのインスタンスを作成します。
メソッドinit(Element actionElt,XSQLPageRequest context)をコールして、アクション・ハンドラ要素オブジェクトおよびXSQL Page Processorコンテキストを含むハンドラ・インスタンスを初期化します。
メソッドhandleAction (Node result)を起動して、ハンドラがアクションを処理できるようにします。
組込みアクションの場合、XSQLエンジンは、そのアクション・ハンドラを実装するJavaクラスへのXSQLアクション・ハンドラ要素名をマップできます。表30-2「XSQL構成ファイルの設定」に、組込みアクションとそのアクションに対応するクラスを示しています。
ユーザー定義のアクションの場合は、次の組込みアクションを使用します。fully.qualified.Classnameの部分は使用するクラス名に置き換えてください。
<xsql:action handler="fully.qualified.Classname" ... />
handler属性は、そのカスタム・アクション・ハンドラを実装するJavaクラスの完全修飾名を指定します。
カスタム・アクション・ハンドラを作成するには、oracle.xml.xsql.XSQLActionHandlerインタフェースを実装するクラスを作成します。ほぼすべてのカスタム・アクション・ハンドラは、init()メソッドのデフォルト実装および有用なヘルパー・メソッドを提供するoracle.xml.xsql.XSQLActionHandlerImplを拡張します。
XSQLページ・プロセッサがアクション・ハンドラのhandleAction()メソッドをコールすると、DOMフラグメントがアクション実装に渡されます。アクション・ハンドラは、ページに戻された、動的に作成されたXMLコンテンツをルート・ノードに追加します。
XSQLページ内のアクション・ハンドラ要素は、概念的にこのドキュメント・フラグメントのコンテンツに置き換えられます。ページに追加するXMLコンテンツがない場合、アクション・ハンドラはこのフラグメントに何も追加しません。
カスタム・アクション・ハンドラを作成する場合、XSQLActionHandlerImplクラスのいくつかのメソッドが役に立ちます。表15-2に、これらのメソッドを示します。
表15-2 XSQLActionHandlerImplクラスの有用なメソッド
| メソッド名 | 説明 |
|---|---|
getActionElement |
処理中の現行のアクション・ハンドラ要素を戻します。 |
getActionElementContent |
すべての字句パラメータを適切に置き換えて、現行のアクション・ハンドラ要素のテキスト・コンテンツを戻します。 |
getPageRequest |
現行のXSQLページ・プロセッサのコンテキストを戻します。このオブジェクトでは次のメソッドを使用できます。
|
getAttributeAllowingParam |
属性値で使用されているすべてのXSQL字句パラメータ参照を解決し、要素から属性値を取得します。通常、このメソッドはアクション・ハンドラ要素自体に適用されますが、サブ要素の属性にアクセスすることも有効です。字句パラメータを許可せずに属性値にアクセスするには、DOMの |
appendSecondaryDocument |
外部XML文書のコンテンツをアクション・ハンドラの結果コンテンツのルートに追加します。 |
addResultElement |
テキスト・コンテンツを含む単一の要素をアクション・ハンドラの結果コンテンツのルートに追加する操作を簡単にします。 |
firstColumnOfFirstRow |
SQL文の最初の行にある最初の列値を戻します。このメソッドを使用するには、現行のページのドキュメント要素に接続属性が含まれている必要があります。含まれていない場合は、エラーが戻されます。 |
getBindVariableCount |
空白で区切られた |
handleBindVariables |
現行のアクション・ハンドラ要素の |
reportErrorIncludingStatement |
エラーを報告します。エラーには問題の原因である違反(SQL)文が含まれます。オプションで、エラーに数値エラー・コードが含まれる場合もあります。 |
reportFatalError |
致命的エラーを報告します。 |
reportMissingAttribute |
|
reportStatus |
|
requiredConnectionProvided |
このリクエストに使用できる接続の有無を確認し、使用可能な接続がない場合はページにエラーグラムを出力します。 |
variableValue |
字句パラメータのデフォルト値を決定する場合があるすべての有効範囲決定規則を考慮して、字句パラメータの値を戻します。 |
例15-19に、カスタム・アクション・ハンドラMyIncludeXSQLHandlerを示します。このハンドラは、組込みアクション・ハンドラの1つおよび任意のJavaコードを使用し、そのハンドラによって戻されたXMLフラグメントを変更してから、その結果をXSQLページに追加します。
例15-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);
}
}
ページがXSQLサーブレット、XSQLコマンドライン・ユーティリティまたはプログラムでXSQLRequestクラスを介してリクエストされているかどうかに基づいて、異なる動作をするカスタム・アクション・ハンドラを作成する場合、アクション・ハンドラの実装で、getPageRequest()を起動して、現行のページ・リクエスト用の XSQLPageRequestインタフェースを参照できます。XSQLPageRequestオブジェクトに対してgetRequestType()をコールすると、Servlet、Command LineまたはProgrammaticのいずれからリクエストを受信しているかを確認できます。戻り値がServletの場合、例15-20の構文によって、HTTPサーブレットのリクエスト、レスポンスおよびサーブレット・コンテキスト・オブジェクトにアクセスできます。
例15-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.
}
XSQLActionHandlerImplはカスタムXSQLアクションの基本クラスです。このクラスでは次の機能を使用できます。
配列名を使用した字句パラメータ置換
配列名を使用したバインド変数
単一値のパラメータ
カスタム・アクションでこの基本クラスからのメソッド、たとえばgetAttributeAllowingParam()、getActionElementContent()またはhandleBindVariables()などを使用する場合は、カスタム・アクションで複数値のパラメータの機能を使用できます。
パラメータ値をString[]として明示的に取得するには、XSQLPageRequestインタフェースでgetParameterValues()メソッドを使用します。XSQLActionHandlerImplのヘルパー・メソッドvariableValues()を使用すると、プログラムで必要な場合にカスタム・アクション・ハンドラ内からこの機能を使用できます。
ユーザー定義のシリアライザ・クラスを実装し、最終XSQLデータページをテキストまたはバイナリ・ストリームにシリアライズする方法を制御できます。ユーザー定義のシリアライザには、oracle.xml.xsql.XSQLDocumentSerializerインタフェースを実装する必要があります。このインタフェースには次の単一メソッドがあります。
void serialize(org.w3c.dom.Document doc, XSQLPageRequest env) throws Throwable;
DOMベースのシリアライザのみがサポートされます。カスタム・シリアライザ・クラスを使用する場合は、次のタスクを適切な順序で実行する必要があります。
出力PrintWriter(またはOutputStream)に内容を出力する前に、シリアライズされたストリームのコンテンツ・タイプを設定します。
シリアライザに渡されたXSQLPageRequestに対してsetContentType()をコールし、型を設定します。コンテンツ・タイプを設定する場合は、次のようなMIMEタイプを設定できます。
env.setContentType("text/html");
または、次のようにエンコーディング・キャラクタ・セットを含むMIMEタイプを設定することもできます。
env.setContentType("text/html;charset=Shift_JIS");
XSQLPageRequestに対してgetWriter()またはgetOutputStream()のどちらかをコールし(両方は不可)、それぞれ適切なPrintWriterまたはOutputStreamを取得して、コンテンツのシリアライズに使用します。
例15-21のカスタム・シリアライザは、現行のXSQLデータ・ページのドキュメント要素名を含むHTMLドキュメントをシリアライズする単純な実装を示します。
例15-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>");
}
}
カスタム・シリアライザを使用するには、シリアライズの前に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"?>
また、XSQL構成ファイルの<serializerdefs>セクションでカスタム・シリアライザに短縮名を割り当てることができます。serializer属性でそのニックネームを使用して、入力作業を省くことができます。短縮名には大/小文字の区別があります。
XSQL構成ファイルに例15-22に示す情報が指定されているとします。
例15-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>
次のようにスタイルシートの命令に短縮名"Sample"または"FOP"を使用できます。
<?xml-stylesheet type="text/xsl" href="emp-to-xslfo.xsl" serializer="FOP"?> <?xml-stylesheet serializer="Sample"?>
XSQLPageRequestインタフェースは、getWriter()メソッドおよびgetOutputStream()メソッドの両方をサポートします。カスタム・シリアライザは、getOutputStream()をコールして、OutputStreamインスタンスを戻します。バイナリ・データは、このインスタンスにシリアライズできます。XSQLサーブレットを使用する場合は、このOutputStreamに出力すると、バイナリ情報がサーブレットのOutputStreamに出力されます。
例15-23のシリアライザは、動的GIFイメージを出力する例を示します。この例では、GIFイメージは静的な「OK」アイコンですが、より高度なイメージ・シリアライザで使用する必要がある基本的な方法を示します。
例15-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();
}
}
XSQLコマンドライン・ユーティリティを使用する場合は、バイナリ情報がターゲット出力ファイルに出力されます。XSQLRequestAPIを使用する場合は、2つのコンストラクタが存在します。これらのコンストラクタは、コール元がページ処理の結果用に使用するターゲットOutputStreamを提供できるようにします。
シリアライザは、getWriter()(テキスト出力用)またはgetOutputStream()(バイナリ出力用)のどちらかをコールする必要があります。ただし、これらの両方をコールすることはできません。同一のリクエストで両方のメソッドをコールすると、エラーが発生します。
XSQL構成ファイル内に自分が使用する接続を名前を付けて定義するという方法の他に、提供されている2つのXSQLConnectionManager実装のいずれかを使用するという方法があります。これらの実装を使用すると、サーブレット・コンテナのJDBCデータソース実装および関連する接続プーリング機能を使用できます。
XSQLページ・フレームワークには、代替として使用できる次のConnection Manager実装が付属しています。
oracle.xml.xsql.XSQLDatasourceConnectionManager
サーブレット・コンテナのデータソース実装がOracle JDBCドライバを使用しない場合は、このConnection Managerを代替に使用することをお薦めします。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 Application Serverには、このタスクを実行するデータソース実装が含まれています。
前述の代替Connection Manager実装のいずれかを使用するとき、XSQLページ内の接続属性の値には、必要なデータソースの検索に使用するJNDI名を指定します。接続属性の値の例を次に示します。
jdbc/scottDS
java:comp/env/jdbc/MyDatasource
デフォルトのXSQLページConnection Managerを使用しない場合は、代替のConnection Manager実装を使用して必要な接続プーリング機能を提供する必要があります。JDBCデータソースに基づく前述の2つのオプションでは、サーブレット・コンテナを適切に構成し、接続プーリングを提供する必要があります。プールされた接続を提供するためにデータソースを適切に構成する方法については、使用しているサーブレット・コンテナのドキュメントを参照してください。
カスタムConnection Managerを作成し、組込みConnection Managementメカニズムを置き換えることができます。カスタムConnection Managerの実装を提供するには、次の手順を実行する必要があります。
oracle.xml.xsql.XSQLConnectionManagerFactoryインタフェースを実装するConnection Managerファクトリ・クラスを作成します。
oracle.xml.xsql.XSQLConnectionManagerインタフェースを実装するConnection Managerクラスを作成します。
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はサーブレットの破棄プロセスの一部として、リソースをクリーンアップできます。
HTTP認証メカニズムを使用して、データベースに接続するためのユーザー名およびパスワードを取得するには、カスタマイズしたConnection Managerを作成します。これにより、getConnection()メソッドを起動して必要な情報を取得できます。
Javaプログラムを作成するには、次の手順を実行します。
oracle.xml.xsql.XSQLPageRequestインタフェースのインスタンスをgetConnection()メソッドに渡します。
getRequestType()を起動して、リクエストのタイプがServletであることを確認します。
XSQLPageRequestオブジェクトをXSQLServletPageRequestにキャストします。
前述の手順の結果に対してgetHttpServletRequest()をコールします。
前述のコールで戻されたjavax.servlet.http.HttpServletResponseオブジェクトから認証情報を取得します。
重大なPage Processorエラー(接続が使用できないなど)をユーザーに通知する方法を制御する場合があります。これを行うには、oracle.xml.xsql.XSQLErrorHandlerインタフェースを実装します。このインタフェースには次に示す単一のメソッド・シグネチャが含まれています。
public interface XSQLErrorHandler {
public void handleError( XSQLError err, XSQLPageRequest env);
}
XSQLErrorHandlerインタフェースを実装するクラスを提供すると、XSQLページ・プロセッサによるエラー・メッセージの出力方法をカスタマイズできます。新しいXSQLErrorオブジェクトはエラー情報をカプセル化し、エラー・コード、フォーマットされたエラー・メッセージなどへのアクセスを提供します。
例15-24に、XSQLErrorHandlerのサンプル実装を示します。
例15-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());
}
}
使用するカスタムXSQLErrorHandler実装を、次の2つの方法で制御できます。
カスタムXSQLErrorHandler実装クラスの名前をXSQL構成ファイルに定義します。エラー・ハンドラ・クラスの完全修飾クラス名を/XSQLConfig/processor/error-handler/classエントリの値として指定する必要があります。
XSQLページ・プロセッサがこのクラスをロードし、XSQLErrorHandlerインタフェースを正しく実装すると、このクラスはシングルトンとして使用され、ページ・プロセッサのエラーが通知された場合にデフォルトの実装をグローバルに置換します。
ページのドキュメント要素に対してerrorHandler(またはxsql:errorHandler)属性を使用して、ページごとにエラー・ライターをオーバーライドします。この属性の値は、XSQLErrorHandlerインタフェースを実装するクラスの完全修飾クラス名です。このクラスは現行のページで発生したエラーのみを通知します。このクラスは、Page Engineによってページ・リクエストごとにインスタンス化されます。
前述の方法は、必要に応じて組み合せて使用できます。
各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);
}
例15-25および例15-26のクラスは、カスタム・ログ出力の一般的な実装を示します。例15-25のXSQLLogger実装では、ページ・リクエストの開始時刻を記録します。また、ページ・リクエストの名前と経過時間をSystem.outに出力して、ページ・リクエストの終了時刻を記録します。
例15-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");
}
}
例15-26に、ファクトリの実装を示します。
例15-26 SampleCustomLoggerFactoryクラス
package example;
import oracle.xml.xsql.*;
public class SampleCustomLoggerFactory implements XSQLLoggerFactory {
public XSQLLogger create(XSQLPageRequest env) {
return new SampleCustomLogger();
}
}
カスタム・ログ出力ファクトリを登録するには、XSQLConfig.xmlファイルを編集し、カスタム・ログ出力ファクトリ・クラスの名前を/XSQLConfig/processor/logger/factory要素のコンテンツとして指定します。例15-27に、その方法を示します。
例15-27 カスタム・ログ出力ファクトリの登録
<XSQLConfig>
:
<processor>
:
<logger>
<factory>example.SampleCustomLoggerFactory</factory>
</logger>
:
</processor>
</XSQLConfig>
デフォルトでは、<logger>セクションはコメント・アウトされています。デフォルトのログ出力はありません。