(まとめ)JavaでXMLをフォーマットする

結果をまとめてみました

必要ない場合はXMLを読み込む所でDOMを作らないようにし、XMLをフォーマットするという事だけに焦点を絞ってコードを書き直してみました。

検証した環境

XSLスタイルシートでXSLする方法(id:toolkit:20060719)

備考
JDKだけで稼動します。単なるXSLです。

サンプルソース

import java.io.File;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class JDKXSLTTest01 {

	public static void main(String[] args) throws Exception {
		// フォーマットしたいXML
		File inXml = new File("in.xml");
		// フォーマットしたXML
		File outXml = new File("out.xml");
		// インデントをつけるスタイルシート
		File xsl = new File("style.xsl");

		// XSLT付きのTransformerを用意する。
		TransformerFactory transFactory = TransformerFactory.newInstance();
		Source xslSource = new StreamSource(xsl);
		Transformer transformer = transFactory.newTransformer(xslSource);

		Source source = new StreamSource(inXml);
		Result result = new StreamResult(outXml);

		// outXmlに書き出す。
		transformer.transform(source, result);
	}

}

style.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:xalan="http://xml.apache.org/xslt">
	<xsl:output method="xml" encoding="UTF-8"
		indent="yes" xalan:indent-amount="2"/>
	<xsl:template match="/">
		<xsl:copy-of select="."/>
	</xsl:template>
</xsl:stylesheet>

Xercesを使って、DOM Level3 APIを使用する方法(id:toolkit:20060720)

備考
JDKの実装では、format-pretty-printerパラメータは実装されていないので、Xerces 2.8 が必要。次のJDKでは問題が解決されるみたい。

サンプルソース

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 inStream = new FileInputStream(inXml);
		Document document = docBuilder.parse(inStream);
		inStream.close();

		// DOMImplementationLSを取得する
		DOMImplementation domImpl = document.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にformat-pretty-printをセットする
		lsSer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
		lsSer.write(document, lsOutput);
		out.close();
	}

}

Xalanを使って、OutputPropertiesFactory.S_KEY_INDENT_AMOUNTを指定する方法(id:toolkit:20060721)

備考
JDKの実装ではうまく行かないので、Xalanが必要。OutputPropertiesFactoryは com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory でも、 org.apache.xml.serializer.OutputPropertiesFactory でもどちらでもうまく行く。

サンプルソース

import java.io.File;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory;

public class OutputPropertiesFactoryTest01 {

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

		// Transformerを用意する。
		TransformerFactory transFactory = TransformerFactory.newInstance();
		Transformer transformer = transFactory.newTransformer();
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		transformer.setOutputProperty(OutputKeys.METHOD, "xml");
		
		// OutputPropertiesFactory.S_KEY_INDENT_AMOUNTをセットする
		transformer.setOutputProperty(
				OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "2");

		Source source = new StreamSource(inXml);
		Result result = new StreamResult(outXml);

		// outXmlに書き出す。
		transformer.transform(source, result);
	}

}


個人的な感想としては、パフォーマンスの問題を抜きにして考えると、スタイルシートを使う方法が一番良いのかな?と思います。
今後もそのまま使える方法だし、XSLT出来るし。



いやぁ、しかし、いろんな方からツッコミいただき、ありがたい次第です。いろいろ勉強になりました。
オレンジニュース(http://secure.ddo.jp/~kaku/tdiary/)からリンク張られると、アクセスが急激にアップしてちょっとビビりますけど(笑)。