    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.jdom;
    018
    019    import java.util.Collections;
    020    import java.util.List;
    021
    022    import org.apache.commons.jxpath.ri.compiler.NodeTest;
    023    import org.apache.commons.jxpath.ri.model.NodeIterator;
    024    import org.apache.commons.jxpath.ri.model.NodePointer;
    025    import org.jdom.Document;
    026    import org.jdom.Element;
    027
    028    /**
    029     * An iterator of children of a JDOM Node.
    030     *
    031     * @author Dmitri Plotnikov
    032     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
    033     */
    034    public class JDOMNodeIterator implements NodeIterator {
    035        private NodePointer parent;
    036        private NodeTest nodeTest;
    037
    038        private boolean reverse;
    039        private int position = 0;
    040        private int index = 0;
    041        private List children;
    042        private Object child;
    043
    044        /**
    045         * Create a new JDOMNodeIterator.
    046         * @param parent pointer
    047         * @param nodeTest test
    048         * @param reverse whether to iterate in reverse
    049         * @param startWith starting pointer
    050         */
    051        public JDOMNodeIterator(
    052                NodePointer parent, NodeTest nodeTest,
    053                boolean reverse, NodePointer startWith) {
    054            this.parent = parent;
    055            if (startWith != null) {
    056                this.child = startWith.getNode();
    057            }
    058            // TBD: optimize me for different node tests
    059            Object node = parent.getNode();
    060            if (node instanceof Document) {
    061                this.children = ((Document) node).getContent();
    062            }
    063            else if (node instanceof Element) {
    064                this.children = ((Element) node).getContent();
    065            }
    066            else {
    067                this.children = Collections.EMPTY_LIST;
    068            }
    069            this.nodeTest = nodeTest;
    070            this.reverse = reverse;
    071        }
    072
    073        public NodePointer getNodePointer() {
    074            if (child == null) {
    075                if (!setPosition(1)) {
    076                    return null;
    077                }
    078                position = 0;
    079            }
    080
    081            return new JDOMNodePointer(parent, child);
    082        }
    083
    084        public int getPosition() {
    085            return position;
    086        }
    087
    088        public boolean setPosition(int position) {
    089            while (this.position < position) {
    090                if (!next()) {
    091                    return false;
    092                }
    093            }
    094            while (this.position > position) {
    095                if (!previous()) {
    096                    return false;
    097                }
    098            }
    099            return true;
    100        }
    101
    102        /**
    103         * This is actually never invoked during the normal evaluation
    104         * of xpaths - an iterator is always going forward, never backwards.
    105         * So, this is implemented only for completeness and perhaps for
    106         * those who use these iterators outside of XPath evaluation.
    107         * @return boolean
    108         */
    109        private boolean previous() {
    110            position--;
    111            if (!reverse) {
    112                while (--index >= 0) {
    113                    child = children.get(index);
    114                    if (testChild()) {
    115                        return true;
    116                    }
    117                }
    118            }
    119            else {
    120                for (; index < children.size(); index++) {
    121                    child = children.get(index);
    122                    if (testChild()) {
    123                        return true;
    124                    }
    125                }
    126            }
    127            return false;
    128        }
    129
    130        /**
    131         * Iterate to next pointer.
    132         * @return whether valid
    133         */
    134        private boolean next() {
    135            position++;
    136            if (!reverse) {
    137                if (position == 1) {
    138                    index = 0;
    139                    if (child != null) {
    140                        index = children.indexOf(child) + 1;
    141                    }
    142                }
    143                else {
    144                    index++;
    145                }
    146                for (; index < children.size(); index++) {
    147                    child = children.get(index);
    148                    if (testChild()) {
    149                        return true;
    150                    }
    151                }
    152                return false;
    153            }
    154            else {
    155                if (position == 1) {
    156                    index = children.size() - 1;
    157                    if (child != null) {
    158                        index = children.indexOf(child) - 1;
    159                    }
    160                }
    161                else {
    162                    index--;
    163                }
    164                for (; index >= 0; index--) {
    165                    child = children.get(index);
    166                    if (testChild()) {
    167                        return true;
    168                    }
    169                }
    170                return false;
    171            }
    172        }
    173
    174        /**
    175         * Test a child node.
    176         * @return whether test passes.
    177         */
    178        private boolean testChild() {
    179            return JDOMNodePointer.testNode(parent, child, nodeTest);
    180        }
    181    }