2013-10-25 129 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 -> { 
    // .... 
}); 
相關問題