Strip whitespace and newlines from XML in Java

Viewed 50767

Using Java, I would like to take a document in the following format:

<tag1>
 <tag2>
    <![CDATA[  Some data ]]>
 </tag2>
</tag1>

and convert it to:

<tag1><tag2><![CDATA[  Some data ]]></tag2></tag1>

I tried the following, but it isn't giving me the result I am expecting:

DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
dbfac.setIgnoringElementContentWhitespace(true);
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.parse(new FileInputStream("/tmp/test.xml"));

Writer out = new StringWriter();
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "no");
tf.transform(new DOMSource(doc), new StreamResult(out));
System.out.println(out.toString());
7 Answers

I support @jtahlborn's answer. Just for completeness, I adapted his solution to completely remove the whitespace-only elements instead of just clearing them.

public static void stripEmptyElements(Node node)
{
    NodeList children = node.getChildNodes();
    for(int i = 0; i < children.getLength(); ++i) {
        Node child = children.item(i);
        if(child.getNodeType() == Node.TEXT_NODE) {
            if (child.getTextContent().trim().length() == 0) {
                child.getParentNode().removeChild(child);
                i--;
            }
        }
        stripEmptyElements(child);
    }
}

Java8+transformer does not create any but Java10+transformer puts everywhere empty lines. I still want to keep a pretty indents. This is my helper function to create xml string from any DOMElement instance such as doc.getDocumentElement() root node.

public static String createXML(Element elem) throws Exception {
        DOMSource source = new DOMSource(elem);
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        //transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
        //transformer.setOutputProperty("http://www.oracle.com/xml/is-standalone", "yes");
        transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"yes");
        transformer.setOutputProperty("http://www.oracle.com/xml/is-standalone", "yes");
        transformer.transform(source, result);

        // Java10-transformer adds unecessary empty lines, remove empty lines
        BufferedReader reader = new BufferedReader(new StringReader(writer.toString()));
        StringBuilder buf = new StringBuilder();
        try {
            final String NL = System.getProperty("line.separator", "\r\n");
            String line;
            while( (line=reader.readLine())!=null ) {
                if (!line.trim().isEmpty()) {
                    buf.append(line); 
                    buf.append(NL);
                }
            }
        } finally {
            reader.close();
        }
        return buf.toString();  //writer.toString();
    }

In order to strip whitespace and newlines from XML in Java try the following solution which uses StringBuffer() and conditional logic:

public static String LimpaXML(String xml) {
    StringBuffer result = new StringBuffer();
    char c_prev = '\0';
    xml = xml.trim();
    int len = xml.length();
    for (int i=0; i<len; i++) {
        char c = xml.charAt(i);
        char c_next = (i+1 < len) ? xml.charAt(i+1) : '\0';
        if (c == '\n') continue;
        if (c == '\r') continue;
        if (c == '\t') c = ' ';
        if (c == ' ') {
            if (c_prev == ' ') continue;
            if (c_next == '\0') continue;
            if (c_prev == '>') continue;
            if (c_next == '>') continue;
        }
        result.append(c);
        c_prev = c;
    }
    return result.toString();
}
Related