KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright 2002-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: NodeSequence.java,v 1.11 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.xml.dtm.DTM;
24 import org.apache.xml.dtm.DTMFilter;
25 import org.apache.xml.dtm.DTMIterator;
26 import org.apache.xml.dtm.DTMManager;
27 import org.apache.xml.utils.NodeVector;
28 import org.apache.xpath.NodeSetDTM;
29 import org.apache.xpath.XPathContext;
30 import org.apache.xpath.objects.XObject;
31
32 /**
33  * This class is the dynamic wrapper for a Xalan DTMIterator instance, and
34  * provides random access capabilities.
35  */

36 public class NodeSequence extends XObject
37   implements DTMIterator, Cloneable JavaDoc, PathComponent
38 {
39   /** The index of the last node in the iteration. */
40   protected int m_last = -1;
41   
42   /**
43    * The index of the next node to be fetched. Useful if this
44    * is a cached iterator, and is being used as random access
45    * NodeList.
46    */

47   protected int m_next = 0;
48     
49   /**
50    * If this iterator needs to cache nodes that are fetched, they
51    * are stored in the Vector in the generic object.
52    */

53   protected NodeVector getVector()
54   {
55     return (NodeVector)m_obj;
56   }
57   
58   /**
59    * Set the vector where nodes will be stored.
60    */

61   protected void SetVector(NodeVector v)
62   {
63     m_obj = v;
64   }
65
66   
67   /**
68    * If this iterator needs to cache nodes that are fetched, they
69    * are stored here.
70    */

71   public boolean hasCache()
72   {
73     return (m_obj != null);
74   }
75
76
77   /**
78    * The functional iterator that fetches nodes.
79    */

80   protected DTMIterator m_iter;
81   
82   /**
83    * Set the functional iterator that fetches nodes.
84    * @param iter The iterator that is to be contained.
85    */

86   public final void setIter(DTMIterator iter)
87   {
88     m_iter = iter;
89   }
90   
91   /**
92    * Get the functional iterator that fetches nodes.
93    * @return The contained iterator.
94    */

95   public final DTMIterator getContainedIter()
96   {
97     return m_iter;
98   }
99   
100   /**
101    * The DTMManager to use if we're using a NodeVector only.
102    * We may well want to do away with this, and store it in the NodeVector.
103    */

104   protected DTMManager m_dtmMgr;
105   
106   // ==== Constructors ====
107

108   /**
109    * Create a new NodeSequence from a (already cloned) iterator.
110    *
111    * @param iter Cloned (not static) DTMIterator.
112    * @param context The initial context node.
113    * @param xctxt The execution context.
114    * @param shouldCacheNodes True if this sequence can random access.
115    */

116   public NodeSequence(DTMIterator iter, int context, XPathContext xctxt, boolean shouldCacheNodes)
117   {
118     setIter(iter);
119     setRoot(context, xctxt);
120     setShouldCacheNodes(shouldCacheNodes);
121   }
122   
123   /**
124    * Create a new NodeSequence from a (already cloned) iterator.
125    *
126    * @param iter Cloned (not static) DTMIterator.
127    */

128   public NodeSequence(Object JavaDoc nodeVector)
129   {
130     super(nodeVector);
131     if(null != nodeVector)
132     {
133         assertion(nodeVector instanceof NodeVector,
134             "Must have a NodeVector as the object for NodeSequence!");
135         if(nodeVector instanceof DTMIterator)
136         {
137             setIter((DTMIterator)nodeVector);
138             m_last = ((DTMIterator)nodeVector).getLength();
139         }
140         
141     }
142   }
143   
144   /**
145    * Construct an empty XNodeSet object. This is used to create a mutable
146    * nodeset to which random nodes may be added.
147    */

148   public NodeSequence(DTMManager dtmMgr)
149   {
150     super(new NodeVector());
151     m_last = 0;
152     m_dtmMgr = dtmMgr;
153   }
154
155   
156   /**
157    * Create a new NodeSequence in an invalid (null) state.
158    */

159   public NodeSequence()
160   {
161   }
162
163
164   /**
165    * @see DTMIterator#getDTM(int)
166    */

167   public DTM getDTM(int nodeHandle)
168   {
169     DTMManager mgr = getDTMManager();
170     if(null != mgr)
171         return getDTMManager().getDTM(nodeHandle);
172     else
173     {
174         assertion(false, "Can not get a DTM Unless a DTMManager has been set!");
175         return null;
176     }
177   }
178
179   /**
180    * @see DTMIterator#getDTMManager()
181    */

182   public DTMManager getDTMManager()
183   {
184     return m_dtmMgr;
185   }
186
187   /**
188    * @see DTMIterator#getRoot()
189    */

190   public int getRoot()
191   {
192     if(null != m_iter)
193         return m_iter.getRoot();
194     else
195     {
196         // NodeSetDTM will call this, and so it's not a good thing to throw
197
// an assertion here.
198
// assertion(false, "Can not get the root from a non-iterated NodeSequence!");
199
return DTM.NULL;
200     }
201   }
202
203   /**
204    * @see DTMIterator#setRoot(int, Object)
205    */

206   public void setRoot(int nodeHandle, Object JavaDoc environment)
207   {
208     if(null != m_iter)
209     {
210         XPathContext xctxt = (XPathContext)environment;
211         m_dtmMgr = xctxt.getDTMManager();
212         m_iter.setRoot(nodeHandle, environment);
213         if(!m_iter.isDocOrdered())
214         {
215             if(!hasCache())
216                 setShouldCacheNodes(true);
217             runTo(-1);
218             m_next=0;
219         }
220     }
221     else
222         assertion(false, "Can not setRoot on a non-iterated NodeSequence!");
223   }
224
225   /**
226    * @see DTMIterator#reset()
227    */

228   public void reset()
229   {
230     m_next = 0;
231     // not resetting the iterator on purpose!!!
232
}
233
234   /**
235    * @see DTMIterator#getWhatToShow()
236    */

237   public int getWhatToShow()
238   {
239     return hasCache() ? (DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE)
240         : m_iter.getWhatToShow();
241   }
242
243   /**
244    * @see DTMIterator#getExpandEntityReferences()
245    */

246   public boolean getExpandEntityReferences()
247   {
248     if(null != m_iter)
249         return m_iter.getExpandEntityReferences();
250     else
251         return true;
252   }
253
254   /**
255    * @see DTMIterator#nextNode()
256    */

257   public int nextNode()
258   {
259     // If the cache is on, and the node has already been found, then
260
// just return from the list.
261
NodeVector vec = getVector();
262     if (null != vec)
263     {
264         if(m_next < vec.size())
265         {
266             int next = vec.elementAt(m_next);
267             m_next++;
268             return next;
269         }
270         else if((-1 != m_last) || (null == m_iter))
271         {
272             m_next++;
273             return DTM.NULL;
274         }
275     }
276     
277   if (null == m_iter)
278     return DTM.NULL;
279   
280     int next = m_iter.nextNode();
281     if(DTM.NULL != next)
282     {
283         if(hasCache())
284         {
285             if(m_iter.isDocOrdered())
286             {
287                 getVector().addElement(next);
288                 m_next++;
289             }
290             else
291             {
292                 int insertIndex = addNodeInDocOrder(next);
293                 if(insertIndex >= 0)
294                     m_next++;
295             }
296         }
297         else
298             m_next++;
299     }
300     else
301     {
302         m_last = m_next;
303         m_next++;
304     }
305         
306     return next;
307   }
308
309   /**
310    * @see DTMIterator#previousNode()
311    */

312   public int previousNode()
313   {
314     if(hasCache())
315     {
316         if(m_next <= 0)
317             return DTM.NULL;
318         else
319         {
320             m_next--;
321             return item(m_next);
322         }
323     }
324     else
325     {
326         int n = m_iter.previousNode();
327         m_next = m_iter.getCurrentPos();
328         return m_next;
329     }
330   }
331
332   /**
333    * @see DTMIterator#detach()
334    */

335   public void detach()
336   {
337     if(null != m_iter)
338         m_iter.detach();
339     super.detach();
340   }
341
342   /**
343    * Calling this with a value of false will cause the nodeset
344    * to be cached.
345    * @see DTMIterator#allowDetachToRelease(boolean)
346    */

347   public void allowDetachToRelease(boolean allowRelease)
348   {
349     if((false == allowRelease) && !hasCache())
350     {
351         setShouldCacheNodes(true);
352     }
353     
354     if(null != m_iter)
355         m_iter.allowDetachToRelease(allowRelease);
356     super.allowDetachToRelease(allowRelease);
357   }
358
359   /**
360    * @see DTMIterator#getCurrentNode()
361    */

362   public int getCurrentNode()
363   {
364     if(hasCache())
365     {
366         int currentIndex = m_next-1;
367         NodeVector vec = getVector();
368         if((currentIndex >= 0) && (currentIndex < vec.size()))
369             return vec.elementAt(currentIndex);
370         else
371             return DTM.NULL;
372     }
373     
374     if(null != m_iter)
375     {
376         return m_iter.getCurrentNode();
377     }
378     else
379         return DTM.NULL;
380   }
381
382   /**
383    * @see DTMIterator#isFresh()
384    */

385   public boolean isFresh()
386   {
387     return (0 == m_next);
388   }
389
390   /**
391    * @see DTMIterator#setShouldCacheNodes(boolean)
392    */

393   public void setShouldCacheNodes(boolean b)
394   {
395     if (b)
396     {
397       if(!hasCache())
398       {
399         SetVector(new NodeVector());
400       }
401 // else
402
// getVector().RemoveAllNoClear(); // Is this good?
403
}
404     else
405       SetVector(null);
406   }
407
408   /**
409    * @see DTMIterator#isMutable()
410    */

411   public boolean isMutable()
412   {
413     return hasCache(); // though may be surprising if it also has an iterator!
414
}
415
416   /**
417    * @see DTMIterator#getCurrentPos()
418    */

419   public int getCurrentPos()
420   {
421     return m_next;
422   }
423
424   /**
425    * @see DTMIterator#runTo(int)
426    */

427   public void runTo(int index)
428   {
429     int n;
430     
431     if (-1 == index)
432     {
433       int pos = m_next;
434       while (DTM.NULL != (n = nextNode()));
435       m_next = pos;
436     }
437     else if(m_next == index)
438     {
439       return;
440     }
441     else if(hasCache() && m_next < getVector().size())
442     {
443       m_next = index;
444     }
445     else if((null == getVector()) && (index < m_next))
446     {
447       while ((m_next >= index) && DTM.NULL != (n = previousNode()));
448     }
449     else
450     {
451       while ((m_next < index) && DTM.NULL != (n = nextNode()));
452     }
453     
454   }
455
456   /**
457    * @see DTMIterator#setCurrentPos(int)
458    */

459   public void setCurrentPos(int i)
460   {
461     runTo(i);
462   }
463
464   /**
465    * @see DTMIterator#item(int)
466    */

467   public int item(int index)
468   {
469     setCurrentPos(index);
470     int n = nextNode();
471     m_next = index;
472     return n;
473   }
474
475   /**
476    * @see DTMIterator#setItem(int, int)
477    */

478   public void setItem(int node, int index)
479   {
480     NodeVector vec = getVector();
481     if(null != vec)
482     {
483         vec.setElementAt(node, index);
484         m_last = vec.size();
485     }
486     else
487         m_iter.setItem(node, index);
488   }
489
490   /**
491    * @see DTMIterator#getLength()
492    */

493   public int getLength()
494   {
495     if(hasCache())
496     {
497         // If this NodeSequence wraps a mutable nodeset, then
498
// m_last will not reflect the size of the nodeset if
499
// it has been mutated...
500
if (m_iter instanceof NodeSetDTM)
501         {
502             return m_iter.getLength();
503         }
504         
505         if(-1 == m_last)
506         {
507             int pos = m_next;
508             runTo(-1);
509             m_next = pos;
510         }
511         return m_last;
512     }
513     else
514     {
515         return (-1 == m_last) ? (m_last = m_iter.getLength()) : m_last;
516     }
517   }
518
519   /**
520    * Note: Not a deep clone.
521    * @see DTMIterator#cloneWithReset()
522    */

523   public DTMIterator cloneWithReset() throws CloneNotSupportedException JavaDoc
524   {
525     NodeSequence seq = (NodeSequence)super.clone();
526     seq.m_next = 0;
527     return seq;
528   }
529   
530   /**
531    * Get a clone of this iterator, but don't reset the iteration in the
532    * process, so that it may be used from the current position.
533    * Note: Not a deep clone.
534    *
535    * @return A clone of this object.
536    *
537    * @throws CloneNotSupportedException
538    */

539   public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc
540   {
541     return super.clone();
542   }
543
544
545   /**
546    * @see DTMIterator#isDocOrdered()
547    */

548   public boolean isDocOrdered()
549   {
550     if(null != m_iter)
551         return m_iter.isDocOrdered();
552     else
553         return true; // can't be sure?
554
}
555
556   /**
557    * @see DTMIterator#getAxis()
558    */

559   public int getAxis()
560   {
561     if(null != m_iter)
562         return m_iter.getAxis();
563     else
564     {
565         assertion(false, "Can not getAxis from a non-iterated node sequence!");
566         return 0;
567     }
568   }
569
570   /**
571    * @see PathComponent#getAnalysisBits()
572    */

573   public int getAnalysisBits()
574   {
575     if((null != m_iter) && (m_iter instanceof PathComponent))
576         return ((PathComponent)m_iter).getAnalysisBits();
577     else
578         return 0;
579   }
580
581   /**
582    * @see org.apache.xpath.Expression#fixupVariables(Vector, int)
583    */

584   public void fixupVariables(Vector JavaDoc vars, int globalsSize)
585   {
586     super.fixupVariables(vars, globalsSize);
587   }
588   
589   /**
590    * Add the node into a vector of nodes where it should occur in
591    * document order.
592    * @param v Vector of nodes, presumably containing Nodes
593    * @param obj Node object.
594    *
595    * @param node The node to be added.
596    * @param test true if we should test for doc order
597    * @param support The XPath runtime context.
598    * @return insertIndex.
599    * @throws RuntimeException thrown if this NodeSetDTM is not of
600    * a mutable type.
601    */

602    protected int addNodeInDocOrder(int node)
603    {
604       assertion(hasCache(), "addNodeInDocOrder must be done on a mutable sequence!");
605
606       int insertIndex = -1;
607       
608       NodeVector vec = getVector();
609
610       // This needs to do a binary search, but a binary search
611
// is somewhat tough because the sequence test involves
612
// two nodes.
613
int size = vec.size(), i;
614
615       for (i = size - 1; i >= 0; i--)
616       {
617         int child = vec.elementAt(i);
618
619         if (child == node)
620         {
621           i = -2; // Duplicate, suppress insert
622

623           break;
624         }
625
626         DTM dtm = m_dtmMgr.getDTM(node);
627         if (!dtm.isNodeAfter(node, child))
628         {
629           break;
630         }
631       }
632
633       if (i != -2)
634       {
635         insertIndex = i + 1;
636
637         vec.insertElementAt(node, insertIndex);
638       }
639
640       // checkDups();
641
return insertIndex;
642     } // end addNodeInDocOrder(Vector v, Object obj)
643
}
644
645
Popular Tags