125

I'm using Java's built in XML transformer to take a DOM document and print out the resulting XML. The problem is that it isn't indenting the text at all despite having set the parameter "indent" explicitly.

sample code

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

 }
}

result

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

desired result

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

Thoughts?

Mike
  • 58,961
  • 76
  • 175
  • 221

7 Answers7

236

You need to enable 'INDENT' and set the indent amount for the transformer:

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

Update:


Reference : How to strip whitespace-only text nodes from a DOM before serialization?

(Many thanks to all members especially @marc-novakowski, @james-murty and @saad):

Community
  • 1
  • 1
KV Prajapati
  • 93,659
  • 19
  • 148
  • 186
  • 72
    Seems silly to me that the default indentation is 0, but in addition to `INDENT=yes` I also had to add this: `t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");` – lapo Jan 28 '11 at 10:21
  • 1
    Beware. This indentation property doesn't work in java 5. it does in java 7. Haven't tried in java 6 – Hilikus Mar 06 '13 at 17:04
  • 4
    If there are inner nodes that are multiple lines, can you indent the inner portion as well? Just using this doesn't indent the inner nodes. – eipark Apr 25 '13 at 21:10
  • I have a similar problem which @eipark might be referring. I am converting a plain string of XML to a Node and then using transformer to indent it. My plain string contains whitespaces and the indentation does not seem to work (given the above suggestions). I will try to remove the whitespaces before converting to Node, perhaps that would work. – Sa'ad Jun 24 '14 at 10:25
  • To add to my last comment, the whitespaces in my string are regarded as text nodes. – Sa'ad Jun 24 '14 at 10:34
  • @Hilikus I'm using jdk 7 and the indent is 0 for me with this. – apcuk Nov 12 '15 at 16:44
  • If your document contains nodes which were imported from another document, you should also check out http://stackoverflow.com/questions/16641835/strange-xml-indentation for removing whitespace before formatting – Daniel Alder Dec 21 '15 at 13:33
  • This solution works for me in Android - except for the first line of a newly created element node in an existing document. The node always starts at the first column even if it is nested deep in the xml document. Childnodes of this new node are indented correctly and the node's closing tag also is indented as expected. Only the start tag isn't. Any ideas? – Droidum Jul 04 '18 at 12:17
  • 2
    @lapo if your provider is xalan (which it probably is if this works), then it's available as `org.apache.xml.serializer.OutputPropertiesFactory.S_KEY_INDENT_AMOUNT` – OrangeDog May 14 '19 at 17:10
24

Neither of the suggested solutions worked for me. So I kept on searching for an alternative solution, which ended up being a mixture of the two before mentioned and a third step.

  1. set the indent-number into the transformerfactory
  2. enable the indent in the transformer
  3. wrap the otuputstream with a writer (or bufferedwriter)
//(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"));

You must do (3) to workaround a "buggy" behavior of the xml handling code.

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

(If I have cited my source incorrectly please let me know)

Thomas
  • 17,016
  • 4
  • 46
  • 70
mabac
  • 1,420
  • 1
  • 10
  • 6
14

The following code is working for me with Java 7. I set the indent (yes) and indent-amount (2) on the transformer (not the transformer factory) to get it working.

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's solution to set the attribute didn't work for me, but @lapo's comment proved helpful.

Archimedes Trajano
  • 35,625
  • 19
  • 175
  • 265
remipod
  • 11,269
  • 1
  • 22
  • 25
8

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

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

If you want the indentation, you have to specify it to the TransformerFactory.

TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", new Integer(2));
Transformer t = tf.newTransformer();
lucbelanger
  • 342
  • 3
  • 4
6

For me adding DOCTYPE_PUBLIC worked:

transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "10");
xenteros
  • 15,586
  • 12
  • 56
  • 91
Vikas Chowdhury
  • 737
  • 8
  • 15
4

I used the Xerces (Apache) library instead of messing with Transformer. Once you add the library add the code below.

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);
nhahtdh
  • 55,989
  • 15
  • 126
  • 162
sevensevens
  • 1,703
  • 16
  • 27
  • Yes. I tried all the other approaches with the Transformer but all broken. The whole W3C library is a mess. Xerces worked. – Tuntable Nov 10 '17 at 07:44