    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
    018package org.apache.commons.jxpath.ri.model.dom;
    019
    020import org.apache.commons.jxpath.ri.compiler.NodeTest;
    021import org.apache.commons.jxpath.ri.model.NodeIterator;
    022import org.apache.commons.jxpath.ri.model.NodePointer;
    023import org.w3c.dom.Node;
    024
    025/**
    026 * An iterator of children of a DOM Node.
    027 */
    028public class DOMNodeIterator implements NodeIterator {
    029
    030    private final NodePointer parent;
    031    private final NodeTest nodeTest;
    032    private final Node node;
    033    private Node child;
    034    private final boolean reverse;
    035    private int position;
    036
    037    /**
    038     * Constructs a new DOMNodeIterator.
    039     *
    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(final NodePointer parent, final NodeTest nodeTest, final boolean reverse, final NodePointer startWith) {
    046        this.parent = parent;
    047        this.node = (Node) parent.getNode();
    048        if (startWith != null) {
    049            this.child = (Node) startWith.getNode();
    050        }
    051        this.nodeTest = nodeTest;
    052        this.reverse = reverse;
    053    }
    054
    055    @Override
    056    public NodePointer getNodePointer() {
    057        if (position == 0) {
    058            setPosition(1);
    059        }
    060        return child == null ? null : new DOMNodePointer(parent, child);
    061    }
    062
    063    @Override
    064    public int getPosition() {
    065        return position;
    066    }
    067
    068    /**
    069     * Sets the next position.
    070     *
    071     * @return whether valid
    072     */
    073    private boolean next() {
    074        position++;
    075        if (!reverse) {
    076            if (position == 1 && child == null) {
    077                child = node.getFirstChild();
    078            } else {
    079                child = child.getNextSibling();
    080            }
    081            while (child != null && !testChild()) {
    082                child = child.getNextSibling();
    083            }
    084        } else {
    085            if (position == 1 && child == null) {
    086                child = node.getLastChild();
    087            } else {
    088                child = child.getPreviousSibling();
    089            }
    090            while (child != null && !testChild()) {
    091                child = child.getPreviousSibling();
    092            }
    093        }
    094        return child != null;
    095    }
    096
    097    /**
    098     * Sets the previous position.
    099     *
    100     * @return whether valid
    101     */
    102    private boolean previous() {
    103        position--;
    104        if (!reverse) {
    105            if (position == 0) {
    106                child = null;
    107            } else if (child == null) {
    108                child = node.getLastChild();
    109            } else {
    110                child = child.getPreviousSibling();
    111            }
    112            while (child != null && !testChild()) {
    113                child = child.getPreviousSibling();
    114            }
    115        } else {
    116            child = child.getNextSibling();
    117            while (child != null && !testChild()) {
    118                child = child.getNextSibling();
    119            }
    120        }
    121        return child != null;
    122    }
    123
    124    @Override
    125    public boolean setPosition(final int position) {
    126        while (this.position < position) {
    127            if (!next()) {
    128                return false;
    129            }
    130        }
    131        while (this.position > position) {
    132            if (!previous()) {
    133                return false;
    134            }
    135        }
    136        return true;
    137    }
    138
    139    /**
    140     * Test child.
    141     *
    142     * @return result of the test
    143     */
    144    private boolean testChild() {
    145        return DOMNodePointer.testNode(child, nodeTest);
    146    }
    147}