Java:Transformerによって生成されたXMLをインデントする方法


112

Javaの組み込みXMLトランスフォーマーを使用してDOMドキュメントを取得し、結果のXMLを出力しています。問題は、パラメータ「indent」を明示的に設定したにもかかわらず、テキストをまったくインデントしないことです。

サンプルコード

public class TestXML {

 public static void main(String args[]) throws Exception {
  ByteArrayOutputStream s;

  Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
  Transformer t = TransformerFactory.newInstance().newTransformer();

  Element a,b;

  a = d.createElement("a");
  b = d.createElement("b");

  a.appendChild(b);

  d.appendChild(a);

  t.setParameter(OutputKeys.INDENT, "yes");

  s = new ByteArrayOutputStream();

  t.transform(new DOMSource(d),new StreamResult(s));

  System.out.println(new String(s.toByteArray()));

 }
}

結果

<?xml version="1.0" encoding="UTF-8" standalone="no"?><a><b/></a>

望ましい結果

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<a>
 <b/>
</a>

考え?

回答:


215

「INDENT」を有効にして、トランスフォーマーのインデント量を設定する必要があります。

t.setOutputProperty(OutputKeys.INDENT, "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

更新:


参照:シリアル化前にDOMから空白のみのテキストノードを削除する方法

(すべてのメンバー、特に@ marc-novakowski、@ james-murty、@ saadに感謝します)


70
デフォルトのインデントが0であるように私には愚かなようだが、に加えてINDENT=yes、私もこれを追加する必要がありました:t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
のLaPO

1
注意してください。このインデントプロパティは、Java 5では機能しません
。Java7

4
複数行の内部ノードがある場合、内部部分もインデントできますか?これを使用しても、内部ノードはインデントされません。
eipark 2013

1
@eiparkでstackoverflow.com/a/979606/837530を使用して、空白を削除し、今度はチャームのようにインデントします
Sa'ad

1
@lapoプロバイダーがxalan(これが機能するかどうか)の場合、次のように使用できますorg.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT
OrangeDog

21

提案された解決策はどちらもうまくいきませんでした。したがって、私は代替ソリューションを探し続けました。その結果、前述の2つのソリューションが混合し、3番目のステップになりました。

  1. インデント番号をTransformerfactoryに設定します
  2. トランスのインデントを有効にします
  3. otuputstreamをライター(またはバッファー付きライター)でラップする
//(1)
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));

//(2)
Transformer t = tf.newTransformer();
t.setOutputProperty(OutputKeys.INDENT, "yes");

//(3)
t.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "utf-8"));

xml処理コードの「バグのある」動作を回避するには、(3)を実行する必要があります。

ソース:johnnymac75 @ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446

(出典を間違って引用している場合はお知らせください)


3
最後の行の「アウト」とは何ですか?
mujimu 2011

コンストラクタを使用して新しい整数を作成する必要がありますか?
Benjineer 2015

あなたのプロバイダーがXalanではないので、私は推測しています。あなたがTransformerFactory実際に何であるかを確認して、他の人に知ってもらうことができますか?
OrangeDog

ステップ3は、Writer出力として使用することが不可欠です。
エリクソン

14

次のコードはJava 7で動作します。トランスフォーマー(トランスフォーマーファクトリではない)にインデント(yes)とインデント量(2)を設定して、インデントを機能させます。

TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.transform(source, result);

属性を設定する@mabacのソリューションは私にとってはうまくいきませんでしたが、@ lapoのコメントは役に立ちました。


8

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

transformer.setOutputProperty(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "2");

これは内部クラスなので、コードは他の(またはさらに新しい)JVMに移植できません。
OrangeDog

5

インデントが必要な場合は、それをに指定する必要がありTransformerFactoryます。

TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));
Transformer t = tf.newTransformer();

4

Transformerをいじるのではなく、Xerces(Apache)ライブラリを使用しました。ライブラリを追加したら、以下のコードを追加します。

OutputFormat format = new OutputFormat(document);
format.setLineWidth(65);
format.setIndenting(true);
format.setIndent(2);
Writer outxml = new FileWriter(new File("out.xml"));
XMLSerializer serializer = new XMLSerializer(outxml, format);
serializer.serialize(document);

はい。私はトランスフォーマーで他のすべてのアプローチを試しましたが、すべて壊れました。W3Cライブラリ全体が混乱しています。クセルスは働いた。
調整可能

3

私にとってDOCTYPE_PUBLICはうまくいきました:

transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "10");

transform.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC、 "yes"); キーです
silentsudo 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.