1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id: MatchPatternIterator.java 469314 2006-10-30 23:31:59Z minchau $ 20 */ 21 package org.apache.xpath.axes; 22 23 import org.apache.xml.dtm.Axis; 24 import org.apache.xml.dtm.DTM; 25 import org.apache.xml.dtm.DTMAxisTraverser; 26 import org.apache.xml.dtm.DTMIterator; 27 import org.apache.xpath.XPathContext; 28 import org.apache.xpath.compiler.Compiler; 29 import org.apache.xpath.compiler.OpMap; 30 import org.apache.xpath.objects.XObject; 31 import org.apache.xpath.patterns.NodeTest; 32 import org.apache.xpath.patterns.StepPattern; 33 34 /** 35 * This class treats a 36 * <a href="http://www.w3.org/TR/xpath#location-paths">LocationPath</a> as a 37 * filtered iteration over the tree, evaluating each node in a super axis 38 * traversal against the LocationPath interpreted as a match pattern. This 39 * class is useful to find nodes in document order that are complex paths 40 * whose steps probably criss-cross each other. 41 */ 42 public class MatchPatternIterator extends LocPathIterator 43 { 44 static final long serialVersionUID = -5201153767396296474L; 45 46 /** This is the select pattern, translated into a match pattern. */ 47 protected StepPattern m_pattern; 48 49 /** The traversal axis from where the nodes will be filtered. */ 50 protected int m_superAxis = -1; 51 52 /** The DTM inner traversal class, that corresponds to the super axis. */ 53 protected DTMAxisTraverser m_traverser; 54 55 /** DEBUG flag for diagnostic dumps. */ 56 private static final boolean DEBUG = false; 57 58 // protected int m_nsElemBase = DTM.NULL; 59 60 /** 61 * Create a LocPathIterator object, including creation 62 * of step walkers from the opcode list, and call back 63 * into the Compiler to create predicate expressions. 64 * 65 * @param compiler The Compiler which is creating 66 * this expression. 67 * @param opPos The position of this iterator in the 68 * opcode list from the compiler. 69 * @param analysis Analysis bits that give general information about the 70 * LocationPath. 71 * 72 * @throws javax.xml.transform.TransformerException 73 */ 74 MatchPatternIterator(Compiler compiler, int opPos, int analysis) 75 throws javax.xml.transform.TransformerException 76 { 77 78 super(compiler, opPos, analysis, false); 79 80 int firstStepPos = OpMap.getFirstChildPos(opPos); 81 82 m_pattern = WalkerFactory.loadSteps(this, compiler, firstStepPos, 0); 83 84 boolean fromRoot = false; 85 boolean walkBack = false; 86 boolean walkDescendants = false; 87 boolean walkAttributes = false; 88 89 if (0 != (analysis & (WalkerFactory.BIT_ROOT | 90 WalkerFactory.BIT_ANY_DESCENDANT_FROM_ROOT))) 91 fromRoot = true; 92 93 if (0 != (analysis 94 & (WalkerFactory.BIT_ANCESTOR 95 | WalkerFactory.BIT_ANCESTOR_OR_SELF 96 | WalkerFactory.BIT_PRECEDING 97 | WalkerFactory.BIT_PRECEDING_SIBLING 98 | WalkerFactory.BIT_FOLLOWING 99 | WalkerFactory.BIT_FOLLOWING_SIBLING 100 | WalkerFactory.BIT_PARENT | WalkerFactory.BIT_FILTER))) 101 walkBack = true; 102 103 if (0 != (analysis 104 & (WalkerFactory.BIT_DESCENDANT_OR_SELF 105 | WalkerFactory.BIT_DESCENDANT 106 | WalkerFactory.BIT_CHILD))) 107 walkDescendants = true; 108 109 if (0 != (analysis 110 & (WalkerFactory.BIT_ATTRIBUTE | WalkerFactory.BIT_NAMESPACE))) 111 walkAttributes = true; 112 113 if(false || DEBUG) 114 { 115 System.out.print("analysis: "+Integer.toBinaryString(analysis)); 116 System.out.println(", "+WalkerFactory.getAnalysisString(analysis)); 117 } 118 119 if(fromRoot || walkBack) 120 { 121 if(walkAttributes) 122 { 123 m_superAxis = Axis.ALL; 124 } 125 else 126 { 127 m_superAxis = Axis.DESCENDANTSFROMROOT; 128 } 129 } 130 else if(walkDescendants) 131 { 132 if(walkAttributes) 133 { 134 m_superAxis = Axis.ALLFROMNODE; 135 } 136 else 137 { 138 m_superAxis = Axis.DESCENDANTORSELF; 139 } 140 } 141 else 142 { 143 m_superAxis = Axis.ALL; 144 } 145 if(false || DEBUG) 146 { 147 System.out.println("axis: "+Axis.getNames(m_superAxis)); 148 } 149 150 } 151 152 153 /** 154 * Initialize the context values for this expression 155 * after it is cloned. 156 * 157 * @param context The XPath runtime context for this 158 * transformation. 159 */ 160 public void setRoot(int context, Object environment) 161 { 162 super.setRoot(context, environment); 163 m_traverser = m_cdtm.getAxisTraverser(m_superAxis); 164 } 165 166 /** 167 * Detaches the iterator from the set which it iterated over, releasing 168 * any computational resources and placing the iterator in the INVALID 169 * state. After<code>detach</code> has been invoked, calls to 170 * <code>nextNode</code> or<code>previousNode</code> will raise the 171 * exception INVALID_STATE_ERR. 172 */ 173 public void detach() 174 { 175 if(m_allowDetach) 176 { 177 m_traverser = null; 178 179 // Always call the superclass detach last! 180 super.detach(); 181 } 182 } 183 184 /** 185 * Get the next node via getNextXXX. Bottlenecked for derived class override. 186 * @return The next node on the axis, or DTM.NULL. 187 */ 188 protected int getNextNode() 189 { 190 m_lastFetched = (DTM.NULL == m_lastFetched) 191 ? m_traverser.first(m_context) 192 : m_traverser.next(m_context, m_lastFetched); 193 return m_lastFetched; 194 } 195 196 /** 197 * Returns the next node in the set and advances the position of the 198 * iterator in the set. After a NodeIterator is created, the first call 199 * to nextNode() returns the first node in the set. 200 * @return The next <code>Node</code> in the set being iterated over, or 201 * <code>null</code> if there are no more members in that set. 202 */ 203 public int nextNode() 204 { 205 if(m_foundLast) 206 return DTM.NULL; 207 208 int next; 209 210 org.apache.xpath.VariableStack vars; 211 int savedStart; 212 if (-1 != m_stackFrame) 213 { 214 vars = m_execContext.getVarStack(); 215 216 // These three statements need to be combined into one operation. 217 savedStart = vars.getStackFrame(); 218 219 vars.setStackFrame(m_stackFrame); 220 } 221 else 222 { 223 // Yuck. Just to shut up the compiler! 224 vars = null; 225 savedStart = 0; 226 } 227 228 try 229 { 230 if(DEBUG) 231 System.out.println("m_pattern"+m_pattern.toString()); 232 233 do 234 { 235 next = getNextNode(); 236 237 if (DTM.NULL != next) 238 { 239 if(DTMIterator.FILTER_ACCEPT == acceptNode(next, m_execContext)) 240 break; 241 else 242 continue; 243 } 244 else 245 break; 246 } 247 while (next != DTM.NULL); 248 249 if (DTM.NULL != next) 250 { 251 if(DEBUG) 252 { 253 System.out.println("next: "+next); 254 System.out.println("name: "+m_cdtm.getNodeName(next)); 255 } 256 incrementCurrentPos(); 257 258 return next; 259 } 260 else 261 { 262 m_foundLast = true; 263 264 return DTM.NULL; 265 } 266 } 267 finally 268 { 269 if (-1 != m_stackFrame) 270 { 271 // These two statements need to be combined into one operation. 272 vars.setStackFrame(savedStart); 273 } 274 } 275 276 } 277 278 /** 279 * Test whether a specified node is visible in the logical view of a 280 * TreeWalker or NodeIterator. This function will be called by the 281 * implementation of TreeWalker and NodeIterator; it is not intended to 282 * be called directly from user code. 283 * @param n The node to check to see if it passes the filter or not. 284 * @return a constant to determine whether the node is accepted, 285 * rejected, or skipped, as defined above . 286 */ 287 public short acceptNode(int n, XPathContext xctxt) 288 { 289 290 try 291 { 292 xctxt.pushCurrentNode(n); 293 xctxt.pushIteratorRoot(m_context); 294 if(DEBUG) 295 { 296 System.out.println("traverser: "+m_traverser); 297 System.out.print("node: "+n); 298 System.out.println(", "+m_cdtm.getNodeName(n)); 299 // if(m_cdtm.getNodeName(n).equals("near-east")) 300 System.out.println("pattern: "+m_pattern.toString()); 301 m_pattern.debugWhatToShow(m_pattern.getWhatToShow()); 302 } 303 304 XObject score = m_pattern.execute(xctxt); 305 306 if(DEBUG) 307 { 308 // System.out.println("analysis: "+Integer.toBinaryString(m_analysis)); 309 System.out.println("score: "+score); 310 System.out.println("skip: "+(score == NodeTest.SCORE_NONE)); 311 } 312 313 // System.out.println("\n::acceptNode - score: "+score.num()+"::"); 314 return (score == NodeTest.SCORE_NONE) ? DTMIterator.FILTER_SKIP 315 : DTMIterator.FILTER_ACCEPT; 316 } 317 catch (javax.xml.transform.TransformerException se) 318 { 319 320 // TODO: Fix this. 321 throw new RuntimeException(se.getMessage()); 322 } 323 finally 324 { 325 xctxt.popCurrentNode(); 326 xctxt.popIteratorRoot(); 327 } 328 329 } 330 331 } 332