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 13:46:46 -0400 (Fri, 02 May 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 }