入力ストリームに対してXSLTを適用するフィルタストリームです。
Javaプログラム中で、RSS0.9/1.0/2.0/Atom0.3をRSS1.0に変換するXSLTをつかって、RSSを正規化するために作りましたが、もちろんXSLT変換一般に使えます。
FilterInputStream?は、フィルタ処理をするInputStream?の上位クラスとして用意されたクラスです。
Javaでは、
InputStream inp = new BufferedInputStream( new FileInputStream( "a.txt" ) ); a.txt ---> FileInputStream ---> BufferedInputStream ---> ユーザプログラム
などというように入力ストリームを多段に使う事がよく行われます。
FilterInputStream?は、
read() や close() など InputStream?が実装しなければいけないメソッドに関して、
in.read() 、 in.close() など、フィールド属性の
protected InputStream in;
を操作した結果を返すように実装されています。
そこで、フィルタ処理を行うInputStream?を作るときには、FilterInputStream?を継承して、コンストラクタのみをオーバーライドします。
コンストラクタで一旦全てのデータを受信してデータ変換を行い、
結果のbyte[]をByteArrayInputStream?にラップしてinにセットしてやれば、
簡単にフィルタ処理を行うInputStream?を作ることができます。
そして、大量の受信をするのでなければそれで十分。今回もその方式でいきます。
XML --(HTTP等)--> |XSLTFilterInputStream | | ↓XSLT適用 | |byte[] | | ↓ByteArrayInputStreamでwrap | | in ---------------------------+--(InputStream)--> ユーザプログラム
JDK1.4から標準で入っています。
xml系の他のライブラリと同じように、TransformerFactoryからTransformerを作り、Transformerで変換します。
まぁ、実際にソースコード(getTranslatedXML())を見てみれば一目瞭然。
/** * 入力ストリームに対してXSLTを適用するフィルタストリーム. * <pre> * 入力ストリームに対してXSLTを適用するフィルタストリームです。 * </pre> * @author kagyuu * @version $Id$ */ public class XSLTFilterInputStream extends FilterInputStream { /** * コンストラクタ. * @param xsltFileName xsltのファイル名 * @param xmlInput 変換対象のサイトURL * @throws IOException xsltファイルもしくはhtmlが読み込めなかった * @throws TransformerException XSLT変換エラー */ public XSLTFilterInputStream(String xsltFileName, String xmlUrlString) throws IOException, TransformerException { super(null); // ファイルを開く InputStream xsltInput = new BufferedInputStream(new FileInputStream(xsltFileName)); // URL接続を開く URL xmlUrl = new URL(xmlUrlString); HttpURLConnection httpConn = (HttpURLConnection) xmlUrl.openConnection(); httpConn.setRequestMethod("GET"); InputStream xmlInput = httpConn.getInputStream(); // 変換結果をinフィールドに格納 in = getTranslatedXML(xsltInput, xmlInput); } /** * コンストラクタ. * @param xsltInput xsltが得られるInputStream * @param xmlInput 変換対象のxmlが得られるInputStream * @throws TransformerException XSLT変換エラー */ public XSLTFilterInputStream(InputStream xsltInput, InputStream xmlInput) throws TransformerException { // 上位クラスのコンストラクタ呼び出し // 基底となる入力ストリーム(this.in)は後で指定するのでここではnullを指定 super(null); // 変換結果をinフィールドに格納 in = getTranslatedXML(xsltInput, xmlInput); } /** * 上位クラスのコンストラクタを無効化します * @param arg0 */ private XSLTFilterInputStream(InputStream arg0) { super(arg0); } /** * XMLをXSLTで変換して、変換結果を取り出すInputStreamを返す. * <pre> * XMLをXSLTで変換して、変換結果をByteArrayInputStreamにwrapします。 * </pre> * @param xsltInput xsltが得られるInputStream * @param xmlInput 変換対象のxmlが得られるInputStream * @return 結果を取り出すInputStream * @throws TransformerException XSLT変換エラー */ private InputStream getTranslatedXML( InputStream xsltInput, InputStream xmlInput) throws TransformerException { // Transformerの作成 TransformerFactory trfactory = TransformerFactory.newInstance(); Transformer t = trfactory.newTransformer(new StreamSource(xsltInput)); // xmlInputに、XSLTを適用する ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); t.transform(new StreamSource(xmlInput), new StreamResult(bufStream)); // 基底となる入力ストリーム return new ByteArrayInputStream(bufStream.toByteArray()); } }