locus2k
locus2k

Reputation: 2935

JAVA pretty print XML with properly formatted comments

I have an issue when trying to pretty print xml with properly formatted comments. I generate an xml file from a process and need to add header information to the xml document. This header information is in the format of xml comments.

The file that gets generated looks something like this:

<Messages><Message Name="Foo">FooMessage</Message><Message Name="Bar">BarMessage</Message></Messages>

The generated file is from a different process in which I cant modify what it outputs. After the xml file has been generated I need to add a couple comments above the data. The output should look something like this when I'm done:

<xml version="1.0" encoding="us-ascii">
<!-- Message Documentation -->
<!-- Version 1.0 -->
<Messages>
  <Message Name="Foo">FooMessage</Message>
  <Message Name="Bar">BarMessage</Message>
</Messages>

But after I run it through my transformer to pretty print the xml, it causes the comments to be squashed onto a single line:

<xml version="1.0" encoding="us-ascii">
<!-- Message Documentation --><!-- Version 1.0 -->
<Messages>
  <Message Name="Foo">FooMessage</Message>
  <Message Name="Bar">BarMessage</Message>
</Messages>

The header is just a file that has the comments in it:

<!-- Message Documentation -->
<!-- Version 1.0 -->

This is what I am currently doing (Note messages.xml is the generated file):

public static void generate() throws Exception {
    List <String> header = Files.readAllLines(Paths.get("header.xml"));
    List <String> message = Files.readAllLines(Paths.get("messasges.xml"));

    StringBuilder sb = new StringBuilder();
    for (String s: header) {
        sb.append(String.format("%s%n", s));
    }
    for (String s: message) {
        sb.append(String.format("%s%n", s));
    }

    Files.write(Paths.get("tmp.xml"), sb.toString.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);

    DocumentBuilder db = DocumentBuilderFactor.newInstance().newDocumentBuilder();

    Document doc = db.parse(Paths.get("tmp.xml").toFile());
    String xmlStr = prettyPrint(doc);
}

public static String prettyPrint(Document doc) throws Exception {
    Transformer transformer = TransformerFactory.newInstance().newTransformer();
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", 4);
    transformer.setOutputProperty(OutputKeys.ENCODING, "us-ascii");
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
    transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");

    DOMSource source = new DOMSource(doc);
    StringWriter writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    transformer.transform(source, result);
    return writer.getBuffer().toString();
}

Any help would be greatly appreciated as I have not been able to find any information on preserving comments on their respective lines.

Upvotes: 1

Views: 6439

Answers (2)

Valentyn Kolesnikov
Valentyn Kolesnikov

Reputation: 2097

Underscore-java has method U.formatXml(string). I am the maintainer of the project. Live example

import com.github.underscore.U;

public class MyClass {
    public static void main(String args[]) {
        System.out.println(U.formatXml("<?xml version=\"1.0\" encoding=\"us-ascii\"?>\n"
          + "<!-- Message Documentation -->\n"
          + "<!-- Version 1.0 -->\n"
          + "<Messages>\n"
          + "  <Message Name=\"Foo\">FooMessage</Message>\n"
          + "  <Message Name=\"Bar\">BarMessage</Message>\n"
          + "</Messages>"));
    }
}

Output:

<?xml version="1.0" encoding="us-ascii"?>
<!-- Message Documentation -->
<!-- Version 1.0 -->
<Messages>
   <Message Name="Foo">FooMessage</Message>
   <Message Name="Bar">BarMessage</Message>
</Messages>

Upvotes: 0

user987339
user987339

Reputation: 10707

I am afraid, that you cannot achieve this with settings. Use a bit of brute force:

    return writer.getBuffer().toString().replaceAll("--><", "-->\n<");

Upvotes: 3

Related Questions