2013-10-25 126 views
25

我想在Java中使用for-each循环遍历NodeList。我使用for循环和do-while循环,但不是for-each循环。我可以使用for-each在Java中迭代NodeList吗?

NodeList nList = dom.getElementsByTagName("year"); 
do { 
    Element ele = (Element) nList.item(i); 
    list.add(ele.getElementsByTagName("MonthId").item(0).getTextContent()); 
    i++; 
} while (i < nList.getLength()); 

NodeList nList = dom.getElementsByTagName("year"); 

for (int i = 0; i < nList.getLength(); i++) { 
    Element ele = (Element) nList.item(i); 
    list.add(ele.getElementsByTagName("MonthId").item(0).getTextContent()); 
} 
+1

您不能对NodeList使用foreach循环,因为它没有实现Iterable接口。只有选项,您可以使用nodeList.getLength使用for或while循环。 http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/NodeList.html –

+3

虽然这是与你问的问题相切,但我会避开使用w3c来自Java标准库的东西。国际海事组织这是一个热门的混乱,有更好的XML解析库在那里。 – Jazzepi

+0

+ Jazzepi我知道这是一个老话题,但是您建议使用哪种XML解析库?注意这个w3c库没有提供一个简单而通用的迭代器的事实是一个“细节”,但看起来像是针对这个东西的多一个参数(即使选择一个库可能比这个更复杂)。 –

回答

33

解决此问题的方法非常简单,谢天谢地,您只需要实现一次。

import java.util.*; 
import org.w3c.dom.*; 

public final class XmlUtil { 
    private XmlUtil(){} 

    public static List<Node> asList(NodeList n) { 
    return n.getLength()==0? 
     Collections.<Node>emptyList(): new NodeListWrapper(n); 
    } 
    static final class NodeListWrapper extends AbstractList<Node> 
    implements RandomAccess { 
    private final NodeList list; 
    NodeListWrapper(NodeList l) { 
     list=l; 
    } 
    public Node get(int index) { 
     return list.item(index); 
    } 
    public int size() { 
     return list.getLength(); 
    } 
    } 
} 

一旦你添加了这个工具类项目,并增加了一个staticimportXmlUtil.asList法源代码,你可以使用它像这样:

for(Node n: asList(dom.getElementsByTagName("year"))) { 
    … 
} 
+0

真的很有用! :) – AweSIM

2

NodeList没有实现Iterable,所以你不能使用增强for循环使用。

5

由于NodeList只是一个接口,您可以创建一个类,该类将实现NodeListIterable,以遍历它。

5
public static Iterable<Node> iterable(final NodeList n) { 
    return new Iterable<Node>() { 

    @Override 
    public Iterator<Node> iterator() { 

     return new Iterator<Node>() { 

     int index = 0; 

     @Override 
     public boolean hasNext() { 
      return index < n.getLength(); 
     } 

     @Override 
     public Node next() { 
      if (hasNext()) { 
      return n.item(index++); 
      } else { 
      throw new NoSuchElementException(); 
      } 
     } 

     @Override 
     public void remove() { 
      throw new UnsupportedOperationException(); 
     } 
     }; 
    } 
    }; 
} 
+0

从这里:https://odoepner.wordpress.com/2012/07/13/turn-org-w3c-dom-nodelist-into-iterable/ –

1

如果当前DOM元素在迭代NodeList(通过getElementsByTagName()和其他元素创建)时被删除(通过JavaScript),元素将从NodeList中消失。这使得NodeList的正确迭代更加棘手。

public class IteratableNodeList implements Iterable<Node> { 
    final NodeList nodeList; 
    public IteratableNodeList(final NodeList _nodeList) { 
     nodeList = _nodeList; 
    } 
    @Override 
    public Iterator<Node> iterator() { 
     return new Iterator<Node>() { 
      private int index = -1; 
      private Node lastNode = null; 
      private boolean isCurrentReplaced() { 
       return lastNode != null && index < nodeList.getLength() && 
         lastNode != nodeList.item(index); 
      } 

      @Override 
      public boolean hasNext() { 
       return index + 1 < nodeList.getLength() || isCurrentReplaced(); 
      } 

      @Override 
      public Node next() { 
       if (hasNext()) { 
        if (isCurrentReplaced()) { 
         // It got removed by a change in the DOM. 
         lastNode = nodeList.item(index); 
        } else { 
         lastNode = nodeList.item(++index); 
        } 
        return lastNode; 
       } else { 
        throw new NoSuchElementException(); 
       } 
      } 

      @Override 
      public void remove() { 
       throw new UnsupportedOperationException(); 
      } 
     }; 
    } 

    public Stream<Node> stream() { 
     Spliterator<Node> spliterator = 
      Spliterators.spliterator(iterator(), nodeList.getLength(), 0); 
     return StreamSupport.stream(spliterator, false); 
    } 
} 

然后使用它是这样的: new IteratableNodeList(doc.getElementsByTagName(elementType)). stream().filter(...)

或者: new IteratableNodeList(doc.getElementsByTagName(elementType)).forEach(...)

0

添加快乐的小科特林版本sience:

fun NodeList.forEach(action: (Node) -> Unit) { 
    (0 until this.length) 
      .asSequence() 
      .map { this.item(it) } 
      .forEach { action(it) } 
} 

人们可以再用nodeList.forEach { do_something_awesome() }使用

0

我知道这是迟到了,但是...
由于Java-8则可以通过使用lambda表达式写@RayHulha's solution更加简洁(用于创建新Iterable)和默认方法(Iterator.remove):

public static Iterable<Node> iterable(final NodeList nodeList) { 
    return() -> new Iterator<Node>() { 

     private int index = 0; 

     @Override 
     public boolean hasNext() { 
      return index < nodeList.getLength(); 
     } 

     @Override 
     public Node next() { 
      if (!hasNext()) 
       throw new NoSuchElementException(); 
      return nodeList.item(index++); 
     } 
    }; 
} 

,然后用它是这样的:

NodeList nodeList = ...; 
for (Node node : iterable(nodeList)) { 
    // .... 
} 

或等价这样的:

NodeList nodeList = ...; 
iterable(nodeList).forEach(node -> { 
    // .... 
}); 
相关问题