001    /* JAPI - (Yet another (hopefully) useful) Java API
002     *
003     * Copyright (C) 2004-2006 Christian Hujer
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License as
007     * published by the Free Software Foundation; either version 2 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful, but
011     * WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013     * General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018     * 02111-1307, USA.
019     */
020    
021    package net.sf.japi.xml;
022    
023    import java.util.Iterator;
024    import java.util.NoSuchElementException;
025    import javax.xml.xpath.XPath;
026    import static javax.xml.xpath.XPathConstants.NODESET;
027    import javax.xml.xpath.XPathExpressionException;
028    import org.w3c.dom.Element;
029    import org.w3c.dom.Node;
030    import static org.w3c.dom.Node.ELEMENT_NODE;
031    import org.w3c.dom.NodeList;
032    import org.jetbrains.annotations.Nullable;
033    import org.jetbrains.annotations.NotNull;
034    
035    /** A combined iterable / iterator implementation for iterating over NodeLists.
036     * @author <a href="mailto:chris@riedquat.de">Christian Hujer</a>
037     */
038    public class NodeListIterator<T extends Node> implements Iterable<T>, Iterator<T> {
039    
040        /** The NodeList to iterate over. */
041        @NotNull private final NodeList nodeList;
042    
043        /** Index of next element. */
044        private int index;
045    
046        /** Convenience helper method for getting the first child of an element that is an element with a specific name.
047         * @param el element to get child of
048         * @param childName name of child element to get
049         * @return child element or <code>null</code> if no such child element
050         */
051        @Nullable public static Element getFirstChild(final Element el, final String childName) {
052            final NodeList childNodes = el.getChildNodes();
053            final int count = childNodes.getLength();
054            for (int i = 0; i < count; i++) {
055                final Node node = childNodes.item(i);
056                if (node.getNodeType() == ELEMENT_NODE && node.getNodeName().equals(childName)) {
057                    return (Element) node;
058                }
059            }
060            return null;
061        }
062    
063        /** Create a NodeListIterator.
064         * @param nodeList NodeList to iterate over
065         */
066        public NodeListIterator(@NotNull final NodeList nodeList) {
067            this.nodeList = nodeList;
068        }
069    
070        /** Create a NodeListIterator.
071         * @param item Element to evaluate against
072         * @param nodeType node type of children
073         */
074        public NodeListIterator(@NotNull final Element item, final short nodeType) {
075            this(new FilteredNodeList<T>(item, nodeType));
076        }
077    
078        /** Create a NodeListIterator.
079         * @param item Element to evaluate against
080         * @param childName name of child element
081         */
082        public NodeListIterator(@NotNull final Element item, @NotNull final String childName) {
083            this(new FilteredNodeList<T>(item, childName));
084        }
085    
086        /** Create a NodeListIterator.
087         * @param xpath XPath to evaulate against
088         * @param item Object to evaluate against
089         * @param expression XPath expression to evaluate
090         * @throws XPathExpressionException in case of xpath errors
091         */
092        public NodeListIterator(@NotNull final XPath xpath, @NotNull final Element item, @NotNull final String expression) throws XPathExpressionException {
093            this((NodeList) xpath.evaluate(expression, item, NODESET));
094        }
095    
096        /** {@inheritDoc} */
097        @NotNull public Iterator<T> iterator() {
098            return this;
099        }
100    
101        /** {@inheritDoc} */
102        public boolean hasNext() {
103            return index < nodeList.getLength();
104        }
105    
106        /** {@inheritDoc} */
107        @NotNull public T next() throws NoSuchElementException {
108            //noinspection unchecked
109            final T item = (T) nodeList.item(index++);
110            if (item == null) {
111                throw new NoSuchElementException();
112            }
113            return item;
114        }
115    
116        /** {@inheritDoc} */
117        public void remove() {
118            throw new UnsupportedOperationException();
119        }
120    
121        /** Get the number of elements this iterator would iterate over all.
122         * @return number of elements
123         */
124        public int size() {
125            return nodeList.getLength();
126        }
127    
128    } // class NodeListIterator