View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jxpath.ri.model.jdom;
18  
19  import java.util.Collections;
20  import java.util.List;
21  
22  import org.apache.commons.jxpath.ri.compiler.NodeTest;
23  import org.apache.commons.jxpath.ri.model.NodeIterator;
24  import org.apache.commons.jxpath.ri.model.NodePointer;
25  import org.jdom.Document;
26  import org.jdom.Element;
27  
28  /**
29   * An iterator of children of a JDOM Node.
30   *
31   * @author Dmitri Plotnikov
32   * @version $Revision: 652845 $ $Date: 2008-05-02 19:46:46 +0200 (Fr, 02 Mai 2008) $
33   */
34  public class JDOMNodeIterator implements NodeIterator {
35      private NodePointer parent;
36      private NodeTest nodeTest;
37  
38      private boolean reverse;
39      private int position = 0;
40      private int index = 0;
41      private List children;
42      private Object child;
43  
44      /**
45       * Create a new JDOMNodeIterator.
46       * @param parent pointer
47       * @param nodeTest test
48       * @param reverse whether to iterate in reverse
49       * @param startWith starting pointer
50       */
51      public JDOMNodeIterator(
52              NodePointer parent, NodeTest nodeTest,
53              boolean reverse, NodePointer startWith) {
54          this.parent = parent;
55          if (startWith != null) {
56              this.child = startWith.getNode();
57          }
58          // TBD: optimize me for different node tests
59          Object node = parent.getNode();
60          if (node instanceof Document) {
61              this.children = ((Document) node).getContent();
62          }
63          else if (node instanceof Element) {
64              this.children = ((Element) node).getContent();
65          }
66          else {
67              this.children = Collections.EMPTY_LIST;
68          }
69          this.nodeTest = nodeTest;
70          this.reverse = reverse;
71      }
72  
73      public NodePointer getNodePointer() {
74          if (child == null) {
75              if (!setPosition(1)) {
76                  return null;
77              }
78              position = 0;
79          }
80  
81          return new JDOMNodePointer(parent, child);
82      }
83  
84      public int getPosition() {
85          return position;
86      }
87  
88      public boolean setPosition(int position) {
89          while (this.position < position) {
90              if (!next()) {
91                  return false;
92              }
93          }
94          while (this.position > position) {
95              if (!previous()) {
96                  return false;
97              }
98          }
99          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 }