Skip to content

Commit 3982486

Browse files
XML Pretty printer with for pretty printing text contents and aligning closing tags
1 parent f4d5f44 commit 3982486

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* ModifiableVariable - A Variable Concept for Runtime Modifications
3+
*
4+
* Copyright 2014-2017 Ruhr University Bochum / Hackmanit GmbH
5+
*
6+
* Licensed under Apache License 2.0
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*/
9+
package de.rub.nds.modifiablevariable.util;
10+
11+
import java.io.IOException;
12+
import java.io.StringReader;
13+
import java.io.StringWriter;
14+
import java.util.Arrays;
15+
import javax.xml.parsers.DocumentBuilderFactory;
16+
import javax.xml.parsers.ParserConfigurationException;
17+
import javax.xml.transform.OutputKeys;
18+
import javax.xml.transform.Transformer;
19+
import javax.xml.transform.TransformerConfigurationException;
20+
import javax.xml.transform.TransformerException;
21+
import javax.xml.transform.TransformerFactory;
22+
import javax.xml.transform.dom.DOMSource;
23+
import javax.xml.transform.stream.StreamResult;
24+
import javax.xml.xpath.XPathConstants;
25+
import javax.xml.xpath.XPathExpression;
26+
import javax.xml.xpath.XPathExpressionException;
27+
import javax.xml.xpath.XPathFactory;
28+
import org.w3c.dom.Document;
29+
import org.w3c.dom.NodeList;
30+
import org.xml.sax.InputSource;
31+
import org.xml.sax.SAXException;
32+
33+
/**
34+
* The goal of this class is to pretty print byte array text nodes so that text
35+
* contents and closing XML tags are correctly aligned.
36+
*
37+
* Juraj Somorovsky <juraj.somorovsky@rub.de>
38+
*/
39+
public class XMLPrettyPrinter {
40+
41+
public static int IDENT_AMOUNT = 4;
42+
43+
public static String prettyPrintXML(String input) throws TransformerConfigurationException,
44+
ParserConfigurationException, SAXException, IOException, TransformerException, XPathExpressionException {
45+
Transformer transformer = TransformerFactory.newInstance().newTransformer();
46+
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
47+
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", Integer.toString(IDENT_AMOUNT));
48+
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
49+
50+
StreamResult result = new StreamResult(new StringWriter());
51+
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
52+
.parse(new InputSource(new StringReader(input)));
53+
54+
// XPath for selecting all text contents
55+
XPathExpression xpath = XPathFactory.newInstance().newXPath().compile("//*[text()]/*");
56+
// XPath for counting the number of ancestors of a current element
57+
XPathExpression xpathDepth = XPathFactory.newInstance().newXPath().compile("count(ancestor-or-self::*)");
58+
59+
NodeList textNodes = (NodeList) xpath.evaluate(doc, XPathConstants.NODESET);
60+
61+
for (int i = 0; i < textNodes.getLength(); i++) {
62+
String content = textNodes.item(i).getTextContent();
63+
System.out.println(textNodes.item(i).getTextContent());
64+
double doubleDepth = (Double) xpathDepth.evaluate(textNodes.item(i), XPathConstants.NUMBER);
65+
int depth = (int) doubleDepth;
66+
String emptyString = createEmptyString(depth);
67+
System.out.println(depth);
68+
String newContent = content.replaceAll("\n", ("\n" + emptyString));
69+
// remove last white space elements from the text content to align
70+
// the closing tag
71+
if (newContent.length() > content.length()) {
72+
newContent = newContent.substring(0, newContent.length() - IDENT_AMOUNT);
73+
}
74+
textNodes.item(i).setTextContent(newContent);
75+
}
76+
77+
DOMSource source = new DOMSource(doc);
78+
transformer.transform(source, result);
79+
return result.getWriter().toString();
80+
}
81+
82+
private static String createEmptyString(int depth) {
83+
char[] charArray = new char[depth * IDENT_AMOUNT];
84+
Arrays.fill(charArray, ' ');
85+
return new String(charArray);
86+
}
87+
88+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* ModifiableVariable - A Variable Concept for Runtime Modifications
3+
*
4+
* Copyright 2014-2017 Ruhr University Bochum / Hackmanit GmbH
5+
*
6+
* Licensed under Apache License 2.0
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*/
9+
package de.rub.nds.modifiablevariable.util;
10+
11+
import org.junit.Test;
12+
import static org.junit.Assert.*;
13+
14+
/**
15+
*
16+
*/
17+
public class XMLPrettyPrinterTest {
18+
19+
/**
20+
* Test of prettyPrintXML method, of class XMLPrettyPrinter.
21+
*/
22+
@Test
23+
public void testPrettyPrintXML() throws Exception {
24+
String input = "<modifiableByteArray>\n" + " <originalValue>\n"
25+
+ "FF 01 02 03 FF 01 02 03 FF 01 02 03 FF 01 02 03\n" + "FF 01 02 03\n" + "</originalValue>\n"
26+
+ "</modifiableByteArray>";
27+
String expected = "<modifiableByteArray>\n" + " <originalValue>\n"
28+
+ " FF 01 02 03 FF 01 02 03 FF 01 02 03 FF 01 02 03\n" + " FF 01 02 03\n"
29+
+ " </originalValue>\n" + "</modifiableByteArray>";
30+
String result = XMLPrettyPrinter.prettyPrintXML(input);
31+
32+
assertEquals(expected.trim(), result.trim());
33+
}
34+
35+
}

0 commit comments

Comments
 (0)