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