続・JavaでXMLをフォーマットする

前回のエントリ(id:toolkit:20060719)での、id:suchiさんのコメントから、

LSSerializerのDOMConfigrationで ”format-pretty-print” をtrue

という方法を教わったので、早速検証してみます。

結果としては・・・ちょっと微妙な感じになったのでメモしておきます。*1

LSSerializerまでの長い道のり(笑)

LSSerializerはJ2SE 5.0でDOM Level3をサポートする事によって追加されたクラスのようです。
まず、LSSerializerはインターフェースです。なので、どうにかして実装を取ってこなければなりません。
DocumentBuilderFactoryみたいに、Factoryクラスがあるのかな?と思ったら、どうも見当たりません。
しょうがないので、Webをあさって、JavaDoc見て調べてみた結果、

  1. LSSerializerはDOMImplementationLS#createLSSerializer()で得られる。
  2. DOMImplementationLSはDocument#getFeature()で得られたオブジェクトをキャストする事によって得られる。

という結論になりました。

Document doc;
※docを作る
DOMImplementation domImpl = doc.getImplementation();
DOMImplementationLS domImplLS = (DOMImplementationLS) domImpl.getFeature("LS", "3.0");
LSSerializer lsSer = domImplLS.createLSSerializer();

ココまでくれば、

lsSer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);

とすれば良い・・と思います。

コードにしてみました。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;

public class LSSerializerTest01 {
	public static void main(String[] args) throws Exception {
		// フォーマットしたいXML
		File inXml = new File("in.xml");
		// フォーマットしたXML
		File outXml = new File("out.xml");

		// フォーマットしたいXMLのDOMオブジェクトを作る
		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
		InputStream in = new FileInputStream(inXml);
		Document doc = docBuilder.parse(in);
		in.close();

		// DOMImplementationLSを取得する
		DOMImplementation domImpl = doc.getImplementation();
		DOMImplementationLS domImplLS = (DOMImplementationLS) domImpl.getFeature("LS", "3.0");

		LSOutput lsOutput = domImplLS.createLSOutput();
		LSSerializer lsSer = domImplLS.createLSSerializer();
		OutputStream out = new FileOutputStream(outXml);
		lsOutput.setByteStream(out);
		
		// LSSerializerのDOMConfigurationにパラメータをセットする
		lsSer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
		lsSer.write(doc, lsOutput);
		out.close();
	}
}


で、実行してみると・・ありゃ、Exception発生。

Exception in thread "main" org.w3c.dom.DOMException: FEATURE_NOT_SUPPORTED: The parameter format-pretty-print is recognized but the requested value cannot be set.
at com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl.setParameter(DOMSerializerImpl.java:267)


なんと!そのパラメータ(format-pretty-print)は認識できるけど、セットできませんと怒られてしまいました(笑)
うーん、今ひとつ釈然としない。メインのソースが悪いのかな・・それともOSXだから??


もう、よくわかんないので、Xercesの最新版をゲットして、パスを通して実行してみると・・・うまく行くではないですか(笑)。*2


Documentオブジェクトの実装は

org.apache.xerces.dom.CoreDOMImplementationImpl

です。


JDKの場合は

com.sun.org.apache.xerces.internal.dom.CoreDOMImplementationImpl

でした。

ってことは、JDKに入っているDOMの実装が古い(?)のかも。

ちなみにJAXPのパッチがあがっていました。

2006/07/13のコメントで、

this will be fixed in Mustang b92.

とあるから、JDK6でサポートされるのかな??

Xercesでもサポートされたのは最近みたい。(2.8からか?)

Implemented the DOM Level 3 Load and Save format-pretty-print parameter.

*1:検証するにあたって、http://jx-study.net/D3pF/D3p.htmlを参考にさせてもらいました。

*2:XMLパーサの指定にXercesを使うという事は特にやっていなくて、単にパスを通しただけです。