SAXでXMLの複製を作る
SAXTransformerFactory#newTransformerHandler() を使うと、SAXでXMLを読みつつそのコピーをストリームに書き出すことができます。委譲などを駆使してカスタマイズすれば、特定の要素を除いたXMLのコピーを作成するといったことも可能。DOMにしてからシリアライズするよりは高速でメモリ消費も少ないはず(たぶん)。以下は、コメントを除外したXMLのコピーを作成するサンプルです。
// XMLReaderを作る SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); XMLReader r = factory.newSAXParser().getXMLReader(); // TransformerHandlerを作る SAXTransformerFactory stf = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); final TransformerHandler h = stf.newTransformerHandler(); // コメントをフィルタするようにカスタマイズ。 TransformerHandler proxy = (TransformerHandler) Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(), new Class[]{ TransformerHandler.class, ContentHandler.class, DTDHandler.class, LexicalHandler.class, DeclHandler.class}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ( "comment".equals( method.getName() )) { // コメントの場合は何もしない。 return null; } else { return method.invoke(h, args); } } }); // 出力先の設定 // とりあえず標準出力に。 StreamResult result = new StreamResult(System.out); h.setResult(result); // XMLReaderに設定 r.setContentHandler( proxy ); r.setDTDHandler( proxy ); r.setProperty( "http://xml.org/sax/properties/lexical-handler", proxy ); r.setProperty( "http://xml.org/sax/properties/declaration-handler", proxy ); // パーズ r.parse( new InputSource(ClassLoader.getSystemResourceAsStream("sax/test.xml")) );
次のようなXMLを対象として実行すると、
<?xml version="1.0" encoding="UTF-8" standalone='yes'?> <!DOCTYPE test[ <!ELEMENT hoge (#PCDATA|foo|var)*> <!ATTLIST hoge attr CDATA #REQUIRED> ]> <hoge attr="test"> <?PI aaaaa ?> <![CDATA[ CDATAsection ]]> <!-- comment --> <foo>foo</foo> <var>var</var> </hoge>
以下の結果が出力されます。コメントとDTDがすっ飛ばされています。(JDKは1.5を使用)
<?xml version="1.0" encoding="UTF-8"?><hoge attr="test"> <?PI aaaaa ?> <![CDATA[ CDATAsection ]]> <foo>foo</foo> <var>var</var> </hoge>
Xalanの新しい奴(2.7.1で確認)をパスに通しておくと、DTDも出力されるようになります。
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE test [ <!ELEMENT hoge (#PCDATA|foo|var)*> <!ATTLIST hoge attr CDATA #REQUIRED> ]> <hoge attr="test"> <?PI aaaaa ?> <![CDATA[ CDATAsection ]]> <foo>foo</foo> <var>var</var> </hoge>