今回はシステムリソース内のスタイルシートが他のスタイルシートを読み込む(<import>, <include> 要素を持つ)場合を考えます。
何の設定もせずに前回と同じ方法をとると、「(読み込まれる方の)スタイルシートが見つからない」旨の例外が投げられます。 これは、読み込み先のスタイルシートをベースディレクトリ上のファイルとして読み込もうとしているためです。
これを解決するには、独自に javax.xml.transform.URIResolver の実装クラスを作成する必要があります(標準 API で提供されててもいい気はしますが)。 ここではその実装クラスを org.sample.SystemResourceURIResolver として作成します。
ソースコードの配置
ファイル名 | パス | 説明 |
---|---|---|
Main.java | org/sample/ | XSL 変換を実行する main() メソッドをもつクラスです。 |
SystemResourceURIResolver.java | org/sample/ | スタイルシートをシステムリソースとして読み込むためのクラスです。 |
stylesheet.xsl | org/sample/resources/xsl/ | 開発者が作成したスタイルシート。 Main クラス内から直接読み込まれます。 このスタイルシート内から「includee-stylesheet.xsl」が読み込まれます。 |
includee-stylesheet.xsl | org/sample/resources/xsl/ | 開発者が作成したスタイルシートです。 |
stylesheet.xsl, includee-stylesheet.xsl
「includee-stylesheet.xsl」(読み込まれる側のスタイルシート)は特に制限はありません。
「stylesheet.xsl」は「includee-stylesheet.xsl」を読み込んでいるとします:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 「includee-stylesheet.xsl」を読み込んでいる --> <xsl:include href="includee-stylesheet.xsl"/> ... </xsl:stylesheet>
SystemResourceURIResolver.java
javax.xml.transform.URIResolver インターフェースは、スタイルシート内に出てきた URI を独自の方法で解決したい際に用います。 定義されているメソッドは1つだけです:
package javax.xml.transform; public interface URIResolver{ Source resolve(String href, String base)throws TransformerException; }
resolve() メソッドの引数に関して、「href」は <import>, <include> 要素の @href 属性の値、「base」は読み込み側のスタイルシートのベース URI です*1。
さて、今の場合に必要な実装を具体的に見ていきましょう。 Java コードは以下の通り:
package org.sample; import java.io.InputStream; import javax.xml.transform.*; import javax.xml.transform.stream.*; public class SystemResourceURIResolver implements URIResolver{ private final String basedir; public SystemResourceURIResolver(String basedir){ this.basedir = basedir; } public Source resolve(String href, String base)throws TransformerException { InputStream is = ClassLoader.getSystemResourceAsStream(this.basedir+href); return new StreamSource(is); } }
システムリソースの基点となるフォルダへのパス(ここで扱うサンプルでは "org/sample/resources/xsl/")を private フィールドとして保持するようにして、resolve() メソッドでは、そのフォルダと引数の「href」からシステムリソースへのパスを特定します。 リソースを読む際にはやはり ClassLoader.getSystemResourceAsStream() メソッドを用います。
Main.java
変換の手順は以下のようになります:
- TransformerFactory オブジェクトを生成する
- URIResolver オブジェクトを生成し、TransformerFactory にセットする
- Transformer オブジェクトを生成する
- 変換を実行
URIResolver オブジェクトを生成して TransformerFactory オブジェクトにセットする*2ステップが追加されています。 サンプルコードは以下のようになります:
package org.sample; import java.io.InputStream; import javax.xml.transform.*; import javax.xml.transform.stream.*; public class Main { private static final String BASEDIR = "org/sample/resources/xsl/"; public static void main(String[] args) throws TransformerException{ // 1. TransformerFactory オブジェクトを生成する TransformerFactory factory = TransformerFactory.newInstance(); // 2. URIResolver オブジェクトを生成し、TransformerFactory にセットする factory.setURIResolver(new SystemResourceURIResolver(BASEDIR)); // 3. Transformer オブジェクトを生成する InputStream stylesheet = ClassLoader.getSystemResourceAsStream( BASEDIR + "stylesheet.xsl"); Transformer transformer = factory.newTransformer(new StreamSource(stylesheet)); // 4. 変換を実行 transformer.transform( new StreamSource("sample.xml"), new StreamResult(System.out)); } }