I want to write a simple method in Java to convert XML to some user-friendly plain format (like YAML, etc.).
Attributes, null, empty or zero values should not be taken into account. Also, documents with containing mixed content (or comments or processing instructions) should not be parsed/passed into. This should provide the user with a quick overview of the data. Backward conversion is not necessary.
Example:
Input:
<?xml version="1.0" encoding="UTF-8"?>
<e>
<foo>
<bar>Tari</bar>
</foo>
<baz>
<qux>
<quux>i gdht</quux>
</qux>
</baz>
<corge>2073</corge>
<grault>
<garply>
<waldo>29856</waldo>
<fred>13:05:36</fred>
<plugh>Swaziland</plugh>
</garply>
</grault>
</e>
Output:
#document:
e:
foo:
bar: Tari
baz:
qux:
quux: i gdht
corge: 2073
grault:
garply:
waldo: 29856
fred: 13:05:36
plugh: Swaziland
Is my recursive docToText()
method all right, or is there a smell?
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class XMLProcessing {
public static Document getDocFromXmlString(String xml)
throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
}
public static StringBuilder docToText(Node doc, int indent, StringBuilder result) {
if (doc.hasChildNodes()) {
if (doc.getChildNodes().getLength() == 1 && !doc.getChildNodes().item(0).hasChildNodes()) {
String textContent = doc.getTextContent();
if (textContent != null && !textContent.isBlank() && !"0".equals(textContent)) {
result
.append(" ".repeat(indent))
.append(doc.getNodeName())
.append(": ")
.append(textContent)
.append("\n");
}
} else {
result.append(" ".repeat(indent)).append(doc.getNodeName()).append(":\n");
NodeList list = doc.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
docToText(list.item(i), indent + 2, result);
}
}
}
return result;
}
public static void test() throws ParserConfigurationException, IOException, SAXException {
String inputXml =
"""
<?xml version="1.0" encoding="UTF-8"?>
<e>
<foo>
<bar>Tari</bar>
</foo>
<baz>
<qux>
<quux>i gdht</quux>
</qux>
</baz>
<corge>2073</corge>
<grault>
<garply>
<waldo>29856</waldo>
<fred>13:05:36</fred>
<plugh>Swaziland</plugh>
</garply>
</grault>
</e>
""";
String outputText =
"""
#document:
e:
foo:
bar: Tari
baz:
qux:
quux: i gdht
corge: 2073
grault:
garply:
waldo: 29856
fred: 13:05:36
plugh: Swaziland
""";
assert outputText.contentEquals(
docToText(getDocFromXmlString(inputXml), 0, new StringBuilder()));
}
public static void main(String[] args)
throws ParserConfigurationException, IOException, SAXException {
test();
}
}