http://xml.apache.org/http://www.apache.org/http://www.w3.org/

What's New
DTM
XSLTC Translets

Overview
Getting Started

FAQs

Sample Apps
Command Line

Usage Patterns
Features

TrAX
API (Javadoc)

Extensions
Extensions Library

Release Notes

Xalan 2 Design
XSLTC Design

Bugs
Testing
Builds

Credits
XSLTC Credits

イントロダクション
 

拡張要素と拡張関数は、Xalan のようなXSLT処理系が、拡張によってあなたの出来ることを簡単にするための、強力なメカニズムを提供する。XMLオープンソース開発者コミュニティからの貢献によって、われわれはXalan-Javaで同梱された拡張ライブラリに含まれる便利な拡張を配置する作業を行っている。もしあなたにアイディアや貢献したいことがあれば、Xalan Development Mailing Listでわれわれにメールを送ってほしい。


EXSLT拡張
 

Xalan-Java は EXSLT イニシアティブをサポートして、XSLTの利用者に標準的な拡張関数の集合を提供する。Xalan-Java 2.3.2 は、12の EXSLT関数の実装を含んでいる(いくつかは既にXalanのネームスペースで拡張の呼び出しになっている)。たとえば、こんな感じ:

EXSLT 日付・時刻関数 とユーザー定義のEXSLT 関数(関数と結果要素)の作業が進行中だ。 この他の EXSLT 拡張の実装を手伝いたいっていう人がいたら、歓迎だ。Xalan Development Mailing Listでわれわれにメールを送ってほしい。


Xalan ネームスペース
 

われわれは、それが意味をなすかぎりで、新しい Xalan 拡張を org.apache.xalan.lib.Extensions クラスに置いて、このクラスにネームスペースを定義した:

     http://xml.apache.org/xalan

もし Xalan-Java が提供する拡張を呼び出すなら、このネームスペースをあなたのスタイルシート要素中で定義して、あなたがそれに関連付けたネームスペース プレフィックスを使ってこの拡張を呼び出すことをお勧めするよ。こうすると、もしわれわれが後で Xalan-Java で提供する拡張をどういう風に保存することにしたとしても、あなたのスタイルシートを修正する必要はないだろう。

この名前空間の使用例については、nodeset 拡張関数の例を見てくれ。


Redirect
 

標準のXSL変換処理は、単一のXSLスタイルシート、単一のXMLソースツリー、そして変換結果ツリーからなる。この変換処理は完全な結果を単一のorg.apache.trax.Result オブジェクトに送る。

Redirect エクステンション (org.apache.xalan.xslt.extensions.Redirect) は、あなたが変換出力の一部を複数のファイルにリダイレクトするように使うことが出来る3つの拡張要素を提供している: <open>, <write>, <close> だ。もし<write> 要素を単独で使用すれば、このエクステンションはファイルを開いて、それを書き込んで、すぐにファイルを閉じる。もし明示的にファイルのオープンとクローズを制御したければ、<write> をこの <open> や <close> の要素と結びつけて使うんだ。

これらの要素はそれぞれ、出力ファイルを指定する file 属性や select 属性をもっている。file 属性は文字列を取るので、ここに出力ファイル名を直接指定する。select 属性ならXPath式を取るので、あなたは動的に出力ファイルを生成することが出来る。もし両方の属性を指定したら、Redirect エクステンションはまず select 属性を評価して、もしこれが有効なファイル名を返さなかった場合は、続いてfile 属性を評価する。

Redirectエクステンションの例
 

あなたが結果ツリーの大部分を1つのファイルに出力したいが、<foo> 要素とその子の変換結果を別のファイルに出力したいとする。以下の例がXMLソースの基本構造を示している:

<?xml version="1.0"?> 
<doc>
  <foo file="foo.out">
    Testing Redirect extension:
      <bar>A foo subelement text node</bar>
  </foo>
  <main>
    Everything else
  </main>  
</doc>

このスタイルシートは出力の一部を2番目のファイルにリダイレクトする:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0"
    xmlns:lxslt="http://xml.apache.org/xslt"
    xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"
    extension-element-prefixes="redirect">

  <xsl:template match="/">
    <standard-out>
      Standard output:
      <xsl:apply-templates/>
    </standard-out>
  </xsl:template>
  
  <xsl:template match="main">
    <main>
      <xsl:apply-templates/>
    </main>
  </xsl:template>
  
  <xsl:template match="/doc/foo">
    <redirect:write select="@file">
      <foo-out>
        <xsl:apply-templates/>
      </foo-out>
    </redirect:write>
  </xsl:template>
  
  <xsl:template match="bar">
    <foobar-out>
      <xsl:apply-templates/>
    </foobar-out>
  </xsl:template>
  
</xsl:stylesheet>

標準出力はこうなり:

<?xml version="1.0" encoding="UTF-8"?>
<standard-out>
  Standard output:
  <main>
    Everything else.
  </main>
<standard-out>

foo.out にリダイレクトされた出力はこうなる:

<?xml version="1.0" encoding="UTF-8"?>
<foo-out>
    Testing Redirect extension:
    <foobar-out>foo subelement text node</foobar-out>
  </foo-out>

Redirect エクステンションを使って複数のファイルに出力を送る使い方についての詳細情報は、SimpleRedirect サンプルを検分して、Redirect クラスの Javadoc を見てくれ。



nodeset
 

org.apache.xalan.lib.Extensionsに実装されている
nodeset (result-tree-fragment) は、結果ツリーフラグメントをnode-setにキャストする。

Noteselect式によって生成される値ではなく、テンプレートに変数を結び付けたい場合、この変数のデータ型は結果ツリーフラグメントになってしまう。詳しくは結果ツリーフラグメントを見てくれ。
nodeset拡張関数の例
 

以下のスタイルシートはnodeset拡張関数を使って、結果ツリーフラグメントを、標準のXPathの方法でナビゲートできるnode-setにキャストしている。これは http://xml.apache.org/xalan ネームスペースを使って、xml.apache.xalan.lib.Extensions にあるnodeset()メソッドへにアクセスさせている。

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                   version="1.0"
                   xmlns:xalan="http://xml.apache.org/xalan"
                   exclude-result-prefixes="xalan">
<xsl:template match="/">
  <out>
	  <xsl:variable name="rtf">
      <docelem>
        <elem1>
          <elem1a>ELEMENT1A</elem1a>
          <elem1b>,ELEMENT1B</elem1b>
        </elem1>
        <elem2>
          <elem2a>ELEMENT2A</elem2a>
        </elem2>
      </docelem>
    </xsl:variable>     
      <xsl:for-each select="xalan:nodeset($rtf)/docelem//*">
        <xsl:value-of select="name(.)"/><xsl:text>,</xsl:text>
      </xsl:for-each>
  </out>
</xsl:template> 
</xsl:stylesheet>

このスタイルシートの実行出力は(XML入力ソースは何でもいい)、node-set中の要素名の、カンマ区切りリストだ。
  <out>elem1,elem1a,elem1b,elem2,elem2a</out>

Noteここでは例示のため、このスタイルシートはXML入力文書の構造や内容には何も注意を払っていないものとする。そのかわり、これはrtf という名前の変数に結び付けられた(スタイルシート中の)テンプレートを処理する。


intersection
 

org.apache.xalan.lib.Extensionsに実装されている
intersection (node-set1, node-set2) 関数は、 ns1 と ns2 の中にある全てのノードを含む、単一のnode-setを返す。


difference
 

org.apache.xalan.lib.Extensionsに実装されている
difference(node-set1, node-set2) は、node-set1にあって、node-set2にないノードを含む、単一のnode-setを返す。


distinct
 

org.apache.xalan.lib.Extensionsに実装されている
distinct (node-set) は、一意の文字列値となるノードを含むnode-setを返す。もし同じテキストノード値をもつノードが1つ以上ある場合、distinct は見つかった最初のノードのみを返す。


hasSameNodes
 

org.apache.xalan.lib.Extensionsで実装されている
hasSameNodes(node-set1, node-set2) は、もしnode-set1とnode-set2が同一のノードの集合を含んでいたら true を返す。


NodeInfo
 

org.apache.xalan.lib.NodeInfo は、ソースドキュメント中のノードの位置情報を取得するための拡張要素を提供する:

NoteもしNodeInfo拡張要素を使いたいなら、TransformerFactory の source_location アトリビュートを true に設定しなければならない。command-line utility -L フラグあるいは TransformerFactory.setAttribute() メソッドを使って、このアトリビュートを設定することもできる。
systemId
 

org.apache.xalan.lib.NodeInfoに実装されている,
systemId() はカレントノードのシステムIDを返し、
systemId(node-set) はnode-set中の最初のノードのシステムIDを返す。


publicId
 

これからやる。 org.apache.xalan.lib.NodeInfoに実装されている
publicId() はカレントノードの公開識別子を返すことになるだろう。そして、
publicId(node-set) はnode-set中の最初のノードの公開識別子を返す。


lineNumber
 

org.apache.xalan.lib.NodeInfoに実装されている
lineNumber() はカレントノードのソースドキュメント内での行番号を返し、
lineNumber(node-set) はnode-set中の最初のノードのソースドキュメント内での行番号を返す。

Noteこの関数は、行番号が未知である(たとえばソースがDOMのDocumentだった場合)には -1 を返す。

columnNumber
 

org.apache.xalan.lib.NodeInfoに実装されている
columnNumber() はカレントノードのソースドキュメント内での列番号を返し、
columnNumber(node-set) はnode-set中の最初のノードのソースドキュメント内での列番号を返す。

Noteこの関数は、列番号が未知である(たとえばソースがDOMのDocumentだった場合)には -1 を返す。


SQL ライブラリ
 
NoteSQL ライブラリのUML図面は、SQL ライブラリの UML 図面を見てくれ。

JDBCデータソースへの接続のための拡張関数を提供する。これはクエリを実行して、「ストリーム可能な」結果セットを通して、累積的に動作する。ストリーミング(単一の行ノードを、結果セットのトラバース[たどり]に再利用する)が、操作のデフォルトモードになっている。もし完全な結果セットに無制限のアクセスをしたいなら、クエリの結果セットをキャッシュすることが出来る(結果セット中のそれぞれの行に1行のノードとなる)。

もしあなたがストリーミングモードを使うなら(デフォルト)、同時的には1つの行要素にのみ、結果セットは順次にのみ、アクセスできる。たとえば、結果セット中のノードを別の方法で返すような、スタイルシート中でのXPath式の利用は、予期しない結果を生成しうる。

NoteSQLライブラリの多くの機能は、コネクション プーリングやパラメータ付きクエリ、キャッシング、XMLソースドキュメントからの接続情報やクエリ パラメータの展開のサポートも含めて、John Gentilin (johnglinux@eyecatching.com)の功績が大きい。彼は数多くのSQL library samplesも作ってくれた。

org.apache.xalan.lib.sql.XConnection は、あなたがスタイルシート中で使えるような、数多くの拡張関数を提供している。

  1. new() -- XConnectionコンストラクタを使ってデータソースに接続し、XConnectionオブジェクトを返す。スタイルシートがデータソースから取得できるコネクションプールから接続を生成するコンストラクタを使うことができる。コネクションプールの使用をサポートするには、SQLライブラリがConnectionPool のインターフェースと実装 DefaultConnectionPool をインクルードしていなければならない。あなた自身のConnectionPoolの実装を使ったっていい。

  2. query() -- XConnection オブジェクトの query() メソッドを使って、row-setノードの形で「ストリーム可能な」結果セットを返す。row-setで同時に作業する行は1つにしてくれ。同じ行の要素は何度も使われるから、あなたは完全な結果セットが返ってくる前に、row-setを「変換」し始めることができる。

  3. pquery(), addParameter(), addParameterFromElement(), clearParameters() -- XConnection の pquery() メソッドを他のメソッドと連携して使って、パラメータ付きのクエリをセットアップして実行する。

  4. enableStreamingMode() を使って、結果セットを通じて1つの行ノードを「ストリーム」するのに使う。そして disableStreamingMode() はクエリ結果セットをキャッシュする。

  5. close() -- XConnection オブジェクトの close() メソッドを使って、接続を切断する。

query() と pquery() 拡張関数は、column-header 要素の配列(を必要なだけ)、反復的に使われる1つのrow要素、そしてcol要素の配列を含む Document を返す。column-header要素のそれぞれは(row-set中のcolumnにつきひとつ)、ResultSetMetaDataオブジェクト中のそれぞれの列の記述子についての属性 (ColumnAttribute) を含む。それぞれの col 要素は、現在の行のその列の値のテキスト表現を含むテキストノードを含んでいる。

接続をセットアップする
 

あなたは接続情報(JDBCドライバ、データソースのURL、そして普通はユーザーIDとパスワード)をスタイルシートやXMLソースドキュメント中に書いておくことができる。

以下のスタイルシート フラグメントは、スタイルシートパラメータを使って、JDBCドライバとデータソースを指定している。デフォルトのパラメータ値は、実行時のパラメータ値によって上書きできる。

<xsl:param name="driver" select="'org.enhydra.instantdb.jdbc.idbDriver'"/>
<xsl:param name="datasource" select="'jdbc:idb:../../instantdb/sample.prp'"/>
<xsl:param name="query" select="'SELECT * FROM import1'"/>

変換するXMLソースドキュメントから接続情報を取得することだってできる。あなたがXML文書中に以下の DBINFO ノードセットを持っているとしよう:

<DBINFO>
  <dbdriver>org.enhydra.instantdb.jdbc.idbDriver</dbdriver>
  <dburl>jdbc:idb:../../instantdb/sample.prp</dburl>
  <user>jbloe</user>
  <password>geron07moe</password>
</DBINFO>

スタイルシートでは、この情報を以下のようにして取り出すことができる:

<xsl:stylesheet version 1.0
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:sql="org.apache.xalan.lib.sql.XConnection"
     extension-element-prefixes="sql">
  <xsl:param name="cinfo" select="//DBINFO"/>
  <xsl:variable name="db" select="sql:new($cinfo)"/>
....

どちらのアプローチの例についても、Basic Connection サンプルを見てくれ。

Xalan-Java の外側で維持されている、名前付きコネクションプールを生成することも出来る。

import org.apache.xalan.lib.sql.DefaultConnectionPool;
import org.apache.xalan.lib.sql.XConnectionPoolManager;
...
DefaultConnectionPool cp = new DefaultConnectionPool();
cp.setDriver("org.enhydra.instantdb.jdbc.idbDriver");
cp.setURL("jdbc:idb:../../instantdb/sample.prp");
cp.setUser("jbloe");
cp.setPassword("geron07moe");
// Start with 10 connections.
cp.setMinConnections(10);
cp.enablePool();
// Register the connection pool so stylesheets can use it.
XConnectionPoolManager pm = new XConnectionPoolManager();
pm.registerPool("extpool", cp);

スタイルシートでは、この情報を次のようにして使うことが出来る:

<xsl:stylesheet version 1.0
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:sql="org.apache.xalan.lib.sql.XConnection"
     extension-element-prefixes="sql">
...
  <xsl:variable name="db" select="sql:new($driver, 'extpool')"/>

この例については、ExternalConnection サンプルを見てくれ。


パラメータ付きクエリ
 

パラメータ付きクエリを定義するには、SQLクエリ文字列でそれぞれのパラメータのところに疑問符 (?) を使う。あなたはパラメータの値を、スタイルシートパラメータやXMLソースドキュメント中のノードから、実行時に用意することができる。あなたは、どのパラメータについてもSQLデータ型を指定してやんなきゃいけない。

XConnection はたくさんの addParameter() メソッドと addParameterFromElement() メソッドを提供していて、これを使えば拡張関数を使って(パラメータがクエリ中に出現する順番で)パラメータ値を引っ張ってくることができる。クエリを実行して結果セットを返すには、pquery() メソッドを拡張関数として呼び出す。pquery() メソッドには2つのバリエーションがある。1つはあなたが普通は使わなきゃいけないもので、SQLクエリ文字列とパラメータ型に従った文字列リスト(空白、タブ、改行で区切られる)を引数として含むものだ。たとえばこんなの:

<xsl:variable name="resultset" 
        select=sql:pquery($XConnectionObj, 
                          'select * from X where Y = ? and Z = ?',
                          'int string')"/>

完全な例については、Parameterized query のサンプルを見てくれ。


SQL ライブラリの例
 

この例は、サンプル InstanceDB データベースのテーブルから結果セットを表示する。これはサンプル アプリケーションとしても利用可能だ。6-sqllib-instantdbを見てくれ。

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0"
                xmlns:sql="org.apache.xalan.lib.sql.XConnection"
                extension-element-prefixes="sql">
  <xsl:output method="html" indent="yes"/>
  <xsl:param name="query" select="'SELECT * FROM import1'"/>
 
  <xsl:template match="/">
    <!-- 1. Make the connection -->
    <xsl:variable name="products"
                  select="sql:new('org.enhydra.instantdb.jdbc.idbDriver',
                                'jdbc:idb:.\instantdb\sample.prp')"/>
    <HTML>
      <HEAD>
      </HEAD>
      <BODY>
        <TABLE border="1">
        <!--2. Execute the query -->
        <xsl:variable name="table" select='sql:query($products, $query)'/>
          <TR>
          <!-- Get column-label attribute from each column-header-->
          <xsl:for-each select="$table/sql/metadata/column-header">
            <TH><xsl:value-of select="@column-label"/></TH>
          </xsl:for-each>
          </TR>
          <xsl:apply-templates select="$table/sql/row-set/row"/>
          <xsl:text>&#10;</xsl:text>
        </TABLE>
      </BODY>
    </HTML> 
    <!-- 3. Close the connection -->
    <xsl:value-of select="sql:close($products)"/>
  </xsl:template>

  <xsl:template match="row">
        <TR>
          <xsl:apply-templates select="col"/>
        </TR>
  </xsl:template>

  <xsl:template match="col">
    <TD>
      <!-- Here is the column data -->
      <xsl:value-of select="text()"/>
    </TD>
  </xsl:template>

</xsl:stylesheet>


pipeDocument
 

org.apache.xalan.lib.PipeDocumentで実装されている
pipeDocument 拡張要素は、1つ以上の、一連の変換処理を通してXML文書をパイプする。 それぞれの変換の出力は次の変換処理にパイプされる。最後の変換処理がターゲット ファイルを生成する。

たとえば、あなたが、変換されるべき文書を指定するような要素をもつ、"book"ドキュメントを処理するスタイルシートを持っているとしよう。この主要なスタイルシートはこの本の目次を生成する。それぞれのソースドキュメントについては、pipeDocument 拡張要素を使って、1つ以上の一連の変換処理を通して文書をパイプする。

サンプル: 目次と、HTMLの「本」を生成する
 

XMLの "book" ドキュメントは、たくさんの doc 要素を次のようにもっている:
<doc source="sources/intro.xml" id="intro" label="Introduction">

source 属性は、変換処理すべき文書を識別し、id は出力ファイル名となり、主要なスタイルシートは目次のリンクにラベルを配置する。

スタイルシートでは pipeDocument ネームスペースを宣言し、そのネームスペース プレフィックスをその拡張要素のプレフィックスとして割り当て、またファイルが配置される出力先を示すパラメータを含んでいる:

<xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:pipe="xalan://PipeDocument"
   extension-element-prefixes="pipe">
   
<xsl:param  name="destdir" value="html/output">
...

このスタイルシートは、それぞれのdoc要素が処理されるテンプレートを含んでいる。それぞれのdoc要素では、このスタイルシートは目次ドキュメントにエントリを追加している。拡張要素は、最初の変換処理のスタイルシート入力パラメータと一緒に、2つの繋がった変換処理を通じて、指定された文書をパイプする。pipeDocument の target 属性は、2番目の変換処理の出力を指定する。

<xsl:template match="doc">
  <p>
    <a href={$destdir}><xsl:value-of select="@label"/><a>
  </p>

  <pipe:pipeDocument   source="{@source}" target="{$destdir/@id}">
    <stylesheet href="ss1.xsl">
      <param name="doc-id" value="@id"/>
    </stylesheet>
    <stylesheet href="ss2.xsl"/>   
  </pipe:pipeDocument>
  
</xsl:template>

注意:

  • source 属性のベースURIは、XMLの "book" ドキュメントだ。
  • target 属性はその通りに受け取られる(ベースは、この変換処理が実行されている現在のユーザーディレクトリだ)。
  • この拡張要素を含んでいるスタイルシートは、スタイルシートの href のベースURIとなる。

バリエーション: 空のスタイルシートでpipeDocumentを使う
 

あなたが一連の変換処理を通して文書をパイプしたいとする。あなたは、pipeDocument拡張要素を使って、他の、空のスタイルシートに拡張要素を配置してこの命令を実行することができるんだ。

以下のスタイルシートでは、Xalan 文書を book の中にマージして(最初の変換)、この book をフォーマッティング オブジェクトのツリーに変換する。こうすると、これはPDFファイルの生成に使うことができる。この辺缶処理は以下のようにして呼び出される:

java org.apache.xalan.xslt.Process -in printbook.xml
-param source printbook.xml
-param target xalanbook.fo

ここでは、XML入力文書も出力文書も、主要な変換については存在しなくて、単に拡張要素を呼び出す以上のことはしないんだ。

<?xml version='1.0'?>

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:pipe="xalan://org.apache.xalan.lib.PipeDocument"
                extension-element-prefixes="pipe">

<xsl:param name="source"/>
<xsl:param name="target"/>

<xsl:template match="/">

  <pipe:pipeDocument 
        source="{$source}"
        target="{$target}">
    <stylesheet href="printbook_assemble.xsl"/>
    <stylesheet href="bkbook8x11_xalan.xsl"/>
  </pipe:pipeDocument>
  
</xsl:template>

</xsl:stylesheet>


evaluate
 

org.apache.xalan.lib.Extensionsで実装されている
evaluate (xpath-expression) 関数は、xpath-expression を現在のXPath式コンテキストで評価した結果を返す(自動的にエクステンションのメカニズムによって渡される)。

evaluation 拡張関数は、実行する時になるまで式の値が分からない(訳注 - つまり動的に式を変えたい)場合に使おう。


tokenize
 

org.apache.xalan.lib.Extensionsで実装されている
tokenize (tokenize-string, delimiters)
あるいは
tokenize (tokenize-string) の関数は、tokenize-string のそれぞれのトークンにつき1つのテキストノードを含むnode-setを返す。

delimiters は、tokenize-string をそれぞれのトークンに切り離すために使われる文字を決定する。もしあなたがdelimiters 引数を含めなければ、この関数はタブ(&#x09), 改行 (&#x0A), 復改 (&#x0D), 空白 (&#x20) をデリミタとして使用する。tokenize-string が空文字列だったら、あるいはdelimiters しか含まなかったら、その結果は空のnode-set となる。


group と item
 

これからやる。 共通の値についてアイテムの十分なグループ化を提供する。


type
 

これからやる。 スキーマまたはDTDの型を表す文字列を返す。


to-date
 

これからやる。 文字列を入力として、日付を表す長い値を返す。


format-date
 

これからやる。 文字列をとって、それを指定したとおりに書式化する。


grep
 

これからやる。 grep機能を実行して部分文字列を返す。


for-each-token
 

これからやる。 文字列をトークン化して、それぞれをDOMのTextノードとして、sub-template を実行する。



Copyright © 2002 The Apache Software Foundation. All Rights Reserved.