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 */ 017package org.apache.commons.jxpath.ri.model.jdom; 018 019import java.util.Collections; 020import java.util.List; 021 022import org.apache.commons.jxpath.ri.compiler.NodeTest; 023import org.apache.commons.jxpath.ri.model.NodeIterator; 024import org.apache.commons.jxpath.ri.model.NodePointer; 025import org.jdom.Document; 026import 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 19:46:46 +0200 (Fr, 02 Mai 2008) $ 033 */ 034public 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}