まず、恒等変換について心配する必要はありません。データのメモリ内表現は構築されません。
「ティー」機能を実装するには、パーサーによって生成されたイベントのストリームをリッスンし、トランスフォーマーによって提供されたハンドラーにそれらを渡すコンテンツ ハンドラーを作成する必要があります。残念ながら、これは思ったほど簡単ではありません。パーサーはイベントをDefaultHandlerに送信したいのに対し、トランスフォーマーはXMLReaderからイベントを読み込もうとしています。前者は抽象クラス、後者はインターフェースです。JDK は、クラスXMLFilterImplも提供します。このクラスは、 のすべてのインターフェースを実装しますが、それからDefaultHandler
拡張することはありません。これは、2 つの異なるプロジェクトを「参照実装」として組み込むことで得られるものです。
したがって、2 つの間のブリッジ クラスを記述する必要があります。
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLFilterImpl;
/**
* Uses a decorator ContentHandler to insert a "tee" into a SAX parse/serialize
* stream.
*/
public class SaxTeeExample
{
public static void main(String[] argv)
throws Exception
{
StringReader src = new StringReader("<root><child>text</child></root>");
StringWriter dst = new StringWriter();
Transformer xform = TransformerFactory.newInstance().newTransformer();
XMLReader reader = new MyReader(SAXParserFactory.newInstance().newSAXParser());
xform.transform(new SAXSource(reader, new InputSource(src)),
new StreamResult(dst));
System.out.println(dst.toString());
}
private static class MyReader
extends XMLFilterImpl
{
private SAXParser _parser;
public MyReader(SAXParser parser)
{
_parser = parser;
}
@Override
public void parse(InputSource input)
throws SAXException, IOException
{
_parser.parse(input, new XMLFilterBridge(this));
}
// this is an example of a "tee" function
@Override
public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException
{
System.out.println("startElement: " + name);
super.startElement(uri, localName, name, atts);
}
}
private static class XMLFilterBridge
extends DefaultHandler
{
private XMLFilterImpl _filter;
public XMLFilterBridge(XMLFilterImpl myFilter)
{
_filter = myFilter;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException
{
_filter.characters(ch, start, length);
}
// override all other methods of DefaultHandler
// ...
}
}
このmain
メソッドは、トランスフォーマーをセットアップします。興味深い部分は、SAXSource
が を中心に構築されていることMyReader
です。トランスフォーマーがイベントの準備ができると、parse()
そのオブジェクトのメソッドを呼び出して、指定された を渡しますInputSource
。
次の部分は明らかではありません: XMLFilterImpl
Decorator パターンに従います。トランスフォーマーは、変換を開始する前に、このオブジェクトでさまざまなセッター メソッドを呼び出し、独自のハンドラーを渡します。オーバーライドしないメソッド ( などstartDocument()
) は、単にデリゲートを呼び出します。オーバーライドの例として、私は "分析" (単なる println) をstartElement()
. ContentHandler
おそらく他のメソッドをオーバーライドするでしょう。
最後に、はとXMLFilterBridge
の間の架け橋です。これはデコレーターでもあり、すべてのメソッドはデリゲートを呼び出すだけです。ここでは 1 つのオーバーライドを示していますが、すべてを行う必要があります。DefaultHandler
XmlReader