Java:如何缩进由Transformer生成的XML

125
我将使用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>

你有什么想法?

7个回答

236
你需要启用“INDENT”并设置转换器的缩进量:
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

更新:


参考文献 : 如何在序列化DOM之前删除仅包含空格的文本节点?

(非常感谢所有成员,特别是 @marc-novakowski、@james-murty 和 @saad):


72
对我来说,将默认缩进设置为0似乎有点愚蠢。但除了使用 INDENT=yes 外,我还需要添加以下内容:t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); - lapo
1
注意。这个缩进属性在Java 5中不起作用,在Java 7中起作用。我还没有在Java 6中尝试过。 - Hilikus
4
如果有多行的内部节点,您能否将其内部部分缩进?仅使用此方法无法使内部节点缩进。 - eipark
补充一下我的上一个评论,字符串中的空格被视为文本节点。 - Sa'ad
2
@lapo 如果你的提供者是xalan(如果这个工作的话,它很可能是),那么它可以作为org.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT使用。 - OrangeDog
显示剩余4条评论

24
没有一个建议的解决方案对我起作用。所以我继续寻找另一种替代方案,最终是将前两种方案混合并加上第三个步骤。
  1. 将缩进数设置为transformerfactory
  2. 在transformer中启用缩进
  3. 用writer(或bufferedwriter)包装outputstream
//(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"));

你必须执行(3)个操作来解决XML处理代码的“有缺陷”的行为。
来源:johnnymac75 @ https://bugs.java.com/bugdatabase/view_bug?bug_id=6296446 (如果我引用的来源有误,请告诉我)

我猜测是因为你的提供程序不是Xalan。你能检查一下你的“TransformerFactory”实际上是什么,这样其他人就知道了。 - OrangeDog
第三步,使用“Writer”作为输出是必不可少的。 - erickson

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

导入com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory

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

这是一个内部类,因此您的代码将无法在其他(甚至更新的)JVM上移植。 - OrangeDog

6
对于我来说,添加DOCTYPE_PUBLIC是有效的:
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "10");

transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"yes"); 是关键。 - silentsudo

6
如果您想要缩进,必须将其指定给TransformerFactory
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));
Transformer t = tf.newTransformer();

4

我使用了Xerces(Apache)库,而不是使用Transformer。一旦添加了该库,请添加以下代码:

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);

是的。我尝试了所有其他Transformer方法,但都失败了。整个W3C库一团糟。Xerces可以用。 - Tuntable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接