入力ストリームに対して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());
}
}