2013-10-25 13 views
25

Tôi muốn lặp qua một số NodeList bằng cách sử dụng vòng lặp for-each trong Java. Tôi có nó làm việc với một vòng lặp for và một vòng lặp do-while nhưng không phải cho mỗi.Tôi có thể lặp qua NodeList bằng cách sử dụng cho mỗi trong Java?

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

Bạn không thể sử dụng vòng lặp foreach cho NodeList vì nó không thực hiện giao diện Iterable. Chỉ có tùy chọn bạn có nó để sử dụng vòng lặp for hoặc while khi sử dụng nodeList.getLength. http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/NodeList.html –

+3

Trong khi điều này là tiếp tuyến với câu hỏi bạn đang hỏi, tôi sẽ tránh xa việc sử dụng w3c công cụ từ thư viện chuẩn Java. IMO đó là một mớ hỗn độn nóng và có nhiều thư viện phân tích cú pháp XML tốt hơn trên mạng. – Jazzepi

+0

+ Jazzepi Tôi biết đó là chủ đề cũ nhưng bạn đề xuất thư viện phân tích cú pháp XML nào?NB Thực tế là thư viện w3c này không cung cấp một Iterator đơn giản và chung chung là một "chi tiết" nhưng trông giống như một đối số khác chống lại công cụ này (ngay cả khi sự lựa chọn của một thư viện có thể phức tạp hơn điểm này). –

Trả lời

33

Giải pháp cho vấn đề này là thẳng về phía trước và thật may là bạn chỉ phải thực hiện nó một lần.

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(); 
    } 
    } 
} 

Một khi bạn đã thêm lớp tiện ích này để dự án của bạn và thêm một staticimport cho phương pháp XmlUtil.asList vào mã nguồn của bạn, bạn có thể sử dụng nó như thế này:

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

thực sự hữu ích !!! :) – AweSIM

2

NodeList không thực hiện Iterable, vì vậy bạn không thể sử dụng nó với sự tăng cường for vòng lặp.

5

NodeList chỉ là một giao diện, bạn có thể tạo một lớp sẽ triển khai cả hai NodeListIterable, để lặp qua nó.

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

Từ đây: https://odoepner.wordpress.com/2012/07/13/turn-org-w3c-dom-nodelist-into-iterable/ –

1

Nếu hiện tại Phần tử DOM được loại bỏ (thông qua JavaScript) trong khi lặp lại một NodeList (được tạo từ getElementsByTagName() và có thể là các phần tử khác), phần tử sẽ biến mất khỏi NodeList. Điều này làm cho việc lặp lại chính xác NodeList phức tạp hơn.

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); 
    } 
} 

Sau đó sử dụng nó như thế này: new IteratableNodeList(doc.getElementsByTagName(elementType)). stream().filter(...)

Hoặc: new IteratableNodeList(doc.getElementsByTagName(elementType)).forEach(...)

0

Thêm chút phiên bản Kotlin hạnh phúc cho Sience:

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

Người ta có thể sau đó sử dụng nó với nodeList.forEach { do_something_awesome() }

0

Tôi biết nó là muộn để đảng, nhưng ...
Kể từ Java-8 bạn có thể viết @RayHulha's solution thậm chí nhiều hơn chính xác bằng cách sử dụng biểu thức lambda (đối với việc tạo ra một mới Iterable) và phương pháp mặc định (ví 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++); 
     } 
    }; 
} 

và sau đó sử dụng nó như thế này:

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

hoặc tương đương như thế này:

NodeList nodeList = ...; 
iterable(nodeList).forEach(node -> { 
    // .... 
}); 
Các vấn đề liên quan