Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 3 of 5
We now need to write some Java code that will help us identify the <address> element in the source tree that needs to be replaced with the updated element. The findAddress() method below shows how that can be accomplished. Please note that, to keep the sample short, we've left out the appropriate
error handling.
public Node findAddress(String name, Document source) {
Element root = source.getDocumentElement();
NodeList nl = root.getChildNodes();
// iterate over all address nodes and find the one that has the correct addressee
for (int i=0;i<nl.getLength(); i++) {
Node n = nl.item(i);
if ((n.getNodeType() == Node.ELEMENT_NODE) &&
(((Element)n).getTagName().equals("address"))) {
// we have an address node, now we need to find the
// 'addressee' child
Node addressee = ((Element)n).getElementsByTagName("addressee").item(0);
// there is the addressee, now get the text node and compare
Node child = addressee.getChildNodes().item(0);
do {
if ((child.getNodeType()==Node.TEXT_NODE) &&
(((Text)child).getData().equals(name))) {
return n;
}
child = child.getNextSibling();
} while (child != null);
}
}
return null;
}
The code above could most likely be optimized, but it is obvious that iterating over the DOM tree can be tedious and error prone. Now let's look at how the target node can be located by using a simple XPath statement. The statement could look like this:
//address[child::addressee[text() = 'Jim Smith']]
We can now rewrite our previous method. This time, we use the XPath statement to find the desired node:
public Node findAddress(String name, Document source) throws Exception {
// need to recreate a few helper objects
XMLParserLiaison xpathSupport = new XMLParserLiaisonDefault();
XPathProcessor xpathParser = new XPathProcessorImpl(xpathSupport);
PrefixResolver prefixResolver = new PrefixResolverDefault(source.getDocumentElement());
// create the XPath and initialize it
XPath xp = new XPath();
String xpString = "//address[child::addressee[text() = '"+name+"']]";
xpathParser.initXPath(xp, xpString, prefixResolver);
// now execute the XPath select statement
XObject list = xp.execute(xpathSupport, source.getDocumentElement(), prefixResolver);
// return the resulting node
return list.nodeset().item(0);
}
The above code may not look a lot better than the previous try, but most of this method's contents could be encapsulated in a helper class. The only part that changes over and over is the actual XPath expression and the target node.
This lets us create an XPathHelper class, which looks like this:
import org.w3c.dom.*;
import org.xml.sax.*;
import org.apache.xalan.xpath.*;
import org.apache.xalan.xpath.xml.*;
public class XPathHelper {
XMLParserLiaison xpathSupport = null;
XPathProcessor xpathParser = null;
PrefixResolver prefixResolver = null;
XPathHelper() {
xpathSupport = new XMLParserLiaisonDefault();
xpathParser = new XPathProcessorImpl(xpathSupport);
}
public NodeList processXPath(String xpath, Node target) thrws SAXException {
prefixResolver = new PrefixResolverDefault(target);
// create the XPath and initialize it
XPath xp = new XPath();
xpathParser.initXPath(xp, xpath, prefixResolver);
// now execute the XPath select statement
XObject list = xp.execute(xpathSupport, target, prefixResolver);
// return the resulting node
return list.nodeset();
}
}
After creating the helper class, we can rewrite our finder method again, which is now very short: