Add support for pretty printing XML fragments
Change-Id: I085e2e883cf445bfa406b0ae753df605b9929540
diff --git a/utils/misc/src/main/java/org/onlab/util/XmlString.java b/utils/misc/src/main/java/org/onlab/util/XmlString.java
index 9ffc0e2..2286747 100644
--- a/utils/misc/src/main/java/org/onlab/util/XmlString.java
+++ b/utils/misc/src/main/java/org/onlab/util/XmlString.java
@@ -18,6 +18,7 @@
import java.io.IOException;
import java.io.StringWriter;
+import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
@@ -34,6 +35,9 @@
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.io.CharSource;
@@ -64,9 +68,33 @@
private String prettyPrintXml(CharSource inputXml) {
try {
- Document document = DocumentBuilderFactory.newInstance()
- .newDocumentBuilder()
- .parse(new InputSource(inputXml.openStream()));
+ Document document;
+ boolean wasFragment = false;
+
+ DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance()
+ .newDocumentBuilder();
+ // do not print error to stderr
+ docBuilder.setErrorHandler(new DefaultHandler());
+
+ try {
+ document = docBuilder
+ .parse(new InputSource(inputXml.openStream()));
+ } catch (SAXException e) {
+ log.debug("will retry assuming input is XML fragment", e);
+ // attempt to parse XML fragments, adding virtual root
+ try {
+ document = docBuilder
+ .parse(new InputSource(CharSource.concat(CharSource.wrap("<vroot>"),
+ inputXml,
+ CharSource.wrap("</vroot>")
+ ).openStream()));
+ wasFragment = true;
+ } catch (SAXException e1) {
+ log.debug("SAXException after retry", e1);
+ // Probably wasn't fragment issue, throwing original
+ throw e;
+ }
+ }
document.normalize();
@@ -89,7 +117,15 @@
// Return pretty print xml string
StringWriter strWriter = new StringWriter();
- t.transform(new DOMSource(document), new StreamResult(strWriter));
+ if (wasFragment) {
+ // print everything but virtual root node added
+ NodeList children = document.getDocumentElement().getChildNodes();
+ for (int i = 0; i < children.getLength(); ++i) {
+ t.transform(new DOMSource(children.item(i)), new StreamResult(strWriter));
+ }
+ } else {
+ t.transform(new DOMSource(document), new StreamResult(strWriter));
+ }
return strWriter.toString();
} catch (Exception e) {
log.warn("Pretty printing failed", e);
diff --git a/utils/misc/src/test/java/org/onlab/util/XmlStringTest.java b/utils/misc/src/test/java/org/onlab/util/XmlStringTest.java
index b09c44d..16954e5 100644
--- a/utils/misc/src/test/java/org/onlab/util/XmlStringTest.java
+++ b/utils/misc/src/test/java/org/onlab/util/XmlStringTest.java
@@ -41,4 +41,12 @@
assertEquals(input, XmlString.prettifyXml(input).toString());
}
+ @Test
+ public void fragments() {
+ String input = "<root/> <a some='foo '/>";
+ String expected = "<root/>\n"
+ + "<a some=\"foo \"/>\n";
+ assertEquals(expected, XmlString.prettifyXml(input).toString());
+ }
+
}