    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    }