I have a need to extract a part of XML tree (everything under root
) and convert it to a string. (The result string will be later pasted inside XSL-FO
XSLT file.)
The above functionality is a part of Java 6 application. I use org.w3c.dom
and javax.xml.transform
. Still in the debugging process.
// ...
// Extract all child notes of root from foDoc
// and convert the result to String
Node root = foDoc.getElementsByTagNameNS("*","root").item(0);
NodeList body = root.getChildNodes();
String foResult;
try {
foResult = nodeListToString(body);
} catch (TransformerException e) {
logger.error(e);
foResult = "";
}
// ...
private static String nodeListToString(NodeList nodes) throws TransformerException {
StringBuilder result = new StringBuilder();
int len = nodes.getLength();
for(int i = 0; i < len; ++ i) {
result.append(nodeToString(nodes.item(i)));
}
return result.toString();
}
private static String nodeToString(Node node) throws TransformerException {
StringWriter buf = new StringWriter();
Transformer xform = TransformerFactory.newInstance().newTransformer();
xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
xform.transform(new DOMSource(node), new StreamResult(buf));
return(buf.toString());
}
My questions:
Assuming that there will always be exactly one
root
node, how reliable is my code in extracting everything under it?Am I missing any edge cases?
Anything just plain wrong?
Please disregard any exception handling inadequacies.
Edited on 10/06/2015
Since my originally posted code had a "just plain wrong" part, I've fixed it. There were no answers based on the old code.
-
2\$\begingroup\$ How committed are you to using DOM? I seldom just jump ion and recommend alternative tools, but, I maintain the JDOM library, and this sort of activity is easy if you can use JDOM instead..... just saying. \$\endgroup\$rolfl– rolfl2015年10月03日 21:56:24 +00:00Commented Oct 3, 2015 at 21:56
-
\$\begingroup\$ @rolfl - Thank you for the reference. I will keep it in mind for future projects. This time I am making a small change to a plugin for a huge system and need to stay within its existing tooling. \$\endgroup\$PM 77-1– PM 77-12015年10月06日 19:10:58 +00:00Commented Oct 6, 2015 at 19:10
1 Answer 1
Reading the documentation for
Transformer
,
where it says:
A Transformer may be used multiple times. Parameters and output properties are preserved across transformations.
, I'd say that not only can the Transformer
object be reused across
multiple nodes, but you should also be able to use a single
StringWriter
instead of recreating it for every node; same goes for
the DOMSource
actually:
private static String nodeListToString(NodeList nodes) throws TransformerException {
DOMSource source = new DOMSource();
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
for (int i = 0; i < nodes.getLength(); ++i) {
source.setNode(nodes.item(i));
transformer.transform(source, result);
}
return writer.toString();
}
That said, I'm only guessing that this should work.
Also, the len
variable is probably going to be inlined automatically
anyway, though you could check that with a disassembler just to be sure
(it wouldn't make that much of a difference I suspect).
Otherwise looks good to me; if you've tested it with all kinds of node types and the output looks good, then I'd say that should work IMHO.
-
\$\begingroup\$ I use
nodeToString()
in other places of my code as well. \$\endgroup\$PM 77-1– PM 77-12015年10月07日 21:04:29 +00:00Commented Oct 7, 2015 at 21:04 -
\$\begingroup\$ Then keep it in addition to this
nodeListToString
? I'm just assuming that inlining and removing allocations helps with bigger documents. \$\endgroup\$ferada– ferada2015年10月07日 21:26:18 +00:00Commented Oct 7, 2015 at 21:26 -
1\$\begingroup\$ I second that it looks strange to build a string in a
StringWriter
just so that it can be appended to aStringBuilder
in the caller. It would be better to reuse theStringWriter
. You could pass theStreamResult
object as a 2nd parameter intonodeListToString
\$\endgroup\$janos– janos2015年10月10日 20:21:07 +00:00Commented Oct 10, 2015 at 20:21