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 }
--- EOF ---