    1   /*
    2    * Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jxpath.ri.model.jdom;
    17
    18  import java.util.Collections;
    19  import java.util.List;
    20
    21  import org.apache.commons.jxpath.ri.compiler.NodeTest;
    22  import org.apache.commons.jxpath.ri.model.NodeIterator;
    23  import org.apache.commons.jxpath.ri.model.NodePointer;
    24  import org.jdom.Document;
    25  import org.jdom.Element;
    26
    27  /***
    28   * An iterator of children of a JDOM Node.
    29   *
    30   * @author Dmitri Plotnikov
    31   * @version $Revision: 1.6 $ $Date: 2004/02/29 14:17:40 $
    32   */
    33  public class JDOMNodeIterator implements NodeIterator {
    34      private NodePointer parent;
    35      private NodeTest nodeTest;
    36
    37      private boolean reverse;
    38      private int position = 0;
    39      private int index = 0;
    40      private List children;
    41      private Object child;
    42
    43      public JDOMNodeIterator(
    44              NodePointer parent, NodeTest nodeTest,
    45              boolean reverse, NodePointer startWith)
    46      {
    47          this.parent = parent;
    48          if (startWith != null) {
    49              this.child = startWith.getNode();
    50          }
    51          // TBD: optimize me for different node tests
    52          Object node = parent.getNode();
    53          if (node instanceof Document) {
    54              this.children = ((Document) node).getContent();
    55          }
    56          else if (node instanceof Element) {
    57              this.children = ((Element) node).getContent();
    58          }
    59          else {
    60              this.children = Collections.EMPTY_LIST;
    61          }
    62          this.nodeTest = nodeTest;
    63          this.reverse = reverse;
    64      }
    65
    66      public NodePointer getNodePointer() {
    67          if (child == null) {
    68              if (!setPosition(1)) {
    69                  return null;
    70              }
    71              position = 0;
    72          }
    73
    74          return new JDOMNodePointer(parent, child);
    75      }
    76
    77      public int getPosition() {
    78          return position;
    79      }
    80
    81      public boolean setPosition(int position) {
    82          while (this.position < position) {
    83              if (!next()) {
    84                  return false;
    85              }
    86          }
    87          while (this.position > position) {
    88              if (!previous()) {
    89                  return false;
    90              }
    91          }
    92          return true;
    93      }
    94
    95      /***
    96       * This is actually never invoked during the normal evaluation
    97       * of xpaths - an iterator is always going forward, never backwards.
    98       * So, this is implemented only for completeness and perhaps for
    99       * those who use these iterators outside of XPath evaluation.
    100      */
    101     private boolean previous() {
    102         position--;
    103         if (!reverse) {
    104             while (--index >= 0) {
    105                 child = children.get(index);
    106                 if (testChild()) {
    107                     return true;
    108                 }
    109             }
    110         }
    111         else {
    112             for (; index < children.size(); index++) {
    113                 child = children.get(index);
    114                 if (testChild()) {
    115                     return true;
    116                 }
    117             }
    118         }
    119         return false;
    120     }
    121
    122     private boolean next() {
    123         position++;
    124         if (!reverse) {
    125             if (position == 1) {
    126                 index = 0;
    127                 if (child != null) {
    128                     index = children.indexOf(child) + 1;
    129                 }
    130             }
    131             else {
    132                 index++;
    133             }
    134             for (; index < children.size(); index++) {
    135                 child = children.get(index);
    136                 if (testChild()) {
    137                     return true;
    138                 }
    139             }
    140             return false;
    141         }
    142         else {
    143             if (position == 1) {
    144                 index = children.size() - 1;
    145                 if (child != null) {
    146                     index = children.indexOf(child) - 1;
    147                 }
    148             }
    149             else {
    150                 index--;
    151             }
    152             for (; index >= 0; index--) {
    153                 child = children.get(index);
    154                 if (testChild()) {
    155                     return true;
    156                 }
    157             }
    158             return false;
    159         }
    160     }
    161
    162     private boolean testChild() {
    163         return JDOMNodePointer.testNode(parent, child, nodeTest);
    164     }
    165 }