Skip to content

Adding linebreak in xml file before root node

I am trying to add line break after my comments above the root node in XML document.

I need something like this:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--DO NOT EDIT THIS FILE-->
<projects>
</projects>

But What I was able to get is this(Line break inside the root but I need line break after the comment):

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--DO NOT EDIT THIS FILE--><projects>

</projects>

I need to add the line break just after my comment. Is there a way to do this?

My code:

import java.io.File;
import java.io.FileInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

public class XMLNewLine {
    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("Adding comment..");

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        dbf.setValidating(false);
        DocumentBuilder db;

        try {
            Document doc;
            StreamResult result;
            result = new StreamResult(new File("abc.xml"));
            db = dbf.newDocumentBuilder();
            doc = db.parse(new FileInputStream(new File("abc.xml")));

            Element element = doc.getDocumentElement();
            Text lineBreak = doc.createTextNode("n");

            element.appendChild(lineBreak);
            Comment comment = doc
                    .createComment("DO NOT EDIT THIS FILE");
            element.getParentNode().insertBefore(comment, element);
            doc.getDocumentElement().normalize();
            TransformerFactory transformerFactory = TransformerFactory
                    .newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(doc);
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.transform(source, result);

        } catch (Exception e) {
            // TODO Auto-generated catch block

        }

    }
}

Answer

You basically want a text node containing a line break after the comment node.

Element docElem = doc.getDocumentElement();

doc.insertBefore(doc.createComment("DO NOT EDIT THIS FILE"), docElem);
doc.insertBefore(doc.createTextNode("\n"), docElem);


EDIT: It seems that appending even whitespace-only text nodes is not allowed at the root node of an org.w3c.dom.Document. This is 100% formally correct, but also unhelpful.

The way comments are rendered in the output of the Transformer is determined by the serializer it uses (there are different serializers for HTML, XML and plain text outputs). In the built-in XML serializer the end of a comment is defined as --> – without a newline.

Since the internals of javax.xml.transform.Transformer are hard-wired, the serializers are not public API and the class is marked as final, overriding that behavior or setting a custom serializer is impossible.

In other words, you are out of luck adding your line break in a clean way.

You can, however, safely add it in a slightly unclean way:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();

FileInputStream inputXml = new FileInputStream(new File("input.xml"));
Document doc = db.parse(inputXml);

// add the comment node    
doc.insertBefore(doc.createComment("THIS IS A COMMENT"), doc.getDocumentElement());

StringWriter outputXmlStringWriter = new StringWriter();
Transformer transformer = transformerFactory.newTransformer();
// "xml" + "UTF-8" "include XML declaration" is the default anyway, but let's be explicit
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(new DOMSource(doc), new StreamResult(outputXmlStringWriter));

// now insert our newline into the string & write an UTF-8 file
String outputXmlString = outputXmlStringWriter.toString()
    .replaceFirst("<!--", "n<!--").replaceFirst("-->", "-->n");

FileOutputStream outputXml = new FileOutputStream(new File("output.xml"));            
outputXml.write(outputXmlString.getBytes("UTF-8"));

Doing search-and-replace operations on XML strings is highly discouraged in general, but in this case there is little that can go wrong.