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 }