KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xpath > internal > axes > UnionPathIterator


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: UnionPathIterator.java,v 1.33 2004/02/17 04:32:08 minchau Exp $
18  */

19 package com.sun.org.apache.xpath.internal.axes;
20
21 import com.sun.org.apache.xml.internal.dtm.Axis;
22 import com.sun.org.apache.xml.internal.dtm.DTM;
23 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
24 import com.sun.org.apache.xpath.internal.Expression;
25 import com.sun.org.apache.xpath.internal.ExpressionOwner;
26 import com.sun.org.apache.xpath.internal.XPathVisitor;
27 import com.sun.org.apache.xpath.internal.compiler.Compiler;
28 import com.sun.org.apache.xpath.internal.compiler.OpCodes;
29
30 /**
31  * This class extends NodeSetDTM, which implements DTMIterator,
32  * and fetches nodes one at a time in document order based on a XPath
33  * <a HREF="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
34  * As each node is iterated via nextNode(), the node is also stored
35  * in the NodeVector, so that previousNode() can easily be done.
36  * @xsl.usage advanced
37  */

38 public class UnionPathIterator extends LocPathIterator
39         implements Cloneable JavaDoc, DTMIterator, java.io.Serializable JavaDoc, PathComponent
40 {
41
42   /**
43    * Constructor to create an instance which you can add location paths to.
44    */

45   public UnionPathIterator()
46   {
47
48     super();
49
50     // m_mutable = false;
51
// m_cacheNodes = false;
52
m_iterators = null;
53     m_exprs = null;
54   }
55
56   /**
57    * Initialize the context values for this expression
58    * after it is cloned.
59    *
60    * @param execContext The XPath runtime context for this
61    * transformation.
62    */

63   public void setRoot(int context, Object JavaDoc environment)
64   {
65     super.setRoot(context, environment);
66
67     try
68     {
69       if (null != m_exprs)
70       {
71         int n = m_exprs.length;
72         DTMIterator newIters[] = new DTMIterator[n];
73   
74         for (int i = 0; i < n; i++)
75         {
76           DTMIterator iter = m_exprs[i].asIterator(m_execContext, context);
77           newIters[i] = iter;
78           iter.nextNode();
79         }
80         m_iterators = newIters;
81       }
82     }
83     catch(Exception JavaDoc e)
84     {
85       throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
86     }
87   }
88   
89   /**
90    * Add an iterator to the union list.
91    *
92    * @param iter non-null reference to a location path iterator.
93    */

94   public void addIterator(DTMIterator expr)
95   {
96
97     // Increase array size by only 1 at a time. Fix this
98
// if it looks to be a problem.
99
if (null == m_iterators)
100     {
101       m_iterators = new DTMIterator[1];
102       m_iterators[0] = expr;
103     }
104     else
105     {
106       DTMIterator[] exprs = m_iterators;
107       int len = m_iterators.length;
108
109       m_iterators = new DTMIterator[len + 1];
110
111       System.arraycopy(exprs, 0, m_iterators, 0, len);
112
113       m_iterators[len] = expr;
114     }
115     expr.nextNode();
116     if(expr instanceof Expression)
117         ((Expression)expr).exprSetParent(this);
118   }
119   
120   /**
121    * Detaches the iterator from the set which it iterated over, releasing
122    * any computational resources and placing the iterator in the INVALID
123    * state. After<code>detach</code> has been invoked, calls to
124    * <code>nextNode</code> or<code>previousNode</code> will raise the
125    * exception INVALID_STATE_ERR.
126    */

127   public void detach()
128   {
129           if(m_allowDetach && null != m_iterators){
130                   int n = m_iterators.length;
131                   for(int i = 0; i < n; i++)
132                   {
133                           m_iterators[i].detach();
134                   }
135                   m_iterators = null;
136           }
137   }
138
139
140   /**
141    * Create a UnionPathIterator object, including creation
142    * of location path iterators from the opcode list, and call back
143    * into the Compiler to create predicate expressions.
144    *
145    * @param compiler The Compiler which is creating
146    * this expression.
147    * @param opPos The position of this iterator in the
148    * opcode list from the compiler.
149    *
150    * @throws javax.xml.transform.TransformerException
151    */

152   public UnionPathIterator(Compiler JavaDoc compiler, int opPos)
153           throws javax.xml.transform.TransformerException JavaDoc
154   {
155
156     super();
157
158     opPos = compiler.getFirstChildPos(opPos);
159
160     loadLocationPaths(compiler, opPos, 0);
161   }
162   
163   /**
164    * This will return an iterator capable of handling the union of paths given.
165    *
166    * @param compiler The Compiler which is creating
167    * this expression.
168    * @param opPos The position of this iterator in the
169    * opcode list from the compiler.
170    *
171    * @return Object that is derived from LocPathIterator.
172    *
173    * @throws javax.xml.transform.TransformerException
174    */

175   public static LocPathIterator createUnionIterator(Compiler JavaDoc compiler, int opPos)
176           throws javax.xml.transform.TransformerException JavaDoc
177   {
178     // For the moment, I'm going to first create a full UnionPathIterator, and
179
// then see if I can reduce it to a UnionChildIterator. It would obviously
180
// be more effecient to just test for the conditions for a UnionChildIterator,
181
// and then create that directly.
182
UnionPathIterator upi = new UnionPathIterator(compiler, opPos);
183     int nPaths = upi.m_exprs.length;
184     boolean isAllChildIterators = true;
185     for(int i = 0; i < nPaths; i++)
186     {
187         LocPathIterator lpi = upi.m_exprs[i];
188         
189         if(lpi.getAxis() != Axis.CHILD)
190         {
191             isAllChildIterators = false;
192             break;
193         }
194         else
195         {
196             // check for positional predicates or position function, which won't work.
197
if(HasPositionalPredChecker.check(lpi))
198             {
199                 isAllChildIterators = false;
200                 break;
201             }
202         }
203     }
204     if(isAllChildIterators)
205     {
206         UnionChildIterator uci = new UnionChildIterator();
207         
208         for(int i = 0; i < nPaths; i++)
209         {
210             PredicatedNodeTest lpi = upi.m_exprs[i];
211             // I could strip the lpi down to a pure PredicatedNodeTest, but
212
// I don't think it's worth it. Note that the test can be used
213
// as a static object... so it doesn't have to be cloned.
214
uci.addNodeTest(lpi);
215         }
216         return uci;
217         
218     }
219     else
220         return upi;
221   }
222   
223   /**
224    * Get the analysis bits for this walker, as defined in the WalkerFactory.
225    * @return One of WalkerFactory#BIT_DESCENDANT, etc.
226    */

227   public int getAnalysisBits()
228   {
229     int bits = 0;
230     
231     if (m_exprs != null)
232     {
233       int n = m_exprs.length;
234
235       for (int i = 0; i < n; i++)
236       {
237         int bit = m_exprs[i].getAnalysisBits();
238         bits |= bit;
239       }
240     }
241
242     return bits;
243   }
244   
245   /**
246    * Read the object from a serialization stream.
247    *
248    * @param stream Input stream to read from
249    *
250    * @throws java.io.IOException
251    * @throws javax.xml.transform.TransformerException
252    */

253   private void readObject(java.io.ObjectInputStream JavaDoc stream)
254           throws java.io.IOException JavaDoc, javax.xml.transform.TransformerException JavaDoc
255   {
256     try
257     {
258       stream.defaultReadObject();
259       m_clones = new IteratorPool(this);
260     }
261     catch (ClassNotFoundException JavaDoc cnfe)
262     {
263       throw new javax.xml.transform.TransformerException JavaDoc(cnfe);
264     }
265   }
266
267   /**
268    * Get a cloned LocPathIterator that holds the same
269    * position as this iterator.
270    *
271    * @return A clone of this iterator that holds the same node position.
272    *
273    * @throws CloneNotSupportedException
274    */

275   public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc
276   {
277
278     UnionPathIterator clone = (UnionPathIterator) super.clone();
279 // if (m_iterators != null)
280
// {
281
// int n = m_iterators.length;
282
//
283
// clone.m_iterators = new LocPathIterator[n];
284
//
285
// for (int i = 0; i < n; i++)
286
// {
287
// clone.m_iterators[i] = (LocPathIterator)m_iterators[i].clone();
288
// }
289
// }
290

291     return clone;
292   }
293   
294   
295   /**
296    * Create a new location path iterator.
297    *
298    * @param compiler The Compiler which is creating
299    * this expression.
300    * @param opPos The position of this iterator in the
301    *
302    * @return New location path iterator.
303    *
304    * @throws javax.xml.transform.TransformerException
305    */

306   protected LocPathIterator createDTMIterator(
307           Compiler JavaDoc compiler, int opPos) throws javax.xml.transform.TransformerException JavaDoc
308   {
309     LocPathIterator lpi = (LocPathIterator)WalkerFactory.newDTMIterator(compiler, opPos,
310                                       (compiler.getLocationPathDepth() <= 0));
311     return lpi;
312   }
313
314   /**
315    * Initialize the location path iterators. Recursive.
316    *
317    * @param compiler The Compiler which is creating
318    * this expression.
319    * @param opPos The position of this iterator in the
320    * opcode list from the compiler.
321    * @param count The insert position of the iterator.
322    *
323    * @throws javax.xml.transform.TransformerException
324    */

325   protected void loadLocationPaths(Compiler JavaDoc compiler, int opPos, int count)
326           throws javax.xml.transform.TransformerException JavaDoc
327   {
328
329     // TODO: Handle unwrapped FilterExpr
330
int steptype = compiler.getOp(opPos);
331
332     if (steptype == OpCodes.OP_LOCATIONPATH)
333     {
334       loadLocationPaths(compiler, compiler.getNextOpPos(opPos), count + 1);
335
336       m_exprs[count] = createDTMIterator(compiler, opPos);
337       m_exprs[count].exprSetParent(this);
338     }
339     else
340     {
341
342       // Have to check for unwrapped functions, which the LocPathIterator
343
// doesn't handle.
344
switch (steptype)
345       {
346       case OpCodes.OP_VARIABLE :
347       case OpCodes.OP_EXTFUNCTION :
348       case OpCodes.OP_FUNCTION :
349       case OpCodes.OP_GROUP :
350         loadLocationPaths(compiler, compiler.getNextOpPos(opPos), count + 1);
351
352         WalkingIterator iter =
353           new WalkingIterator(compiler.getNamespaceContext());
354         iter.exprSetParent(this);
355           
356         if(compiler.getLocationPathDepth() <= 0)
357           iter.setIsTopLevel(true);
358
359         iter.m_firstWalker = new com.sun.org.apache.xpath.internal.axes.FilterExprWalker(iter);
360
361         iter.m_firstWalker.init(compiler, opPos, steptype);
362
363         m_exprs[count] = iter;
364         break;
365       default :
366         m_exprs = new LocPathIterator[count];
367       }
368     }
369   }
370
371   /**
372    * Returns the next node in the set and advances the position of the
373    * iterator in the set. After a DTMIterator is created, the first call
374    * to nextNode() returns the first node in the set.
375    * @return The next <code>Node</code> in the set being iterated over, or
376    * <code>null</code> if there are no more members in that set.
377    */

378   public int nextNode()
379   {
380     if(m_foundLast)
381         return DTM.NULL;
382
383     // Loop through the iterators getting the current fetched
384
// node, and get the earliest occuring in document order
385
int earliestNode = DTM.NULL;
386
387     if (null != m_iterators)
388     {
389       int n = m_iterators.length;
390       int iteratorUsed = -1;
391
392       for (int i = 0; i < n; i++)
393       {
394         int node = m_iterators[i].getCurrentNode();
395
396         if (DTM.NULL == node)
397           continue;
398         else if (DTM.NULL == earliestNode)
399         {
400           iteratorUsed = i;
401           earliestNode = node;
402         }
403         else
404         {
405           if (node == earliestNode)
406           {
407
408             // Found a duplicate, so skip past it.
409
m_iterators[i].nextNode();
410           }
411           else
412           {
413             DTM dtm = getDTM(node);
414
415             if (dtm.isNodeAfter(node, earliestNode))
416             {
417               iteratorUsed = i;
418               earliestNode = node;
419             }
420           }
421         }
422       }
423
424       if (DTM.NULL != earliestNode)
425       {
426         m_iterators[iteratorUsed].nextNode();
427
428         incrementCurrentPos();
429       }
430       else
431         m_foundLast = true;
432     }
433
434     m_lastFetched = earliestNode;
435
436     return earliestNode;
437   }
438             
439   /**
440    * This function is used to fixup variables from QNames to stack frame
441    * indexes at stylesheet build time.
442    * @param vars List of QNames that correspond to variables. This list
443    * should be searched backwards for the first qualified name that
444    * corresponds to the variable reference qname. The position of the
445    * QName in the vector from the start of the vector will be its position
446    * in the stack frame (but variables above the globalsTop value will need
447    * to be offset to the current stack frame).
448    */

449   public void fixupVariables(java.util.Vector JavaDoc vars, int globalsSize)
450   {
451     for (int i = 0; i < m_exprs.length; i++)
452     {
453       m_exprs[i].fixupVariables(vars, globalsSize);
454     }
455     
456   }
457   
458   /**
459    * The location path iterators, one for each
460    * <a HREF="http://www.w3.org/TR/xpath#NT-LocationPath">location
461    * path</a> contained in the union expression.
462    * @serial
463    */

464   protected LocPathIterator[] m_exprs;
465
466     
467   /**
468    * The location path iterators, one for each
469    * <a HREF="http://www.w3.org/TR/xpath#NT-LocationPath">location
470    * path</a> contained in the union expression.
471    * @serial
472    */

473   protected DTMIterator[] m_iterators;
474       
475   /**
476    * Returns the axis being iterated, if it is known.
477    *
478    * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
479    * types.
480    */

481   public int getAxis()
482   {
483     // Could be smarter.
484
return -1;
485   }
486   
487   class iterOwner implements ExpressionOwner
488   {
489     int m_index;
490     
491     iterOwner(int index)
492     {
493         m_index = index;
494     }
495     
496     /**
497      * @see ExpressionOwner#getExpression()
498      */

499     public Expression getExpression()
500     {
501       return m_exprs[m_index];
502     }
503
504     /**
505      * @see ExpressionOwner#setExpression(Expression)
506      */

507     public void setExpression(Expression exp)
508     {
509         
510         if(!(exp instanceof LocPathIterator))
511         {
512             // Yuck. Need FilterExprIter. Or make it so m_exprs can be just
513
// plain expressions?
514
WalkingIterator wi = new WalkingIterator(getPrefixResolver());
515             FilterExprWalker few = new FilterExprWalker(wi);
516             wi.setFirstWalker(few);
517             few.setInnerExpression(exp);
518             wi.exprSetParent(UnionPathIterator.this);
519             few.exprSetParent(wi);
520             exp.exprSetParent(few);
521             exp = wi;
522         }
523         else
524             exp.exprSetParent(UnionPathIterator.this);
525         m_exprs[m_index] = (LocPathIterator)exp;
526     }
527
528   }
529
530   /**
531    * @see com.sun.org.apache.xpath.internal.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
532    */

533   public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
534   {
535         if(visitor.visitUnionPath(owner, this))
536         {
537             if(null != m_exprs)
538             {
539                 int n = m_exprs.length;
540                 for(int i = 0; i < n; i++)
541                 {
542                     m_exprs[i].callVisitors(new iterOwner(i), visitor);
543                 }
544             }
545         }
546   }
547   
548     /**
549      * @see Expression#deepEquals(Expression)
550      */

551     public boolean deepEquals(Expression expr)
552     {
553       if (!super.deepEquals(expr))
554             return false;
555
556       UnionPathIterator upi = (UnionPathIterator) expr;
557
558       if (null != m_exprs)
559       {
560         int n = m_exprs.length;
561         
562         if((null == upi.m_exprs) || (upi.m_exprs.length != n))
563             return false;
564         
565         for (int i = 0; i < n; i++)
566         {
567           if(!m_exprs[i].deepEquals(upi.m_exprs[i]))
568             return false;
569         }
570       }
571       else if (null != upi.m_exprs)
572       {
573           return false;
574       }
575
576       return true;
577     }
578
579
580 }
581
Popular Tags