KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xpath > NodeSetDTM


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: NodeSetDTM.java,v 1.15 2004/02/17 04:30:02 minchau Exp $
18  */

19 package org.apache.xpath;
20
21 import org.apache.xalan.res.XSLMessages;
22 import org.apache.xml.dtm.DTM;
23 import org.apache.xml.dtm.DTMFilter;
24 import org.apache.xml.dtm.DTMIterator;
25 import org.apache.xml.dtm.DTMManager;
26 import org.apache.xml.utils.NodeVector;
27 import org.apache.xpath.res.XPATHErrorResources;
28
29 import org.w3c.dom.Node JavaDoc;
30 import org.w3c.dom.NodeList JavaDoc;
31 import org.w3c.dom.traversal.NodeIterator;
32
33
34 /**
35  * <p>The NodeSetDTM class can act as either a NodeVector,
36  * NodeList, or NodeIterator. However, in order for it to
37  * act as a NodeVector or NodeList, it's required that
38  * setShouldCacheNodes(true) be called before the first
39  * nextNode() is called, in order that nodes can be added
40  * as they are fetched. Derived classes that implement iterators
41  * must override runTo(int index), in order that they may
42  * run the iteration to the given index. </p>
43  *
44  * <p>Note that we directly implement the DOM's NodeIterator
45  * interface. We do not emulate all the behavior of the
46  * standard NodeIterator. In particular, we do not guarantee
47  * to present a "live view" of the document ... but in XSLT,
48  * the source document should never be mutated, so this should
49  * never be an issue.</p>
50  *
51  * <p>Thought: Should NodeSetDTM really implement NodeList and NodeIterator,
52  * or should there be specific subclasses of it which do so? The
53  * advantage of doing it all here is that all NodeSetDTMs will respond
54  * to the same calls; the disadvantage is that some of them may return
55  * less-than-enlightening results when you do so.</p>
56  * @xsl.usage advanced
57  */

58 public class NodeSetDTM extends NodeVector
59         implements /* NodeList, NodeIterator, */ DTMIterator,
60         Cloneable JavaDoc
61 {
62
63   /**
64    * Create an empty nodelist.
65    */

66   public NodeSetDTM(DTMManager dtmManager)
67   {
68     super();
69     m_manager = dtmManager;
70   }
71
72   /**
73    * Create an empty, using the given block size.
74    *
75    * @param blocksize Size of blocks to allocate
76    * @param dummy pass zero for right now...
77    */

78   public NodeSetDTM(int blocksize, int dummy, DTMManager dtmManager)
79   {
80     super(blocksize);
81     m_manager = dtmManager;
82   }
83
84   // %TBD%
85
// /**
86
// * Create a NodeSetDTM, and copy the members of the
87
// * given nodelist into it.
88
// *
89
// * @param nodelist List of Nodes to be made members of the new set.
90
// */
91
// public NodeSetDTM(NodeList nodelist)
92
// {
93
//
94
// super();
95
//
96
// addNodes(nodelist);
97
// }
98

99   /**
100    * Create a NodeSetDTM, and copy the members of the
101    * given NodeSetDTM into it.
102    *
103    * @param nodelist Set of Nodes to be made members of the new set.
104    */

105   public NodeSetDTM(NodeSetDTM nodelist)
106   {
107
108     super();
109     m_manager = nodelist.getDTMManager();
110     m_root = nodelist.getRoot();
111
112     addNodes((DTMIterator) nodelist);
113   }
114
115   /**
116    * Create a NodeSetDTM, and copy the members of the
117    * given DTMIterator into it.
118    *
119    * @param ni Iterator which yields Nodes to be made members of the new set.
120    */

121   public NodeSetDTM(DTMIterator ni)
122   {
123
124     super();
125
126     m_manager = ni.getDTMManager();
127     m_root = ni.getRoot();
128     addNodes(ni);
129   }
130   
131   /**
132    * Create a NodeSetDTM, and copy the members of the
133    * given DTMIterator into it.
134    *
135    * @param ni Iterator which yields Nodes to be made members of the new set.
136    */

137   public NodeSetDTM(NodeIterator iterator, XPathContext xctxt)
138   {
139
140     super();
141
142     Node JavaDoc node;
143     m_manager = xctxt.getDTMManager();
144
145     while (null != (node = iterator.nextNode()))
146     {
147       int handle = xctxt.getDTMHandleFromNode(node);
148       addNodeInDocOrder(handle, xctxt);
149     }
150   }
151   
152   /**
153    * Create a NodeSetDTM, and copy the members of the
154    * given DTMIterator into it.
155    *
156    * @param ni Iterator which yields Nodes to be made members of the new set.
157    */

158   public NodeSetDTM(NodeList JavaDoc nodeList, XPathContext xctxt)
159   {
160
161     super();
162
163     m_manager = xctxt.getDTMManager();
164
165     int n = nodeList.getLength();
166     for (int i = 0; i < n; i++)
167     {
168       Node JavaDoc node = nodeList.item(i);
169       int handle = xctxt.getDTMHandleFromNode(node);
170       // Do not reorder or strip duplicate nodes from the given DOM nodelist
171
addNode(handle); // addNodeInDocOrder(handle, xctxt);
172
}
173   }
174
175
176   /**
177    * Create a NodeSetDTM which contains the given Node.
178    *
179    * @param node Single node to be added to the new set.
180    */

181   public NodeSetDTM(int node, DTMManager dtmManager)
182   {
183
184     super();
185     m_manager = dtmManager;
186
187     addNode(node);
188   }
189   
190   /**
191    * Set the environment in which this iterator operates, which should provide:
192    * a node (the context node... same value as "root" defined below)
193    * a pair of non-zero positive integers (the context position and the context size)
194    * a set of variable bindings
195    * a function library
196    * the set of namespace declarations in scope for the expression.
197    *
198    * <p>At this time the exact implementation of this environment is application
199    * dependent. Probably a proper interface will be created fairly soon.</p>
200    *
201    * @param environment The environment object.
202    */

203   public void setEnvironment(Object JavaDoc environment)
204   {
205     // no-op
206
}
207
208
209   /**
210    * @return The root node of the Iterator, as specified when it was created.
211    * For non-Iterator NodeSetDTMs, this will be null.
212    */

213   public int getRoot()
214   {
215     if(DTM.NULL == m_root)
216     {
217       if(size() > 0)
218         return item(0);
219       else
220         return DTM.NULL;
221     }
222     else
223       return m_root;
224   }
225   
226   /**
227    * Initialize the context values for this expression
228    * after it is cloned.
229    *
230    * @param execContext The XPath runtime context for this
231    * transformation.
232    */

233   public void setRoot(int context, Object JavaDoc environment)
234   {
235     // no-op, I guess... (-sb)
236
}
237
238   /**
239    * Clone this NodeSetDTM.
240    * At this time, we only expect this to be used with LocPathIterators;
241    * it may not work with other kinds of NodeSetDTMs.
242    *
243    * @return a new NodeSetDTM of the same type, having the same state...
244    * though unless overridden in the subclasses, it may not copy all
245    * the state information.
246    *
247    * @throws CloneNotSupportedException if this subclass of NodeSetDTM
248    * does not support the clone() operation.
249    */

250   public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc
251   {
252
253     NodeSetDTM clone = (NodeSetDTM) super.clone();
254
255     return clone;
256   }
257
258   /**
259    * Get a cloned Iterator, and reset its state to the beginning of the
260    * iteration.
261    *
262    * @return a new NodeSetDTM of the same type, having the same state...
263    * except that the reset() operation has been called.
264    *
265    * @throws CloneNotSupportedException if this subclass of NodeSetDTM
266    * does not support the clone() operation.
267    */

268   public DTMIterator cloneWithReset() throws CloneNotSupportedException JavaDoc
269   {
270
271     NodeSetDTM clone = (NodeSetDTM) clone();
272
273     clone.reset();
274
275     return clone;
276   }
277
278   /**
279    * Reset the iterator. May have no effect on non-iterator Nodesets.
280    */

281   public void reset()
282   {
283     m_next = 0;
284   }
285
286   /**
287    * This attribute determines which node types are presented via the
288    * iterator. The available set of constants is defined in the
289    * <code>DTMFilter</code> interface. For NodeSetDTMs, the mask has been
290    * hardcoded to show all nodes except EntityReference nodes, which have
291    * no equivalent in the XPath data model.
292    *
293    * @return integer used as a bit-array, containing flags defined in
294    * the DOM's DTMFilter class. The value will be
295    * <code>SHOW_ALL & ~SHOW_ENTITY_REFERENCE</code>, meaning that
296    * only entity references are suppressed.
297    */

298   public int getWhatToShow()
299   {
300     return DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE;
301   }
302
303   /**
304    * The filter object used to screen nodes. Filters are applied to
305    * further reduce (and restructure) the DTMIterator's view of the
306    * document. In our case, we will be using hardcoded filters built
307    * into our iterators... but getFilter() is part of the DOM's
308    * DTMIterator interface, so we have to support it.
309    *
310    * @return null, which is slightly misleading. True, there is no
311    * user-written filter object, but in fact we are doing some very
312    * sophisticated custom filtering. A DOM purist might suggest
313    * returning a placeholder object just to indicate that this is
314    * not going to return all nodes selected by whatToShow.
315    */

316   public DTMFilter getFilter()
317   {
318     return null;
319   }
320
321   /**
322    * The value of this flag determines whether the children of entity
323    * reference nodes are visible to the iterator. If false, they will be
324    * skipped over.
325    * <br> To produce a view of the document that has entity references
326    * expanded and does not expose the entity reference node itself, use the
327    * whatToShow flags to hide the entity reference node and set
328    * expandEntityReferences to true when creating the iterator. To produce
329    * a view of the document that has entity reference nodes but no entity
330    * expansion, use the whatToShow flags to show the entity reference node
331    * and set expandEntityReferences to false.
332    *
333    * @return true for all iterators based on NodeSetDTM, meaning that the
334    * contents of EntityRefrence nodes may be returned (though whatToShow
335    * says that the EntityReferences themselves are not shown.)
336    */

337   public boolean getExpandEntityReferences()
338   {
339     return true;
340   }
341   
342   /**
343    * Get an instance of a DTM that "owns" a node handle. Since a node
344    * iterator may be passed without a DTMManager, this allows the
345    * caller to easily get the DTM using just the iterator.
346    *
347    * @param nodeHandle the nodeHandle.
348    *
349    * @return a non-null DTM reference.
350    */

351   public DTM getDTM(int nodeHandle)
352   {
353     
354     return m_manager.getDTM(nodeHandle);
355   }
356   
357   /* An instance of the DTMManager. */
358   DTMManager m_manager;
359   
360   /**
361    * Get an instance of the DTMManager. Since a node
362    * iterator may be passed without a DTMManager, this allows the
363    * caller to easily get the DTMManager using just the iterator.
364    *
365    * @return a non-null DTMManager reference.
366    */

367   public DTMManager getDTMManager()
368   {
369     
370     return m_manager;
371   }
372
373   /**
374    * Returns the next node in the set and advances the position of the
375    * iterator in the set. After a DTMIterator is created, the first call
376    * to nextNode() returns the first node in the set.
377    * @return The next <code>Node</code> in the set being iterated over, or
378    * <code>DTM.NULL</code> if there are no more members in that set.
379    * @throws DOMException
380    * INVALID_STATE_ERR: Raised if this method is called after the
381    * <code>detach</code> method was invoked.
382    */

383   public int nextNode()
384   {
385
386     if ((m_next) < this.size())
387     {
388       int next = this.elementAt(m_next);
389
390       m_next++;
391
392       return next;
393     }
394     else
395       return DTM.NULL;
396   }
397
398   /**
399    * Returns the previous node in the set and moves the position of the
400    * iterator backwards in the set.
401    * @return The previous <code>Node</code> in the set being iterated over,
402    * or<code>DTM.NULL</code> if there are no more members in that set.
403    * @throws DOMException
404    * INVALID_STATE_ERR: Raised if this method is called after the
405    * <code>detach</code> method was invoked.
406    * @throws RuntimeException thrown if this NodeSetDTM is not of
407    * a cached type, and hence doesn't know what the previous node was.
408    */

409   public int previousNode()
410   {
411
412     if (!m_cacheNodes)
413       throw new RuntimeException JavaDoc(
414         XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_ITERATE, null)); //"This NodeSetDTM can not iterate to a previous node!");
415

416     if ((m_next - 1) > 0)
417     {
418       m_next--;
419
420       return this.elementAt(m_next);
421     }
422     else
423       return DTM.NULL;
424   }
425
426   /**
427    * Detaches the iterator from the set which it iterated over, releasing
428    * any computational resources and placing the iterator in the INVALID
429    * state. After<code>detach</code> has been invoked, calls to
430    * <code>nextNode</code> or<code>previousNode</code> will raise the
431    * exception INVALID_STATE_ERR.
432    * <p>
433    * This operation is a no-op in NodeSetDTM, and will not cause
434    * INVALID_STATE_ERR to be raised by later operations.
435    * </p>
436    */

437   public void detach(){}
438   
439   /**
440    * Specify if it's OK for detach to release the iterator for reuse.
441    *
442    * @param allowRelease true if it is OK for detach to release this iterator
443    * for pooling.
444    */

445   public void allowDetachToRelease(boolean allowRelease)
446   {
447     // no action for right now.
448
}
449
450
451   /**
452    * Tells if this NodeSetDTM is "fresh", in other words, if
453    * the first nextNode() that is called will return the
454    * first node in the set.
455    *
456    * @return true if nextNode() would return the first node in the set,
457    * false if it would return a later one.
458    */

459   public boolean isFresh()
460   {
461     return (m_next == 0);
462   }
463
464   /**
465    * If an index is requested, NodeSetDTM will call this method
466    * to run the iterator to the index. By default this sets
467    * m_next to the index. If the index argument is -1, this
468    * signals that the iterator should be run to the end.
469    *
470    * @param index Position to advance (or retreat) to, with
471    * 0 requesting the reset ("fresh") position and -1 (or indeed
472    * any out-of-bounds value) requesting the final position.
473    * @throws RuntimeException thrown if this NodeSetDTM is not
474    * one of the types which supports indexing/counting.
475    */

476   public void runTo(int index)
477   {
478
479     if (!m_cacheNodes)
480       throw new RuntimeException JavaDoc(
481         XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_INDEX, null)); //"This NodeSetDTM can not do indexing or counting functions!");
482

483     if ((index >= 0) && (m_next < m_firstFree))
484       m_next = index;
485     else
486       m_next = m_firstFree - 1;
487   }
488
489   /**
490    * Returns the <code>index</code>th item in the collection. If
491    * <code>index</code> is greater than or equal to the number of nodes in
492    * the list, this returns <code>null</code>.
493    *
494    * TODO: What happens if index is out of range?
495    *
496    * @param index Index into the collection.
497    * @return The node at the <code>index</code>th position in the
498    * <code>NodeList</code>, or <code>null</code> if that is not a valid
499    * index.
500    */

501   public int item(int index)
502   {
503
504     runTo(index);
505
506     return this.elementAt(index);
507   }
508
509   /**
510    * The number of nodes in the list. The range of valid child node indices is
511    * 0 to <code>length-1</code> inclusive. Note that this operation requires
512    * finding all the matching nodes, which may defeat attempts to defer
513    * that work.
514    *
515    * @return integer indicating how many nodes are represented by this list.
516    */

517   public int getLength()
518   {
519
520     runTo(-1);
521
522     return this.size();
523   }
524
525   /**
526    * Add a node to the NodeSetDTM. Not all types of NodeSetDTMs support this
527    * operation
528    *
529    * @param n Node to be added
530    * @throws RuntimeException thrown if this NodeSetDTM is not of
531    * a mutable type.
532    */

533   public void addNode(int n)
534   {
535
536     if (!m_mutable)
537       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
538

539     this.addElement(n);
540   }
541
542   /**
543    * Insert a node at a given position.
544    *
545    * @param n Node to be added
546    * @param pos Offset at which the node is to be inserted,
547    * with 0 being the first position.
548    * @throws RuntimeException thrown if this NodeSetDTM is not of
549    * a mutable type.
550    */

551   public void insertNode(int n, int pos)
552   {
553
554     if (!m_mutable)
555       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
556

557     insertElementAt(n, pos);
558   }
559
560   /**
561    * Remove a node.
562    *
563    * @param n Node to be added
564    * @throws RuntimeException thrown if this NodeSetDTM is not of
565    * a mutable type.
566    */

567   public void removeNode(int n)
568   {
569
570     if (!m_mutable)
571       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
572

573     this.removeElement(n);
574   }
575
576   // %TBD%
577
// /**
578
// * Copy NodeList members into this nodelist, adding in
579
// * document order. If a node is null, don't add it.
580
// *
581
// * @param nodelist List of nodes which should now be referenced by
582
// * this NodeSetDTM.
583
// * @throws RuntimeException thrown if this NodeSetDTM is not of
584
// * a mutable type.
585
// */
586
// public void addNodes(NodeList nodelist)
587
// {
588
//
589
// if (!m_mutable)
590
// throw new RuntimeException("This NodeSetDTM is not mutable!");
591
//
592
// if (null != nodelist) // defensive to fix a bug that Sanjiva reported.
593
// {
594
// int nChildren = nodelist.getLength();
595
//
596
// for (int i = 0; i < nChildren; i++)
597
// {
598
// int obj = nodelist.item(i);
599
//
600
// if (null != obj)
601
// {
602
// addElement(obj);
603
// }
604
// }
605
// }
606
//
607
// // checkDups();
608
// }
609

610   // %TBD%
611
// /**
612
// * <p>Copy NodeList members into this nodelist, adding in
613
// * document order. Only genuine node references will be copied;
614
// * nulls appearing in the source NodeSetDTM will
615
// * not be added to this one. </p>
616
// *
617
// * <p> In case you're wondering why this function is needed: NodeSetDTM
618
// * implements both DTMIterator and NodeList. If this method isn't
619
// * provided, Java can't decide which of those to use when addNodes()
620
// * is invoked. Providing the more-explicit match avoids that
621
// * ambiguity.)</p>
622
// *
623
// * @param ns NodeSetDTM whose members should be merged into this NodeSetDTM.
624
// * @throws RuntimeException thrown if this NodeSetDTM is not of
625
// * a mutable type.
626
// */
627
// public void addNodes(NodeSetDTM ns)
628
// {
629
//
630
// if (!m_mutable)
631
// throw new RuntimeException("This NodeSetDTM is not mutable!");
632
//
633
// addNodes((DTMIterator) ns);
634
// }
635

636   /**
637    * Copy NodeList members into this nodelist, adding in
638    * document order. Null references are not added.
639    *
640    * @param iterator DTMIterator which yields the nodes to be added.
641    * @throws RuntimeException thrown if this NodeSetDTM is not of
642    * a mutable type.
643    */

644   public void addNodes(DTMIterator iterator)
645   {
646
647     if (!m_mutable)
648       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
649

650     if (null != iterator) // defensive to fix a bug that Sanjiva reported.
651
{
652       int obj;
653
654       while (DTM.NULL != (obj = iterator.nextNode()))
655       {
656         addElement(obj);
657       }
658     }
659
660     // checkDups();
661
}
662
663   // %TBD%
664
// /**
665
// * Copy NodeList members into this nodelist, adding in
666
// * document order. If a node is null, don't add it.
667
// *
668
// * @param nodelist List of nodes to be added
669
// * @param support The XPath runtime context.
670
// * @throws RuntimeException thrown if this NodeSetDTM is not of
671
// * a mutable type.
672
// */
673
// public void addNodesInDocOrder(NodeList nodelist, XPathContext support)
674
// {
675
//
676
// if (!m_mutable)
677
// throw new RuntimeException("This NodeSetDTM is not mutable!");
678
//
679
// int nChildren = nodelist.getLength();
680
//
681
// for (int i = 0; i < nChildren; i++)
682
// {
683
// int node = nodelist.item(i);
684
//
685
// if (null != node)
686
// {
687
// addNodeInDocOrder(node, support);
688
// }
689
// }
690
// }
691

692   /**
693    * Copy NodeList members into this nodelist, adding in
694    * document order. If a node is null, don't add it.
695    *
696    * @param iterator DTMIterator which yields the nodes to be added.
697    * @param support The XPath runtime context.
698    * @throws RuntimeException thrown if this NodeSetDTM is not of
699    * a mutable type.
700    */

701   public void addNodesInDocOrder(DTMIterator iterator, XPathContext support)
702   {
703
704     if (!m_mutable)
705       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
706

707     int node;
708
709     while (DTM.NULL != (node = iterator.nextNode()))
710     {
711       addNodeInDocOrder(node, support);
712     }
713   }
714
715   // %TBD%
716
// /**
717
// * Add the node list to this node set in document order.
718
// *
719
// * @param start index.
720
// * @param end index.
721
// * @param testIndex index.
722
// * @param nodelist The nodelist to add.
723
// * @param support The XPath runtime context.
724
// *
725
// * @return false always.
726
// * @throws RuntimeException thrown if this NodeSetDTM is not of
727
// * a mutable type.
728
// */
729
// private boolean addNodesInDocOrder(int start, int end, int testIndex,
730
// NodeList nodelist, XPathContext support)
731
// {
732
//
733
// if (!m_mutable)
734
// throw new RuntimeException("This NodeSetDTM is not mutable!");
735
//
736
// boolean foundit = false;
737
// int i;
738
// int node = nodelist.item(testIndex);
739
//
740
// for (i = end; i >= start; i--)
741
// {
742
// int child = elementAt(i);
743
//
744
// if (child == node)
745
// {
746
// i = -2; // Duplicate, suppress insert
747
//
748
// break;
749
// }
750
//
751
// if (!support.getDOMHelper().isNodeAfter(node, child))
752
// {
753
// insertElementAt(node, i + 1);
754
//
755
// testIndex--;
756
//
757
// if (testIndex > 0)
758
// {
759
// boolean foundPrev = addNodesInDocOrder(0, i, testIndex, nodelist,
760
// support);
761
//
762
// if (!foundPrev)
763
// {
764
// addNodesInDocOrder(i, size() - 1, testIndex, nodelist, support);
765
// }
766
// }
767
//
768
// break;
769
// }
770
// }
771
//
772
// if (i == -1)
773
// {
774
// insertElementAt(node, 0);
775
// }
776
//
777
// return foundit;
778
// }
779

780   /**
781    * Add the node into a vector of nodes where it should occur in
782    * document order.
783    * @param v Vector of nodes, presumably containing Nodes
784    * @param obj Node object.
785    *
786    * @param node The node to be added.
787    * @param test true if we should test for doc order
788    * @param support The XPath runtime context.
789    * @return insertIndex.
790    * @throws RuntimeException thrown if this NodeSetDTM is not of
791    * a mutable type.
792    */

793   public int addNodeInDocOrder(int node, boolean test, XPathContext support)
794   {
795
796     if (!m_mutable)
797       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
798

799     int insertIndex = -1;
800
801     if (test)
802     {
803
804       // This needs to do a binary search, but a binary search
805
// is somewhat tough because the sequence test involves
806
// two nodes.
807
int size = size(), i;
808
809       for (i = size - 1; i >= 0; i--)
810       {
811         int child = elementAt(i);
812
813         if (child == node)
814         {
815           i = -2; // Duplicate, suppress insert
816

817           break;
818         }
819
820         DTM dtm = support.getDTM(node);
821         if (!dtm.isNodeAfter(node, child))
822         {
823           break;
824         }
825       }
826
827       if (i != -2)
828       {
829         insertIndex = i + 1;
830
831         insertElementAt(node, insertIndex);
832       }
833     }
834     else
835     {
836       insertIndex = this.size();
837
838       boolean foundit = false;
839
840       for (int i = 0; i < insertIndex; i++)
841       {
842         if (i == node)
843         {
844           foundit = true;
845
846           break;
847         }
848       }
849
850       if (!foundit)
851         addElement(node);
852     }
853
854     // checkDups();
855
return insertIndex;
856   } // end addNodeInDocOrder(Vector v, Object obj)
857

858   /**
859    * Add the node into a vector of nodes where it should occur in
860    * document order.
861    * @param v Vector of nodes, presumably containing Nodes
862    * @param obj Node object.
863    *
864    * @param node The node to be added.
865    * @param support The XPath runtime context.
866    *
867    * @return The index where it was inserted.
868    * @throws RuntimeException thrown if this NodeSetDTM is not of
869    * a mutable type.
870    */

871   public int addNodeInDocOrder(int node, XPathContext support)
872   {
873
874     if (!m_mutable)
875       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
876

877     return addNodeInDocOrder(node, true, support);
878   } // end addNodeInDocOrder(Vector v, Object obj)
879

880   /**
881    * Get the length of the list.
882    *
883    * @return The size of this node set.
884    */

885   public int size()
886   {
887     return super.size();
888   }
889
890   /**
891    * Append a Node onto the vector.
892    *
893    * @param value The node to be added.
894    * @throws RuntimeException thrown if this NodeSetDTM is not of
895    * a mutable type.
896    */

897   public void addElement(int value)
898   {
899
900     if (!m_mutable)
901       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
902

903     super.addElement(value);
904   }
905
906   /**
907    * Inserts the specified node in this vector at the specified index.
908    * Each component in this vector with an index greater or equal to
909    * the specified index is shifted upward to have an index one greater
910    * than the value it had previously.
911    *
912    * @param value The node to be inserted.
913    * @param at The index where the insert should occur.
914    * @throws RuntimeException thrown if this NodeSetDTM is not of
915    * a mutable type.
916    */

917   public void insertElementAt(int value, int at)
918   {
919
920     if (!m_mutable)
921       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
922

923     super.insertElementAt(value, at);
924   }
925
926   /**
927    * Append the nodes to the list.
928    *
929    * @param nodes The nodes to be appended to this node set.
930    * @throws RuntimeException thrown if this NodeSetDTM is not of
931    * a mutable type.
932    */

933   public void appendNodes(NodeVector nodes)
934   {
935
936     if (!m_mutable)
937       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
938

939     super.appendNodes(nodes);
940   }
941
942   /**
943    * Inserts the specified node in this vector at the specified index.
944    * Each component in this vector with an index greater or equal to
945    * the specified index is shifted upward to have an index one greater
946    * than the value it had previously.
947    * @throws RuntimeException thrown if this NodeSetDTM is not of
948    * a mutable type.
949    */

950   public void removeAllElements()
951   {
952
953     if (!m_mutable)
954       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
955

956     super.removeAllElements();
957   }
958
959   /**
960    * Removes the first occurrence of the argument from this vector.
961    * If the object is found in this vector, each component in the vector
962    * with an index greater or equal to the object's index is shifted
963    * downward to have an index one smaller than the value it had
964    * previously.
965    *
966    * @param s The node to be removed.
967    *
968    * @return True if the node was successfully removed
969    * @throws RuntimeException thrown if this NodeSetDTM is not of
970    * a mutable type.
971    */

972   public boolean removeElement(int s)
973   {
974
975     if (!m_mutable)
976       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
977

978     return super.removeElement(s);
979   }
980
981   /**
982    * Deletes the component at the specified index. Each component in
983    * this vector with an index greater or equal to the specified
984    * index is shifted downward to have an index one smaller than
985    * the value it had previously.
986    *
987    * @param i The index of the node to be removed.
988    * @throws RuntimeException thrown if this NodeSetDTM is not of
989    * a mutable type.
990    */

991   public void removeElementAt(int i)
992   {
993
994     if (!m_mutable)
995       throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
996

997     super.removeElementAt(i);
998   }
999
1000  /**
1001   * Sets the component at the specified index of this vector to be the
1002   * specified object. The previous component at that position is discarded.
1003   *
1004   * The index must be a value greater than or equal to 0 and less
1005   * than the current size of the vector.
1006   *
1007   * @param node The node to be set.
1008   * @param index The index of the node to be replaced.
1009   * @throws RuntimeException thrown if this NodeSetDTM is not of
1010   * a mutable type.
1011   */

1012  public void setElementAt(int node, int index)
1013  {
1014
1015    if (!m_mutable)
1016      throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
1017

1018    super.setElementAt(node, index);
1019  }
1020  
1021  /**
1022   * Same as setElementAt.
1023   *
1024   * @param node The node to be set.
1025   * @param index The index of the node to be replaced.
1026   * @throws RuntimeException thrown if this NodeSetDTM is not of
1027   * a mutable type.
1028   */

1029  public void setItem(int node, int index)
1030  {
1031
1032    if (!m_mutable)
1033      throw new RuntimeException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
1034

1035    super.setElementAt(node, index);
1036  }
1037
1038  /**
1039   * Get the nth element.
1040   *
1041   * @param i The index of the requested node.
1042   *
1043   * @return Node at specified index.
1044   */

1045  public int elementAt(int i)
1046  {
1047
1048    runTo(i);
1049
1050    return super.elementAt(i);
1051  }
1052  
1053  /**
1054   * Tell if the table contains the given node.
1055   *
1056   * @param s Node to look for
1057   *
1058   * @return True if the given node was found.
1059   */

1060  public boolean contains(int s)
1061  {
1062
1063    runTo(-1);
1064
1065    return super.contains(s);
1066  }
1067
1068  /**
1069   * Searches for the first occurence of the given argument,
1070   * beginning the search at index, and testing for equality
1071   * using the equals method.
1072   *
1073   * @param elem Node to look for
1074   * @param index Index of where to start the search
1075   * @return the index of the first occurrence of the object
1076   * argument in this vector at position index or later in the
1077   * vector; returns -1 if the object is not found.
1078   */

1079  public int indexOf(int elem, int index)
1080  {
1081
1082    runTo(-1);
1083
1084    return super.indexOf(elem, index);
1085  }
1086
1087  /**
1088   * Searches for the first occurence of the given argument,
1089   * beginning the search at index, and testing for equality
1090   * using the equals method.
1091   *
1092   * @param elem Node to look for
1093   * @return the index of the first occurrence of the object
1094   * argument in this vector at position index or later in the
1095   * vector; returns -1 if the object is not found.
1096   */

1097  public int indexOf(int elem)
1098  {
1099
1100    runTo(-1);
1101
1102    return super.indexOf(elem);
1103  }
1104
1105  /** If this node is being used as an iterator, the next index that nextNode()
1106   * will return. */

1107  transient protected int m_next = 0;
1108
1109  /**
1110   * Get the current position, which is one less than
1111   * the next nextNode() call will retrieve. i.e. if
1112   * you call getCurrentPos() and the return is 0, the next
1113   * fetch will take place at index 1.
1114   *
1115   * @return The the current position index.
1116   */

1117  public int getCurrentPos()
1118  {
1119    return m_next;
1120  }
1121
1122  /**
1123   * Set the current position in the node set.
1124   * @param i Must be a valid index.
1125   * @throws RuntimeException thrown if this NodeSetDTM is not of
1126   * a cached type, and thus doesn't permit indexed access.
1127   */

1128  public void setCurrentPos(int i)
1129  {
1130
1131    if (!m_cacheNodes)
1132      throw new RuntimeException JavaDoc(
1133        XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_INDEX, null)); //"This NodeSetDTM can not do indexing or counting functions!");
1134

1135    m_next = i;
1136  }
1137
1138  /**
1139   * Return the last fetched node. Needed to support the UnionPathIterator.
1140   *
1141   * @return the last fetched node.
1142   * @throws RuntimeException thrown if this NodeSetDTM is not of
1143   * a cached type, and thus doesn't permit indexed access.
1144   */

1145  public int getCurrentNode()
1146  {
1147
1148    if (!m_cacheNodes)
1149      throw new RuntimeException JavaDoc(
1150        "This NodeSetDTM can not do indexing or counting functions!");
1151
1152    int saved = m_next;
1153    // because nextNode always increments
1154
// But watch out for copy29, where the root iterator didn't
1155
// have nextNode called on it.
1156
int current = (m_next > 0) ? m_next-1 : m_next;
1157    int n = (current < m_firstFree) ? elementAt(current) : DTM.NULL;
1158    m_next = saved; // HACK: I think this is a bit of a hack. -sb
1159
return n;
1160  }
1161
1162  /** True if this list can be mutated. */
1163  transient protected boolean m_mutable = true;
1164
1165  /** True if this list is cached.
1166   * @serial */

1167  transient protected boolean m_cacheNodes = true;
1168  
1169  /** The root of the iteration, if available. */
1170  protected int m_root = DTM.NULL;
1171
1172  /**
1173   * Get whether or not this is a cached node set.
1174   *
1175   *
1176   * @return True if this list is cached.
1177   */

1178  public boolean getShouldCacheNodes()
1179  {
1180    return m_cacheNodes;
1181  }
1182
1183  /**
1184   * If setShouldCacheNodes(true) is called, then nodes will
1185   * be cached. They are not cached by default. This switch must
1186   * be set before the first call to nextNode is made, to ensure
1187   * that all nodes are cached.
1188   *
1189   * @param b true if this node set should be cached.
1190   * @throws RuntimeException thrown if an attempt is made to
1191   * request caching after we've already begun stepping through the
1192   * nodes in this set.
1193  */

1194  public void setShouldCacheNodes(boolean b)
1195  {
1196
1197    if (!isFresh())
1198      throw new RuntimeException JavaDoc(
1199        XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CANNOT_CALL_SETSHOULDCACHENODE, null)); //"Can not call setShouldCacheNodes after nextNode has been called!");
1200

1201    m_cacheNodes = b;
1202    m_mutable = true;
1203  }
1204  
1205  /**
1206   * Tells if this iterator can have nodes added to it or set via
1207   * the <code>setItem(int node, int index)</code> method.
1208   *
1209   * @return True if the nodelist can be mutated.
1210   */

1211  public boolean isMutable()
1212  {
1213    return m_mutable;
1214  }
1215  
1216  transient private int m_last = 0;
1217  
1218  public int getLast()
1219  {
1220    return m_last;
1221  }
1222  
1223  public void setLast(int last)
1224  {
1225    m_last = last;
1226  }
1227  
1228  /**
1229   * Returns true if all the nodes in the iteration well be returned in document
1230   * order.
1231   *
1232   * @return true as a default.
1233   */

1234  public boolean isDocOrdered()
1235  {
1236    return true;
1237  }
1238  
1239  /**
1240   * Returns the axis being iterated, if it is known.
1241   *
1242   * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
1243   * types.
1244   */

1245  public int getAxis()
1246  {
1247    return -1;
1248  }
1249  
1250
1251}
1252
Popular Tags