2011-03-22 128 views
57

在Java中遍历所有DOM元素的最有效方法是什么?Java:最有效的方法来遍历org.w3c.dom.Document中的所有元素?

像这样的东西,但对于目前的每个DOM元素org.w3c.dom.Document

for(Node childNode = node.getFirstChild(); childNode!=null;){ 
    Node nextChild = childNode.getNextSibling(); 
    // Do something with childNode, including move or delete... 
    childNode = nextChild; 
} 
+0

递归调用? http://download.oracle.com/javase/6/docs/api/org/w3c/dom/Node.html#getChildNodes%28%29 – 2011-03-22 05:38:36

回答

102

基本上你有两种方法来遍历所有元素:

1.使用递归(最常见的方式,我认为):

public static void main(String[] args) throws SAXException, IOException, 
     ParserConfigurationException, TransformerException { 

    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory 
     .newInstance(); 
    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); 
    Document document = docBuilder.parse(new File("document.xml")); 
    doSomething(document.getDocumentElement()); 
} 

public static void doSomething(Node node) { 
    // do something with the current node instead of System.out 
    System.out.println(node.getNodeName()); 

    NodeList nodeList = node.getChildNodes(); 
    for (int i = 0; i < nodeList.getLength(); i++) { 
     Node currentNode = nodeList.item(i); 
     if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 
      //calls this method for all the children which is Element 
      doSomething(currentNode); 
     } 
    } 
} 

2.避免递归采用getElementsByTagName()方法*作为参数:

public static void main(String[] args) throws SAXException, IOException, 
     ParserConfigurationException, TransformerException { 

    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory 
      .newInstance(); 
    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); 
    Document document = docBuilder.parse(new File("document.xml")); 

    NodeList nodeList = document.getElementsByTagName("*"); 
    for (int i = 0; i < nodeList.getLength(); i++) { 
     Node node = nodeList.item(i); 
     if (node.getNodeType() == Node.ELEMENT_NODE) { 
      // do something with the current element 
      System.out.println(node.getNodeName()); 
     } 
    } 
} 

我认为这些方法都是有效的。
希望这会有所帮助。

+10

将迭代索引作为参数传递给递归函数,您可以将它tail-recursive,这是由编译器优化的,以避免堆栈溢出。 – khachik 2011-04-03 18:30:47

+95

我认为避免堆栈溢出为时已晚。你已经在这里了。 – braden 2012-09-28 17:19:54

+1

是什么让您认为为整个文档创建节点列表是有效的?这意味着几乎要复制整个文档。或者是否有某种隐藏在'NodeList'中的延迟评估优化了对'item'的连续调用? – ceving 2013-03-07 18:17:05

32

​​

变化到

for (int i = 0, len = nodeList.getLength(); i < len; i++)

更有效率。 第二种方式可能是最好的,因为它倾向于使用更平坦,可预测的内存模型。

+1

您需要至少50个评分才能发表评论。我有同样的问题,并回答,因为我无法评论。有一些upvote-aid;) – nyaray 2013-07-11 16:54:24

+2

编译器不会优化? :-P – whomaniac 2015-06-21 07:20:21

2

最近我也偶然发现了这个问题。这是我的解决方案。 我想避免递归,所以我使用了一个while循环。

由于在列表中的任意位置添加和删除,我使用了LinkedList实现。

Node.getChildNodes的
/* traverses tree starting with given node */ 
    private static List<Node> traverse(Node n) 
    { 
    return traverse(Arrays.asList(n)); 
    } 

    /* traverses tree starting with given nodes */ 
    private static List<Node> traverse(List<Node> nodes) 
    { 
    List<Node> open = new LinkedList<Node>(nodes); 
    List<Node> visited = new LinkedList<Node>(); 

    ListIterator<Node> it = open.listIterator(); 
    while (it.hasNext() || it.hasPrevious()) 
    { 
     Node unvisited; 
     if (it.hasNext()) 
     unvisited = it.next(); 
     else 
     unvisited = it.previous(); 

     it.remove(); 

     List<Node> children = getChildren(unvisited); 
     for (Node child : children) 
     it.add(child); 

     visited.add(unvisited); 
    } 

    return visited; 
    } 

    private static List<Node> getChildren(Node n) 
    { 
    List<Node> children = asList(n.getChildNodes()); 
    Iterator<Node> it = children.iterator(); 
    while (it.hasNext()) 
     if (it.next().getNodeType() != Node.ELEMENT_NODE) 
     it.remove(); 
    return children; 
    } 

    private static List<Node> asList(NodeList nodes) 
    { 
    List<Node> list = new ArrayList<Node>(nodes.getLength()); 
    for (int i = 0, l = nodes.getLength(); i < l; i++) 
     list.add(nodes.item(i)); 
    return list; 
    } 
相关问题