Created
June 25, 2011 22:20
-
-
Save jnegre/1046969 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.