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