Skip to content

Instantly share code, notes, and snippets.

@jnegre
Created June 25, 2011 22:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jnegre/1046969 to your computer and use it in GitHub Desktop.
Save jnegre/1046969 to your computer and use it in GitHub Desktop.
package org.jnegre;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Benchmark to illustrate http://www.jnegre.org/news/2011/06/26/beware_of_javax_xml_xpath.html
*
* @author Jerome Negre
*/
public class XpathVsDom {
private static XPath xpath = XPathFactory.newInstance().newXPath();
private final static int SIZE = 20000;
private final static int DELTA = 100;
public static void main(String[] args) throws Exception {
long time;
Document doc = createDoc(SIZE);
NodeList children = doc.getDocumentElement().getChildNodes();
if(children.getLength() != SIZE) {
throw new Exception("Something's fishy");
}
//warm-up + check that we get the same result from both methods
for(int i=0; i<SIZE; i+=DELTA) {
Node root = children.item(i);
Node n1 = getChildDom(root, "a");
Node n2 = getChildXPath(root, "a");
if(n1 == null || !n1.equals(n2)) {
throw new Exception("Something's fishy");
}
}
time = System.currentTimeMillis();
for(int i=0; i<SIZE; i+=DELTA) {
getChildDom(children.item(i), "a");
}
System.out.println("Children were found using DOM in "+(System.currentTimeMillis()-time)+" ms");
time = System.currentTimeMillis();
for(int i=0; i<SIZE; i+=DELTA) {
getChildXPath(children.item(i), "a");
}
System.out.println("Children were found using XPath in "+(System.currentTimeMillis()-time)+" ms");
}
/**
* Create a Document to query
*/
private static Document createDoc(int size) throws Exception {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Node root = doc.appendChild(doc.createElement("root"));
for(int i=0; i<size; i++) {
Node child = root.appendChild(doc.createElement("child"+i));
child.appendChild(doc.createElement("a")).appendChild(doc.createTextNode("pick me"));
child.appendChild(doc.createElement("b")).appendChild(doc.createTextNode("lorem"));
child.appendChild(doc.createElement("c")).appendChild(doc.createTextNode("ipsum"));
}
return doc;
}
/**
* Returns the direct child of parent with the given name using XPath
*/
private static Node getChildXPath(Node parent, String name) throws Exception {
return (Node)xpath.evaluate(name, parent, XPathConstants.NODE);
}
/**
* Returns the direct child of parent with the given name using getChildNodes()
*/
private static Node getChildDom(Node parent, String name) throws Exception {
NodeList list = parent.getChildNodes();
for(int i=0; i<list.getLength(); i++) {
Node child = list.item(i);
if(child.getNodeType() == Node.ELEMENT_NODE && name.equals(child.getNodeName())) {
return child;
}
}
return null;
}
}
@tobidope
Copy link

tobidope commented Feb 3, 2017

I know this is really old, but xpath is not that bad. You would query differently. You would get all nodes at once with
nl = getChildXPath(doc, "//a"); // and changing to NODESET
Its still much slower (200ms to 130ms) than pure DOM, but once you need more, it should be easier to do with xpath than with pure DOM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment