KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xpath > axes > AxesWalker


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: AxesWalker.java,v 1.28 2004/02/17 04:32:08 minchau Exp $
18  */

19 package org.apache.xpath.axes;
20
21 import java.util.Vector JavaDoc;
22
23 import org.apache.xalan.res.XSLMessages;
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.Expression;
28 import org.apache.xpath.ExpressionOwner;
29 import org.apache.xpath.XPathContext;
30 import org.apache.xpath.XPathVisitor;
31 import org.apache.xpath.compiler.Compiler;
32 import org.apache.xpath.res.XPATHErrorResources;
33
34 /**
35  * Serves as common interface for axes Walkers, and stores common
36  * state variables.
37  */

38 public class AxesWalker extends PredicatedNodeTest
39         implements Cloneable JavaDoc, PathComponent, ExpressionOwner
40 {
41   
42   /**
43    * Construct an AxesWalker using a LocPathIterator.
44    *
45    * @param locPathIterator non-null reference to the parent iterator.
46    */

47   public AxesWalker(LocPathIterator locPathIterator, int axis)
48   {
49     super( locPathIterator );
50     m_axis = axis;
51   }
52   
53   public final WalkingIterator wi()
54   {
55     return (WalkingIterator)m_lpi;
56   }
57
58   /**
59    * Initialize an AxesWalker during the parse of the XPath expression.
60    *
61    * @param compiler The Compiler object that has information about this
62    * walker in the op map.
63    * @param opPos The op code position of this location step.
64    * @param stepType The type of location step.
65    *
66    * @throws javax.xml.transform.TransformerException
67    */

68   public void init(Compiler JavaDoc compiler, int opPos, int stepType)
69           throws javax.xml.transform.TransformerException JavaDoc
70   {
71
72     initPredicateInfo(compiler, opPos);
73
74     // int testType = compiler.getOp(nodeTestOpPos);
75
}
76
77   /**
78    * Get a cloned AxesWalker.
79    *
80    * @return A new AxesWalker that can be used without mutating this one.
81    *
82    * @throws CloneNotSupportedException
83    */

84   public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc
85   {
86     // Do not access the location path itterator during this operation!
87

88     AxesWalker clone = (AxesWalker) super.clone();
89
90     //clone.setCurrentNode(clone.m_root);
91

92     // clone.m_isFresh = true;
93

94     return clone;
95   }
96   
97   /**
98    * Do a deep clone of this walker, including next and previous walkers.
99    * If the this AxesWalker is on the clone list, don't clone but
100    * return the already cloned version.
101    *
102    * @param cloneOwner non-null reference to the cloned location path
103    * iterator to which this clone will be added.
104    * @param cloneList non-null vector of sources in odd elements, and the
105    * corresponding clones in even vectors.
106    *
107    * @return non-null clone, which may be a new clone, or may be a clone
108    * contained on the cloneList.
109    */

110   AxesWalker cloneDeep(WalkingIterator cloneOwner, Vector JavaDoc cloneList)
111      throws CloneNotSupportedException JavaDoc
112   {
113     AxesWalker clone = findClone(this, cloneList);
114     if(null != clone)
115       return clone;
116     clone = (AxesWalker)this.clone();
117     clone.setLocPathIterator(cloneOwner);
118     if(null != cloneList)
119     {
120       cloneList.addElement(this);
121       cloneList.addElement(clone);
122     }
123     
124     if(wi().m_lastUsedWalker == this)
125       cloneOwner.m_lastUsedWalker = clone;
126       
127     if(null != m_nextWalker)
128       clone.m_nextWalker = m_nextWalker.cloneDeep(cloneOwner, cloneList);
129       
130     // If you don't check for the cloneList here, you'll go into an
131
// recursive infinate loop.
132
if(null != cloneList)
133     {
134       if(null != m_prevWalker)
135         clone.m_prevWalker = m_prevWalker.cloneDeep(cloneOwner, cloneList);
136     }
137     else
138     {
139       if(null != m_nextWalker)
140         clone.m_nextWalker.m_prevWalker = clone;
141     }
142     return clone;
143   }
144   
145   /**
146    * Find a clone that corresponds to the key argument.
147    *
148    * @param key The original AxesWalker for which there may be a clone.
149    * @param cloneList vector of sources in odd elements, and the
150    * corresponding clones in even vectors, may be null.
151    *
152    * @return A clone that corresponds to the key, or null if key not found.
153    */

154   static AxesWalker findClone(AxesWalker key, Vector JavaDoc cloneList)
155   {
156     if(null != cloneList)
157     {
158       // First, look for clone on list.
159
int n = cloneList.size();
160       for (int i = 0; i < n; i+=2)
161       {
162         if(key == cloneList.elementAt(i))
163           return (AxesWalker)cloneList.elementAt(i+1);
164       }
165     }
166     return null;
167   }
168   
169   /**
170    * Detaches the walker from the set which it iterated over, releasing
171    * any computational resources and placing the iterator in the INVALID
172    * state.
173    */

174   public void detach()
175   {
176     m_currentNode = DTM.NULL;
177     m_dtm = null;
178     m_traverser = null;
179     m_isFresh = true;
180     m_root = DTM.NULL;
181   }
182   
183   //=============== TreeWalker Implementation ===============
184

185   /**
186    * The root node of the TreeWalker, as specified in setRoot(int root).
187    * Note that this may actually be below the current node.
188    *
189    * @return The context node of the step.
190    */

191   public int getRoot()
192   {
193     return m_root;
194   }
195   
196   /**
197    * Get the analysis bits for this walker, as defined in the WalkerFactory.
198    * @return One of WalkerFactory#BIT_DESCENDANT, etc.
199    */

200   public int getAnalysisBits()
201   {
202     int axis = getAxis();
203     int bit = WalkerFactory.getAnalysisBitFromAxes(axis);
204     return bit;
205   }
206
207   /**
208    * Set the root node of the TreeWalker.
209    * (Not part of the DOM2 TreeWalker interface).
210    *
211    * @param root The context node of this step.
212    */

213   public void setRoot(int root)
214   {
215     // %OPT% Get this directly from the lpi.
216
XPathContext xctxt = wi().getXPathContext();
217     m_dtm = xctxt.getDTM(root);
218     m_traverser = m_dtm.getAxisTraverser(m_axis);
219     m_isFresh = true;
220     m_foundLast = false;
221     m_root = root;
222     m_currentNode = root;
223
224     if (DTM.NULL == root)
225     {
226       throw new RuntimeException JavaDoc(
227         XSLMessages.createXPATHMessage(XPATHErrorResources.ER_SETTING_WALKER_ROOT_TO_NULL, null)); //"\n !!!! Error! Setting the root of a walker to null!!!");
228
}
229
230     resetProximityPositions();
231   }
232
233   /**
234    * The node at which the TreeWalker is currently positioned.
235    * <br> The value must not be null. Alterations to the DOM tree may cause
236    * the current node to no longer be accepted by the TreeWalker's
237    * associated filter. currentNode may also be explicitly set to any node,
238    * whether or not it is within the subtree specified by the root node or
239    * would be accepted by the filter and whatToShow flags. Further
240    * traversal occurs relative to currentNode even if it is not part of the
241    * current view by applying the filters in the requested direction (not
242    * changing currentNode where no traversal is possible).
243    *
244    * @return The node at which the TreeWalker is currently positioned, only null
245    * if setRoot has not yet been called.
246    */

247   public final int getCurrentNode()
248   {
249     return m_currentNode;
250   }
251
252   /**
253    * Set the next walker in the location step chain.
254    *
255    *
256    * @param walker Reference to AxesWalker derivative, or may be null.
257    */

258   public void setNextWalker(AxesWalker walker)
259   {
260     m_nextWalker = walker;
261   }
262
263   /**
264    * Get the next walker in the location step chain.
265    *
266    *
267    * @return Reference to AxesWalker derivative, or null.
268    */

269   public AxesWalker getNextWalker()
270   {
271     return m_nextWalker;
272   }
273
274   /**
275    * Set or clear the previous walker reference in the location step chain.
276    *
277    *
278    * @param walker Reference to previous walker reference in the location
279    * step chain, or null.
280    */

281   public void setPrevWalker(AxesWalker walker)
282   {
283     m_prevWalker = walker;
284   }
285
286   /**
287    * Get the previous walker reference in the location step chain.
288    *
289    *
290    * @return Reference to previous walker reference in the location
291    * step chain, or null.
292    */

293   public AxesWalker getPrevWalker()
294   {
295     return m_prevWalker;
296   }
297
298   /**
299    * This is simply a way to bottle-neck the return of the next node, for
300    * diagnostic purposes.
301    *
302    * @param n Node to return, or null.
303    *
304    * @return The argument.
305    */

306   private int returnNextNode(int n)
307   {
308
309     return n;
310   }
311
312   /**
313    * Get the next node in document order on the axes.
314    *
315    * @return the next node in document order on the axes, or null.
316    */

317   protected int getNextNode()
318   {
319     if (m_foundLast)
320       return DTM.NULL;
321
322     if (m_isFresh)
323     {
324       m_currentNode = m_traverser.first(m_root);
325       m_isFresh = false;
326     }
327     // I shouldn't have to do this the check for current node, I think.
328
// numbering\numbering24.xsl fails if I don't do this. I think
329
// it occurs as the walkers are backing up. -sb
330
else if(DTM.NULL != m_currentNode)
331     {
332       m_currentNode = m_traverser.next(m_root, m_currentNode);
333     }
334
335     if (DTM.NULL == m_currentNode)
336       this.m_foundLast = true;
337
338     return m_currentNode;
339   }
340
341   /**
342    * Moves the <code>TreeWalker</code> to the next visible node in document
343    * order relative to the current node, and returns the new node. If the
344    * current node has no next node, or if the search for nextNode attempts
345    * to step upward from the TreeWalker's root node, returns
346    * <code>null</code> , and retains the current node.
347    * @return The new node, or <code>null</code> if the current node has no
348    * next node in the TreeWalker's logical view.
349    */

350   public int nextNode()
351   {
352     int nextNode = DTM.NULL;
353     AxesWalker walker = wi().getLastUsedWalker();
354
355     while (true)
356     {
357       if (null == walker)
358         break;
359
360       nextNode = walker.getNextNode();
361
362       if (DTM.NULL == nextNode)
363       {
364
365         walker = walker.m_prevWalker;
366       }
367       else
368       {
369         if (walker.acceptNode(nextNode) != DTMIterator.FILTER_ACCEPT)
370         {
371           continue;
372         }
373
374         if (null == walker.m_nextWalker)
375         {
376           wi().setLastUsedWalker(walker);
377
378           // return walker.returnNextNode(nextNode);
379
break;
380         }
381         else
382         {
383           AxesWalker prev = walker;
384
385           walker = walker.m_nextWalker;
386
387           walker.setRoot(nextNode);
388
389           walker.m_prevWalker = prev;
390
391           continue;
392         }
393       } // if(null != nextNode)
394
} // while(null != walker)
395

396     return nextNode;
397   }
398
399   //============= End TreeWalker Implementation =============
400

401   /**
402    * Get the index of the last node that can be itterated to.
403    *
404    *
405    * @param xctxt XPath runtime context.
406    *
407    * @return the index of the last node that can be itterated to.
408    */

409   public int getLastPos(XPathContext xctxt)
410   {
411
412     int pos = getProximityPosition();
413     
414     AxesWalker walker;
415
416     try
417     {
418       walker = (AxesWalker) clone();
419     }
420     catch (CloneNotSupportedException JavaDoc cnse)
421     {
422       return -1;
423     }
424
425     walker.setPredicateCount(walker.getPredicateCount() - 1);
426     walker.setNextWalker(null);
427     walker.setPrevWalker(null);
428
429     WalkingIterator lpi = wi();
430     AxesWalker savedWalker = lpi.getLastUsedWalker();
431
432     try
433     {
434       lpi.setLastUsedWalker(walker);
435
436       int next;
437
438       while (DTM.NULL != (next = walker.nextNode()))
439       {
440         pos++;
441       }
442
443       // TODO: Should probably save this in the iterator.
444
}
445     finally
446     {
447       lpi.setLastUsedWalker(savedWalker);
448     }
449
450     // System.out.println("pos: "+pos);
451
return pos;
452   }
453   
454   //============= State Data =============
455

456   /**
457    * The DTM for the root. This can not be used, or must be changed,
458    * for the filter walker, or any walker that can have nodes
459    * from multiple documents.
460    * Never, ever, access this value without going through getDTM(int node).
461    */

462   private DTM m_dtm;
463   
464   /**
465    * Set the DTM for this walker.
466    *
467    * @param dtm Non-null reference to a DTM.
468    */

469   public void setDefaultDTM(DTM dtm)
470   {
471     m_dtm = dtm;
472   }
473   
474   /**
475    * Get the DTM for this walker.
476    *
477    * @return Non-null reference to a DTM.
478    */

479   public DTM getDTM(int node)
480   {
481     //
482
return wi().getXPathContext().getDTM(node);
483   }
484   
485   /**
486    * Returns true if all the nodes in the iteration well be returned in document
487    * order.
488    * Warning: This can only be called after setRoot has been called!
489    *
490    * @return true as a default.
491    */

492   public boolean isDocOrdered()
493   {
494     return true;
495   }
496   
497   /**
498    * Returns the axis being iterated, if it is known.
499    *
500    * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
501    * types.
502    */

503   public int getAxis()
504   {
505     return m_axis;
506   }
507   
508   /**
509    * This will traverse the heararchy, calling the visitor for
510    * each member. If the called visitor method returns
511    * false, the subtree should not be called.
512    *
513    * @param owner The owner of the visitor, where that path may be
514    * rewritten if needed.
515    * @param visitor The visitor whose appropriate method will be called.
516    */

517   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
518   {
519     if(visitor.visitStep(owner, this))
520     {
521         callPredicateVisitors(visitor);
522         if(null != m_nextWalker)
523         {
524             m_nextWalker.callVisitors(this, visitor);
525         }
526     }
527   }
528   
529   /**
530    * @see ExpressionOwner#getExpression()
531    */

532   public Expression getExpression()
533   {
534     return m_nextWalker;
535   }
536
537   /**
538    * @see ExpressionOwner#setExpression(Expression)
539    */

540   public void setExpression(Expression exp)
541   {
542     exp.exprSetParent(this);
543     m_nextWalker = (AxesWalker)exp;
544   }
545   
546     /**
547      * @see Expression#deepEquals(Expression)
548      */

549     public boolean deepEquals(Expression expr)
550     {
551       if (!super.deepEquals(expr))
552                 return false;
553
554       AxesWalker walker = (AxesWalker)expr;
555       if(this.m_axis != walker.m_axis)
556         return false;
557
558       return true;
559     }
560
561   /**
562    * The root node of the TreeWalker, as specified when it was created.
563    */

564   transient int m_root = DTM.NULL;
565
566   /**
567    * The node at which the TreeWalker is currently positioned.
568    */

569   private transient int m_currentNode = DTM.NULL;
570   
571   /** True if an itteration has not begun. */
572   transient boolean m_isFresh;
573
574   /** The next walker in the location step chain.
575    * @serial */

576   protected AxesWalker m_nextWalker;
577   
578   /** The previous walker in the location step chain, or null.
579    * @serial */

580   AxesWalker m_prevWalker;
581   
582   /** The traversal axis from where the nodes will be filtered. */
583   protected int m_axis = -1;
584
585   /** The DTM inner traversal class, that corresponds to the super axis. */
586   protected DTMAxisTraverser m_traverser;
587 }
588
Popular Tags