001    /* JAPI - (Yet anothr (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    
033    /** A combined iterable / iterator implementation for iterating over NodeLists.
034     * @author <a href="mailto:Christian.Hujer@itcqis.com">Christian Hujer</a>
035     */
036    public class NodeListIterator<T extends Node> implements Iterable<T>, Iterator<T> {
037    
038        /** The NodeList to iterate over. */
039        private final NodeList nodeList;
040    
041        /** Index of next element. */
042        private int index;
043    
044        /** Convenience helper method for getting the first child of an element that is an element with a specific name.
045         * @param el element to get child of
046         * @param childName name of child element to get
047         * @return child element or <code>null</code> if no such child element
048         */
049        public static Element getFirstChild(final Element el, final String childName) {
050            final NodeList childNodes = el.getChildNodes();
051            final int count = childNodes.getLength();
052            for (int i = 0; i < count; i++) {
053                final Node node = childNodes.item(i);
054                if (node.getNodeType() == ELEMENT_NODE && node.getNodeName().equals(childName)) {
055                    return (Element) node;
056                }
057            }
058            return null;
059        }
060    
061        /** Create a NodeListIterator.
062         * @param nodeList NodeList to iterate over
063         */
064        public NodeListIterator(final NodeList nodeList) {
065            this.nodeList = nodeList;
066        }
067    
068        /** Create a NodeListIterator.
069         * @param item Element to evaluate against
070         * @param nodeType node type of children
071         */
072        public NodeListIterator(final Element item, final short nodeType) {
073            this(new FilteredNodeList<T>(item, nodeType));
074        }
075    
076        /** Create a NodeListIterator.
077         * @param item Element to evaluate against
078         * @param childName name of child element
079         */
080        public NodeListIterator(final Element item, final String childName) {
081            this(new FilteredNodeList<T>(item, childName));
082        }
083    
084        /** Create a NodeListIterator.
085         * @param xpath XPath to evaulate against
086         * @param item Object to evaluate against
087         * @param expression XPath expression to evaluate
088         * @throws XPathExpressionException in case of xpath errors
089         */
090        public NodeListIterator(final XPath xpath, final Element item, final String expression) throws XPathExpressionException {
091            this((NodeList) xpath.evaluate(expression, item, NODESET));
092        }
093    
094        /** {@inheritDoc} */
095        public Iterator<T> iterator() {
096            return this;
097        }
098    
099        /** {@inheritDoc} */
100        public boolean hasNext() {
101            return index < nodeList.getLength();
102        }
103    
104        /** {@inheritDoc} */
105        public T next() throws NoSuchElementException {
106            final T item = (T) nodeList.item(index++);
107            if (item == null) {
108                throw new NoSuchElementException();
109            }
110            return item;
111        }
112    
113        /** {@inheritDoc} */
114        public void remove() {
115            throw new UnsupportedOperationException();
116        }
117    
118        /** Get the number of elements this iterator would iterate over all.
119         * @return number of elements
120         */
121        public int size() {
122            return nodeList.getLength();
123        }
124    
125    } // class NodeListIterator