Can I iterate through a NodeList using for-each in Java?

前端 未结 10 1101
没有蜡笔的小新
没有蜡笔的小新 2020-12-09 00:55

I want to iterate through a NodeList using a for-each loop in Java. I have it working with a for loop and a do-while loop but not for-each.

Node         


        
相关标签:
10条回答
  • 2020-12-09 01:33

    NodeList does not implement Iterable, so you cannot use it with the enhanced for loop.

    0 讨论(0)
  • 2020-12-09 01:38

    If the current DOM element is removed (via JavaScript) while iterating a NodeList (created from getElementsByTagName() and maybe others), the element will disappear from the NodeList. This makes correct iteration of the NodeList more tricky.

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

    Then use it like this: new IteratableNodeList(doc.getElementsByTagName(elementType)). stream().filter(...)

    Or: new IteratableNodeList(doc.getElementsByTagName(elementType)).forEach(...)

    0 讨论(0)
  • 2020-12-09 01:47

    The workaround for this problem is straight-forward, and, thankfully you have to implements it only once.

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

    Once you have added this utility class to your project and added a static import for the XmlUtil.asList method to your source code you can use it like this:

    for(Node n: asList(dom.getElementsByTagName("year"))) {
      …
    }
    
    0 讨论(0)
  • 2020-12-09 01:47

    One can use the Java8 stream to iterate the NodeList.

    NodeList filterList = source.getChildNodes();
    
    IntStream.range(0, filterList.getLength()).boxed().map(filterList::item).forEach(node -> {
    
    
    });
    
    0 讨论(0)
提交回复
热议问题