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.xalan.internal.res.XSLMessages;
24 import com.sun.org.apache.xml.internal.dtm.DTM;
25 import com.sun.org.apache.xml.internal.dtm.DTMFilter;
26 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
27 import com.sun.org.apache.xml.internal.dtm.DTMManager;
28 import com.sun.org.apache.xml.internal.utils.PrefixResolver;
29 import com.sun.org.apache.xpath.internal.ExpressionOwner;
30 import com.sun.org.apache.xpath.internal.XPathContext;
31 import com.sun.org.apache.xpath.internal.XPathVisitor;
32 import com.sun.org.apache.xpath.internal.compiler.Compiler;
33 import com.sun.org.apache.xpath.internal.objects.XNodeSet;
34 import com.sun.org.apache.xpath.internal.objects.XObject;
35 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
36
37 /**
38 * This class extends NodeSetDTM, which implements NodeIterator,
39 * and fetches nodes one at a time in document order based on a XPath
40 * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a>.
41 *
42 * <p>If setShouldCacheNodes(true) is called,
43 * as each node is iterated via nextNode(), the node is also stored
44 * in the NodeVector, so that previousNode() can easily be done, except in
45 * the case where the LocPathIterator is "owned" by a UnionPathIterator,
46 * in which case the UnionPathIterator will cache the nodes.</p>
47 * @xsl.usage advanced
48 * @LastModified: Nov 2017
49 */
50 public abstract class LocPathIterator extends PredicatedNodeTest
51 implements Cloneable, DTMIterator, java.io.Serializable, PathComponent
52 {
53 static final long serialVersionUID = -4602476357268405754L;
54
55 /**
56 * Create a LocPathIterator object.
57 *
58 */
59 protected LocPathIterator()
60 {
61 }
62
63
64 /**
65 * Create a LocPathIterator object.
66 *
67 * @param nscontext The namespace context for this iterator,
68 * should be OK if null.
69 */
70 protected LocPathIterator(PrefixResolver nscontext)
71 {
72
73 setLocPathIterator(this);
74 m_prefixResolver = nscontext;
75 }
76
77 /**
78 * Create a LocPathIterator object, including creation
79 * of step walkers from the opcode list, and call back
80 * into the Compiler to create predicate expressions.
81 *
82 * @param compiler The Compiler which is creating
83 * this expression.
84 * @param opPos The position of this iterator in the
85 * opcode list from the compiler.
86 *
87 * @throws javax.xml.transform.TransformerException
88 */
89 protected LocPathIterator(Compiler compiler, int opPos, int analysis)
90 throws javax.xml.transform.TransformerException
91 {
92 this(compiler, opPos, analysis, true);
93 }
94
95 /**
96 * Create a LocPathIterator object, including creation
97 * of step walkers from the opcode list, and call back
98 * into the Compiler to create predicate expressions.
99 *
100 * @param compiler The Compiler which is creating
101 * this expression.
102 * @param opPos The position of this iterator in the
103 * opcode list from the compiler.
104 * @param shouldLoadWalkers True if walkers should be
105 * loaded, or false if this is a derived iterator and
106 * it doesn't wish to load child walkers.
107 *
108 * @throws javax.xml.transform.TransformerException
109 */
110 protected LocPathIterator(
111 Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)
112 throws javax.xml.transform.TransformerException
113 {
114 setLocPathIterator(this);
115 }
116
117 /**
118 * Get the analysis bits for this walker, as defined in the WalkerFactory.
119 * @return One of WalkerFactory#BIT_DESCENDANT, etc.
120 */
121 public int getAnalysisBits()
122 {
123 int axis = getAxis();
124 int bit = WalkerFactory.getAnalysisBitFromAxes(axis);
125 return bit;
126 }
127
128 /**
129 * Read the object from a serialization stream.
130 *
131 * @param stream Input stream to read from
132 *
133 * @throws java.io.IOException
134 * @throws javax.xml.transform.TransformerException
135 */
136 private void readObject(java.io.ObjectInputStream stream)
137 throws java.io.IOException, javax.xml.transform.TransformerException
138 {
139 try
140 {
141 stream.defaultReadObject();
142 m_clones = new IteratorPool(this);
143 }
144 catch (ClassNotFoundException cnfe)
145 {
146 throw new javax.xml.transform.TransformerException(cnfe);
147 }
148 }
149
150 /**
151 * Set the environment in which this iterator operates, which should provide:
152 * a node (the context node... same value as "root" defined below)
153 * a pair of non-zero positive integers (the context position and the context size)
154 * a set of variable bindings
155 * a function library
156 * the set of namespace declarations in scope for the expression.
157 *
158 * <p>At this time the exact implementation of this environment is application
159 * dependent. Probably a proper interface will be created fairly soon.</p>
160 *
161 * @param environment The environment object.
162 */
163 public void setEnvironment(Object environment)
164 {
165 // no-op for now.
166 }
167
168 /**
169 * Get an instance of a DTM that "owns" a node handle. Since a node
170 * iterator may be passed without a DTMManager, this allows the
171 * caller to easily get the DTM using just the iterator.
172 *
173 * @param nodeHandle the nodeHandle.
174 *
175 * @return a non-null DTM reference.
176 */
177 public DTM getDTM(int nodeHandle)
178 {
179 // %OPT%
180 return m_execContext.getDTM(nodeHandle);
181 }
182
183 /**
184 * Get an instance of the DTMManager. Since a node
185 * iterator may be passed without a DTMManager, this allows the
186 * caller to easily get the DTMManager using just the iterator.
187 *
188 * @return a non-null DTMManager reference.
189 */
190 public DTMManager getDTMManager()
191 {
192 return m_execContext.getDTMManager();
193 }
194
195 /**
196 * Execute this iterator, meaning create a clone that can
197 * store state, and initialize it for fast execution from
198 * the current runtime state. When this is called, no actual
199 * query from the current context node is performed.
200 *
201 * @param xctxt The XPath execution context.
202 *
203 * @return An XNodeSet reference that holds this iterator.
204 *
205 * @throws javax.xml.transform.TransformerException
206 */
207 public XObject execute(XPathContext xctxt)
208 throws javax.xml.transform.TransformerException
209 {
210
211 XNodeSet iter = new XNodeSet((LocPathIterator)m_clones.getInstance());
212
213 iter.setRoot(xctxt.getCurrentNode(), xctxt);
214
215 return iter;
216 }
217
218 /**
219 * Execute an expression in the XPath runtime context, and return the
220 * result of the expression.
221 *
222 *
223 * @param xctxt The XPath runtime context.
224 * @param handler The target content handler.
225 *
226 * @return The result of the expression in the form of a <code>XObject</code>.
227 *
228 * @throws javax.xml.transform.TransformerException if a runtime exception
229 * occurs.
230 * @throws org.xml.sax.SAXException
231 */
232 public void executeCharsToContentHandler(
233 XPathContext xctxt, org.xml.sax.ContentHandler handler)
234 throws javax.xml.transform.TransformerException,
235 org.xml.sax.SAXException
236 {
237 LocPathIterator clone = (LocPathIterator)m_clones.getInstance();
238
239 int current = xctxt.getCurrentNode();
240 clone.setRoot(current, xctxt);
241
242 int node = clone.nextNode();
243 DTM dtm = clone.getDTM(node);
244 clone.detach();
245
246 if(node != DTM.NULL)
247 {
248 dtm.dispatchCharactersEvents(node, handler, false);
249 }
250 }
251
252 /**
253 * Given an select expression and a context, evaluate the XPath
254 * and return the resulting iterator.
255 *
256 * @param xctxt The execution context.
257 * @param contextNode The node that "." expresses.
258 * @throws TransformerException thrown if the active ProblemListener decides
259 * the error condition is severe enough to halt processing.
260 *
261 * @throws javax.xml.transform.TransformerException
262 * @xsl.usage experimental
263 */
264 public DTMIterator asIterator(
265 XPathContext xctxt, int contextNode)
266 throws javax.xml.transform.TransformerException
267 {
268 XNodeSet iter = new XNodeSet((LocPathIterator)m_clones.getInstance());
269
270 iter.setRoot(contextNode, xctxt);
271
272 return iter;
273 }
274
275
276 /**
277 * Tell if the expression is a nodeset expression.
278 *
279 * @return true if the expression can be represented as a nodeset.
280 */
281 public boolean isNodesetExpr()
282 {
283 return true;
284 }
285
286 /**
287 * Return the first node out of the nodeset, if this expression is
288 * a nodeset expression. This is the default implementation for
289 * nodesets. Derived classes should try and override this and return a
290 * value without having to do a clone operation.
291 * @param xctxt The XPath runtime context.
292 * @return the first node out of the nodeset, or DTM.NULL.
293 */
294 public int asNode(XPathContext xctxt)
295 throws javax.xml.transform.TransformerException
296 {
297 DTMIterator iter = m_clones.getInstance();
298
299 int current = xctxt.getCurrentNode();
300
301 iter.setRoot(current, xctxt);
302
303 int next = iter.nextNode();
304 // m_clones.freeInstance(iter);
305 iter.detach();
306 return next;
307 }
308
309 /**
310 * Evaluate this operation directly to a boolean.
311 *
312 * @param xctxt The runtime execution context.
313 *
314 * @return The result of the operation as a boolean.
315 *
316 * @throws javax.xml.transform.TransformerException
317 */
318 public boolean bool(XPathContext xctxt)
319 throws javax.xml.transform.TransformerException
320 {
321 return (asNode(xctxt) != DTM.NULL);
322 }
323
324
325 /**
326 * Set if this is an iterator at the upper level of
327 * the XPath.
328 *
329 * @param b true if this location path is at the top level of the
330 * expression.
331 * @xsl.usage advanced
332 */
333 public void setIsTopLevel(boolean b)
334 {
335 m_isTopLevel = b;
336 }
337
338 /**
339 * Get if this is an iterator at the upper level of
340 * the XPath.
341 *
342 * @return true if this location path is at the top level of the
343 * expression.
344 * @xsl.usage advanced
345 */
346 public boolean getIsTopLevel()
347 {
348 return m_isTopLevel;
349 }
350
351 /**
352 * Initialize the context values for this expression
353 * after it is cloned.
354 *
355 * @param context The XPath runtime context for this
356 * transformation.
357 */
358 public void setRoot(int context, Object environment)
359 {
360
361 m_context = context;
362
363 XPathContext xctxt = (XPathContext)environment;
364 m_execContext = xctxt;
365 m_cdtm = xctxt.getDTM(context);
366
367 m_currentContextNode = context; // only if top level?
368
369 // Yech, shouldn't have to do this. -sb
370 if(null == m_prefixResolver)
371 m_prefixResolver = xctxt.getNamespaceContext();
372
373 m_lastFetched = DTM.NULL;
374 m_foundLast = false;
375 m_pos = 0;
376 m_length = -1;
377
378 if (m_isTopLevel)
379 this.m_stackFrame = xctxt.getVarStack().getStackFrame();
380
381 // reset();
382 }
383
384 /**
385 * Set the next position index of this iterator.
386 *
387 * @param next A value greater than or equal to zero that indicates the next
388 * node position to fetch.
389 */
390 protected void setNextPosition(int next)
391 {
392 assertion(false, "setNextPosition not supported in this iterator!");
393 }
394
395 /**
396 * Get the current position, which is one less than
397 * the next nextNode() call will retrieve. i.e. if
398 * you call getCurrentPos() and the return is 0, the next
399 * fetch will take place at index 1.
400 *
401 * @return A value greater than or equal to zero that indicates the next
402 * node position to fetch.
403 */
404 public final int getCurrentPos()
405 {
406 return m_pos;
407 }
408
409
410 /**
411 * If setShouldCacheNodes(true) is called, then nodes will
412 * be cached. They are not cached by default.
413 *
414 * @param b True if this iterator should cache nodes.
415 */
416 public void setShouldCacheNodes(boolean b)
417 {
418
419 assertion(false, "setShouldCacheNodes not supported by this iterater!");
420 }
421
422 /**
423 * Tells if this iterator can have nodes added to it or set via
424 * the <code>setItem(int node, int index)</code> method.
425 *
426 * @return True if the nodelist can be mutated.
427 */
428 public boolean isMutable()
429 {
430 return false;
431 }
432
433 /**
434 * Set the current position in the node set.
435 *
436 * @param i Must be a valid index greater
437 * than or equal to zero and less than m_cachedNodes.size().
438 */
439 public void setCurrentPos(int i)
440 {
441 assertion(false, "setCurrentPos not supported by this iterator!");
442 }
443
444 /**
445 * Increment the current position in the node set.
446 */
447 public void incrementCurrentPos()
448 {
449 m_pos++;
450 }
451
452
453 /**
454 * Get the length of the cached nodes.
455 *
456 * <p>Note: for the moment at least, this only returns
457 * the size of the nodes that have been fetched to date,
458 * it doesn't attempt to run to the end to make sure we
459 * have found everything. This should be reviewed.</p>
460 *
461 * @return The size of the current cache list.
462 */
463 public int size()
464 {
465 assertion(false, "size() not supported by this iterator!");
466 return 0;
467 }
468
469 /**
470 * Returns the <code>index</code> th item in the collection. If
471 * <code>index</code> is greater than or equal to the number of nodes in
472 * the list, this returns <code>null</code> .
473 * @param index Index into the collection.
474 * @return The node at the <code>index</code> th position in the
475 * <code>NodeList</code> , or <code>null</code> if that is not a valid
476 * index.
477 */
478 public int item(int index)
479 {
480 assertion(false, "item(int index) not supported by this iterator!");
481 return 0;
482 }
483
484 /**
485 * Sets the node at the specified index of this vector to be the
486 * specified node. The previous component at that position is discarded.
487 *
488 * <p>The index must be a value greater than or equal to 0 and less
489 * than the current size of the vector.
490 * The iterator must be in cached mode.</p>
491 *
492 * <p>Meant to be used for sorted iterators.</p>
493 *
494 * @param node Node to set
495 * @param index Index of where to set the node
496 */
497 public void setItem(int node, int index)
498 {
499 assertion(false, "setItem not supported by this iterator!");
500 }
501
502 /**
503 * The number of nodes in the list. The range of valid child node indices
504 * is 0 to <code>length-1</code> inclusive.
505 *
506 * @return The number of nodes in the list, always greater or equal to zero.
507 */
508 public int getLength()
509 {
510 // Tell if this is being called from within a predicate.
511 boolean isPredicateTest = (this == m_execContext.getSubContextList());
512
513 // And get how many total predicates are part of this step.
514 int predCount = getPredicateCount();
515
516 // If we have already calculated the length, and the current predicate
517 // is the first predicate, then return the length. We don't cache
518 // the anything but the length of the list to the first predicate.
519 if (-1 != m_length && isPredicateTest && m_predicateIndex < 1)
520 return m_length;
521
522 // I'm a bit worried about this one, since it doesn't have the
523 // checks found above. I suspect it's fine. -sb
524 if (m_foundLast)
525 return m_pos;
526
527 // Create a clone, and count from the current position to the end
528 // of the list, not taking into account the current predicate and
529 // predicates after the current one.
530 int pos = (m_predicateIndex >= 0) ? getProximityPosition() : m_pos;
531
532 LocPathIterator clone;
533
534 try
535 {
536 clone = (LocPathIterator) clone();
537 }
538 catch (CloneNotSupportedException cnse)
539 {
540 return -1;
541 }
542
543 // We want to clip off the last predicate, but only if we are a sub
544 // context node list, NOT if we are a context list. See pos68 test,
545 // also test against bug4638.
546 if (predCount > 0 && isPredicateTest)
547 {
548 // Don't call setPredicateCount, because it clones and is slower.
549 clone.m_predCount = m_predicateIndex;
550 // The line above used to be:
551 // clone.m_predCount = predCount - 1;
552 // ...which looks like a dumb bug to me. -sb
553 }
554
555 int next;
556
557 while (DTM.NULL != (next = clone.nextNode()))
558 {
559 pos++;
560 }
561
562 if (isPredicateTest && m_predicateIndex < 1)
563 m_length = pos;
564
565 return pos;
566 }
567
568 /**
569 * Tells if this NodeSetDTM is "fresh", in other words, if
570 * the first nextNode() that is called will return the
571 * first node in the set.
572 *
573 * @return true of nextNode has not been called.
574 */
575 public boolean isFresh()
576 {
577 return (m_pos == 0);
578 }
579
580 /**
581 * Returns the previous node in the set and moves the position of the
582 * iterator backwards in the set.
583 * @return The previous <code>Node</code> in the set being iterated over,
584 * or<code>null</code> if there are no more members in that set.
585 */
586 public int previousNode()
587 {
588 throw new RuntimeException(
589 XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_ITERATE, null)); //"This NodeSetDTM can not iterate to a previous node!");
590 }
591
592 /**
593 * This attribute determines which node types are presented via the
594 * iterator. The available set of constants is defined in the
595 * <code>NodeFilter</code> interface.
596 *
597 * <p>This is somewhat useless at this time, since it doesn't
598 * really return information that tells what this iterator will
599 * show. It is here only to fullfill the DOM NodeIterator
600 * interface.</p>
601 *
602 * @return For now, always NodeFilter.SHOW_ALL & ~NodeFilter.SHOW_ENTITY_REFERENCE.
603 * @see org.w3c.dom.traversal.NodeIterator
604 */
605 public int getWhatToShow()
606 {
607
608 // TODO: ??
609 return DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE;
610 }
611
612 /**
613 * The filter used to screen nodes. Not used at this time,
614 * this is here only to fullfill the DOM NodeIterator
615 * interface.
616 *
617 * @return Always null.
618 * @see org.w3c.dom.traversal.NodeIterator
619 */
620 public DTMFilter getFilter()
621 {
622 return null;
623 }
624
625 /**
626 * The root node of the Iterator, as specified when it was created.
627 *
628 * @return The "root" of this iterator, which, in XPath terms,
629 * is the node context for this iterator.
630 */
631 public int getRoot()
632 {
633 return m_context;
634 }
635
636 /**
637 * The value of this flag determines whether the children of entity
638 * reference nodes are visible to the iterator. If false, they will be
639 * skipped over.
640 * <br> To produce a view of the document that has entity references
641 * expanded and does not expose the entity reference node itself, use the
642 * whatToShow flags to hide the entity reference node and set
643 * expandEntityReferences to true when creating the iterator. To produce
644 * a view of the document that has entity reference nodes but no entity
645 * expansion, use the whatToShow flags to show the entity reference node
646 * and set expandEntityReferences to false.
647 *
648 * @return Always true, since entity reference nodes are not
649 * visible in the XPath model.
650 */
651 public boolean getExpandEntityReferences()
652 {
653 return true;
654 }
655
656 /** Control over whether it is OK for detach to reset the iterator. */
657 protected boolean m_allowDetach = true;
658
659 /**
660 * Specify if it's OK for detach to release the iterator for reuse.
661 *
662 * @param allowRelease true if it is OK for detach to release this iterator
663 * for pooling.
664 */
665 public void allowDetachToRelease(boolean allowRelease)
666 {
667 m_allowDetach = allowRelease;
668 }
669
670 /**
671 * Detaches the iterator from the set which it iterated over, releasing
672 * any computational resources and placing the iterator in the INVALID
673 * state. After<code>detach</code> has been invoked, calls to
674 * <code>nextNode</code> or<code>previousNode</code> will raise the
675 * exception INVALID_STATE_ERR.
676 */
677 public void detach()
678 {
679 if(m_allowDetach)
680 {
681 // sb: allow reusing of cached nodes when possible?
682 // m_cachedNodes = null;
683 m_execContext = null;
684 // m_prefixResolver = null; sb: Why would this ever want to be null?
685 m_cdtm = null;
686 m_length = -1;
687 m_pos = 0;
688 m_lastFetched = DTM.NULL;
689 m_context = DTM.NULL;
690 m_currentContextNode = DTM.NULL;
691
692 m_clones.freeInstance(this);
693 }
694 }
695
696 /**
697 * Reset the iterator.
698 */
699 public void reset()
700 {
701 assertion(false, "This iterator can not reset!");
702 }
703
704 /**
705 * Get a cloned Iterator that is reset to the beginning
706 * of the query.
707 *
708 * @return A cloned NodeIterator set of the start of the query.
709 *
710 * @throws CloneNotSupportedException
711 */
712 public DTMIterator cloneWithReset() throws CloneNotSupportedException
713 {
714 LocPathIterator clone;
715 // clone = (LocPathIterator) clone();
716 clone = (LocPathIterator)m_clones.getInstanceOrThrow();
717 clone.m_execContext = m_execContext;
718 clone.m_cdtm = m_cdtm;
719
720 clone.m_context = m_context;
721 clone.m_currentContextNode = m_currentContextNode;
722 clone.m_stackFrame = m_stackFrame;
723
724 // clone.reset();
725
726 return clone;
727 }
728
729 // /**
730 // * Get a cloned LocPathIterator that holds the same
731 // * position as this iterator.
732 // *
733 // * @return A clone of this iterator that holds the same node position.
734 // *
735 // * @throws CloneNotSupportedException
736 // */
737 // public Object clone() throws CloneNotSupportedException
738 // {
739 //
740 // LocPathIterator clone = (LocPathIterator) super.clone();
741 //
742 // return clone;
743 // }
744
745 /**
746 * Returns the next node in the set and advances the position of the
747 * iterator in the set. After a NodeIterator is created, the first call
748 * to nextNode() returns the first node in the set.
749 * @return The next <code>Node</code> in the set being iterated over, or
750 * <code>null</code> if there are no more members in that set.
751 */
752 public abstract int nextNode();
753
754 /**
755 * Bottleneck the return of a next node, to make returns
756 * easier from nextNode().
757 *
758 * @param nextNode The next node found, may be null.
759 *
760 * @return The same node that was passed as an argument.
761 */
762 protected int returnNextNode(int nextNode)
763 {
764
765 if (DTM.NULL != nextNode)
766 {
767 m_pos++;
768 }
769
770 m_lastFetched = nextNode;
771
772 if (DTM.NULL == nextNode)
773 m_foundLast = true;
774
775 return nextNode;
776 }
777
778 /**
779 * Return the last fetched node. Needed to support the UnionPathIterator.
780 *
781 * @return The last fetched node, or null if the last fetch was null.
782 */
783 public int getCurrentNode()
784 {
785 return m_lastFetched;
786 }
787
788 /**
789 * If an index is requested, NodeSetDTM will call this method
790 * to run the iterator to the index. By default this sets
791 * m_next to the index. If the index argument is -1, this
792 * signals that the iterator should be run to the end.
793 *
794 * @param index The index to run to, or -1 if the iterator
795 * should run to the end.
796 */
797 public void runTo(int index)
798 {
799
800 if (m_foundLast || ((index >= 0) && (index <= getCurrentPos())))
801 return;
802
803 int n;
804
805 if (-1 == index)
806 {
807 while (DTM.NULL != (n = nextNode()));
808 }
809 else
810 {
811 while (DTM.NULL != (n = nextNode()))
812 {
813 if (getCurrentPos() >= index)
814 break;
815 }
816 }
817 }
818
819 /**
820 * Tells if we've found the last node yet.
821 *
822 * @return true if the last nextNode returned null.
823 */
824 public final boolean getFoundLast()
825 {
826 return m_foundLast;
827 }
828
829 /**
830 * The XPath execution context we are operating on.
831 *
832 * @return XPath execution context this iterator is operating on,
833 * or null if setRoot has not been called.
834 */
835 public final XPathContext getXPathContext()
836 {
837 return m_execContext;
838 }
839
840 /**
841 * The node context for the iterator.
842 *
843 * @return The node context, same as getRoot().
844 */
845 public final int getContext()
846 {
847 return m_context;
848 }
849
850 /**
851 * The node context from where the expression is being
852 * executed from (i.e. for current() support).
853 *
854 * @return The top-level node context of the entire expression.
855 */
856 public final int getCurrentContextNode()
857 {
858 return m_currentContextNode;
859 }
860
861 /**
862 * Set the current context node for this iterator.
863 *
864 * @param n Must be a non-null reference to the node context.
865 */
866 public final void setCurrentContextNode(int n)
867 {
868 m_currentContextNode = n;
869 }
870
871 // /**
872 // * Set the current context node for this iterator.
873 // *
874 // * @param n Must be a non-null reference to the node context.
875 // */
876 // public void setRoot(int n)
877 // {
878 // m_context = n;
879 // m_cdtm = m_execContext.getDTM(n);
880 // }
881
882 /**
883 * Return the saved reference to the prefix resolver that
884 * was in effect when this iterator was created.
885 *
886 * @return The prefix resolver or this iterator, which may be null.
887 */
888 public final PrefixResolver getPrefixResolver()
889 {
890 if(null == m_prefixResolver)
891 {
892 m_prefixResolver = (PrefixResolver)getExpressionOwner();
893 }
894
895 return m_prefixResolver;
896 }
897
898 // /**
899 // * Get the analysis pattern built by the WalkerFactory.
900 // *
901 // * @return The analysis pattern built by the WalkerFactory.
902 // */
903 // int getAnalysis()
904 // {
905 // return m_analysis;
906 // }
907
908 // /**
909 // * Set the analysis pattern built by the WalkerFactory.
910 // *
911 // * @param a The analysis pattern built by the WalkerFactory.
912 // */
913 // void setAnalysis(int a)
914 // {
915 // m_analysis = a;
916 // }
917
918 /**
919 * @see com.sun.org.apache.xpath.internal.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
920 */
921 public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
922 {
923 if(visitor.visitLocationPath(owner, this))
924 {
925 visitor.visitStep(owner, this);
926 callPredicateVisitors(visitor);
927 }
928 }
929
930
931 //============= State Data =============
932
933 /**
934 * The pool for cloned iterators. Iterators need to be cloned
935 * because the hold running state, and thus the original iterator
936 * expression from the stylesheet pool can not be used.
937 */
938 transient protected IteratorPool m_clones = new IteratorPool(this);
939
940 /**
941 * The dtm of the context node. Careful about using this... it may not
942 * be the dtm of the current node.
943 */
944 transient protected DTM m_cdtm;
945
946 /**
947 * The stack frame index for this iterator.
948 */
949 transient int m_stackFrame = -1;
950
951 /**
952 * Value determined at compile time, indicates that this is an
953 * iterator at the top level of the expression, rather than inside
954 * a predicate.
955 * @serial
956 */
957 private boolean m_isTopLevel = false;
958
959 /** The last node that was fetched, usually by nextNode. */
960 transient public int m_lastFetched = DTM.NULL;
961
962 /**
963 * The context node for this iterator, which doesn't change through
964 * the course of the iteration.
965 */
966 transient protected int m_context = DTM.NULL;
967
968 /**
969 * The node context from where the expression is being
970 * executed from (i.e. for current() support). Different
971 * from m_context in that this is the context for the entire
972 * expression, rather than the context for the subexpression.
973 */
974 transient protected int m_currentContextNode = DTM.NULL;
975
976 /**
977 * The current position of the context node.
978 */
979 transient protected int m_pos = 0;
980
981 transient protected int m_length = -1;
982
983 /**
984 * Fast access to the current prefix resolver. It isn't really
985 * clear that this is needed.
986 * @serial
987 */
988 private PrefixResolver m_prefixResolver;
989
990 /**
991 * The XPathContext reference, needed for execution of many
992 * operations.
993 */
994 transient protected XPathContext m_execContext;
995
996 /**
997 * Returns true if all the nodes in the iteration well be returned in document
998 * order.
999 *
1000 * @return true as a default.
1001 */
1002 public boolean isDocOrdered()
1003 {
1004 return true;
1005 }
1006
1007 /**
1008 * Returns the axis being iterated, if it is known.
1009 *
1010 * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
1011 * types.
1012 */
1013 public int getAxis()
1014 {
1015 return -1;
1016 }
1017
1018
1019 // /**
1020 // * The analysis pattern built by the WalkerFactory.
1021 // * TODO: Move to LocPathIterator.
1022 // * @see com.sun.org.apache.xpath.internal.axes.WalkerFactory
1023 // * @serial
1024 // */
1025 // protected int m_analysis = 0x00000000;
1026 /**
1027 * @see PredicatedNodeTest#getLastPos(XPathContext)
1028 */
1029 public int getLastPos(XPathContext xctxt)
1030 {
1031 return getLength();
1032 }
1033
1034 }
--- EOF ---