(まとめ)JavaでXMLをフォーマットする
結果をまとめてみました
必要ない場合はXMLを読み込む所でDOMを作らないようにし、XMLをフォーマットするという事だけに焦点を絞ってコードを書き直してみました。
検証した環境
- MacOSX Tiger 10.4.7
- Eclipse 3.2
- JavaSE5.0
- Apache Xerces2 2.8.0(http://xerces.apache.org/xerces2-j/)
- Apache Xalan-Java Version 2.7.0(http://xml.apache.org/xalan-j/)
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)
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/)からリンク張られると、アクセスが急激にアップしてちょっとビビりますけど(笑)。