Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to let Java.xml.Transformer output a xml without any useless space or line break?

Tags:

java

xml

jaxp

My Code Now:

import org.w3c.dom.Node;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;

private String getStringByJAXP(Node input) {
        StreamResult xmlOutput;
        try {
            xmlOutput = new StreamResult(new StringWriter());
            transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.transform(new DOMSource(input), xmlOutput);
        } catch (TransformerException e) {
            throw new IllegalArgumentException();
        }
        return xmlOutput.getWriter().toString();
    }

Output:

<aaa>
    <a>text a</a>
    <b>
        <c>text c</c>
    </b>
    <f>
        <g><h a="xxx"/></g>
    </f>
</aaa>

But I want to output as follows:

<aaa><a>text a</a><b><c>text c</c></b><f><g><h a="xxx" /></g></f></aaa>

Notice that I can't do that task by some simple string replaces, because the space in <a>text a</a> shouldn't be replaced(<a>texta</a> is total different from <a>text a</a>).

EDIT:

OutputKeys.INDENT, "no" not works. Updated code:

private String getStringByJAXP(Node input) {
    StreamResult xmlOutput;
    try {
        xmlOutput = new StreamResult(new StringWriter());
        transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.transform(new DOMSource(input), xmlOutput);
    } catch (TransformerException e) {
        throw new IllegalArgumentException();
    }
    return xmlOutput.getWriter().toString();
}
like image 602
Sayakiss Avatar asked Nov 06 '15 09:11

Sayakiss


2 Answers

I had a similar case once. I tried transformer.setOutputProperty(OutputKeys.INDENT,"no"); first, but this did not work. The problem was that my original node had additional "new line" text nodes.

The answer to Strip whitespace and newlines from XML in Java fixed it for me. Basically, you just remove the unnecessary text nodes before you transform the parent node.

I ended up using this:

public static void trimWhitespace(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) {
            child.setTextContent(child.getTextContent().trim());
        }
        trimWhitespace(child);
    }
}
like image 175
Integrating Stuff Avatar answered Nov 17 '22 23:11

Integrating Stuff


You can pass an XSLT stylesheet to your Transformer which has the advantage that you will not have to parse your document twice.

InputStream xsltStream = getClass().getResourceAsStream("trim-whitespace.xslt");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(new StreamSource(xsltStream));

trim-whitespace.xslt

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- copy all elements as they are -->
    <xsl:template match="*">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*/text()[not(normalize-space())]" />
</xsl:stylesheet>
like image 3
Jan Šimek Avatar answered Nov 18 '22 00:11

Jan Šimek