001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.jxpath.ri.model.dom;
018    
019    import org.apache.commons.jxpath.ri.compiler.NodeTest;
020    import org.apache.commons.jxpath.ri.model.NodeIterator;
021    import org.apache.commons.jxpath.ri.model.NodePointer;
022    import org.w3c.dom.Node;
023    
024    /**
025     * An iterator of children of a DOM Node.
026     *
027     * @author Dmitri Plotnikov
028     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
029     */
030    public class DOMNodeIterator implements NodeIterator {
031        private NodePointer parent;
032        private NodeTest nodeTest;
033        private Node node;
034        private Node child = null;
035        private boolean reverse;
036        private int position = 0;
037    
038        /**
039         * Create a new DOMNodeIterator.
040         * @param parent parent pointer
041         * @param nodeTest test
042         * @param reverse whether to iterate in reverse
043         * @param startWith starting pointer
044         */
045        public DOMNodeIterator(
046            NodePointer parent,
047            NodeTest nodeTest,
048            boolean reverse,
049            NodePointer startWith) {
050            this.parent = parent;
051            this.node = (Node) parent.getNode();
052            if (startWith != null) {
053                this.child = (Node) startWith.getNode();
054            }
055            this.nodeTest = nodeTest;
056            this.reverse = reverse;
057        }
058    
059        public NodePointer getNodePointer() {
060            if (position == 0) {
061                setPosition(1);
062            }
063            return child == null ? null : new DOMNodePointer(parent, child);
064        }
065    
066        public int getPosition() {
067            return position;
068        }
069    
070        public boolean setPosition(int position) {
071            while (this.position < position) {
072                if (!next()) {
073                    return false;
074                }
075            }
076            while (this.position > position) {
077                if (!previous()) {
078                    return false;
079                }
080            }
081            return true;
082        }
083    
084        /**
085         * Set the previous position.
086         * @return whether valid
087         */
088        private boolean previous() {
089            position--;
090            if (!reverse) {
091                if (position == 0) {
092                    child = null;
093                }
094                else if (child == null) {
095                    child = node.getLastChild();
096                }
097                else {
098                    child = child.getPreviousSibling();
099                }
100                while (child != null && !testChild()) {
101                    child = child.getPreviousSibling();
102                }
103            }
104            else {
105                child = child.getNextSibling();
106                while (child != null && !testChild()) {
107                    child = child.getNextSibling();
108                }
109            }
110            return child != null;
111        }
112    
113        /**
114         * Set the next position.
115         * @return whether valid
116         */
117        private boolean next() {
118            position++;
119            if (!reverse) {
120                if (position == 1) {
121                    if (child == null) {
122                        child = node.getFirstChild();
123                    }
124                    else {
125                        child = child.getNextSibling();
126                    }
127                }
128                else {
129                    child = child.getNextSibling();
130                }
131                while (child != null && !testChild()) {
132                    child = child.getNextSibling();
133                }
134            }
135            else {
136                if (position == 1) {
137                    if (child == null) {
138                        child = node.getLastChild();
139                    }
140                    else {
141                        child = child.getPreviousSibling();
142                    }
143                }
144                else {
145                    child = child.getPreviousSibling();
146                }
147                while (child != null && !testChild()) {
148                    child = child.getPreviousSibling();
149                }
150            }
151            return child != null;
152        }
153    
154        /**
155         * Test child.
156         * @return result of the test
157         */
158        private boolean testChild() {
159            return DOMNodePointer.testNode(child, nodeTest);
160        }
161    }