KickJava   Java API By Example, From Geeks To Geeks.

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


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

19 package org.apache.xpath.axes;
20
21 import org.apache.xml.dtm.DTM;
22 import org.apache.xml.dtm.DTMIterator;
23 import org.apache.xml.utils.PrefixResolver;
24 import org.apache.xpath.Expression;
25 import org.apache.xpath.ExpressionOwner;
26 import org.apache.xpath.XPathContext;
27 import org.apache.xpath.XPathVisitor;
28 import org.apache.xpath.compiler.Compiler;
29 import org.apache.xpath.objects.XObject;
30 import org.apache.xpath.patterns.NodeTest;
31
32 public abstract class PredicatedNodeTest extends NodeTest implements SubContextList
33 {
34
35   /**
36    * Construct an AxesWalker using a LocPathIterator.
37    *
38    * @param locPathIterator non-null reference to the parent iterator.
39    */

40   PredicatedNodeTest(LocPathIterator locPathIterator)
41   {
42     m_lpi = locPathIterator;
43   }
44   
45   /**
46    * Construct an AxesWalker. The location path iterator will have to be set
47    * before use.
48    */

49   PredicatedNodeTest()
50   {
51   }
52   
53   /**
54    * Read the object from a serialization stream.
55    *
56    * @param stream Input stream to read from
57    *
58    * @throws java.io.IOException
59    * @throws javax.xml.transform.TransformerException
60    */

61   private void readObject(java.io.ObjectInputStream JavaDoc stream)
62           throws java.io.IOException JavaDoc, javax.xml.transform.TransformerException JavaDoc
63   {
64     try
65     {
66       stream.defaultReadObject();
67       m_predicateIndex = -1;
68       resetProximityPositions();
69     }
70     catch (ClassNotFoundException JavaDoc cnfe)
71     {
72       throw new javax.xml.transform.TransformerException JavaDoc(cnfe);
73     }
74   }
75   
76   /**
77    * Get a cloned PrdicatedNodeTest.
78    *
79    * @return A new PredicatedNodeTest that can be used without mutating this one.
80    *
81    * @throws CloneNotSupportedException
82    */

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

87     PredicatedNodeTest clone = (PredicatedNodeTest) super.clone();
88
89     if ((null != this.m_proximityPositions)
90             && (this.m_proximityPositions == clone.m_proximityPositions))
91     {
92       clone.m_proximityPositions = new int[this.m_proximityPositions.length];
93
94       System.arraycopy(this.m_proximityPositions, 0,
95                        clone.m_proximityPositions, 0,
96                        this.m_proximityPositions.length);
97     }
98     
99     if(clone.m_lpi == this)
100       clone.m_lpi = (LocPathIterator)clone;
101
102     return clone;
103   }
104   
105   // Only for clones for findLastPos. See bug4638.
106
protected int m_predCount = -1;
107
108   /**
109    * Get the number of predicates that this walker has.
110    *
111    * @return the number of predicates that this walker has.
112    */

113   public int getPredicateCount()
114   {
115     if(-1 == m_predCount)
116       return (null == m_predicates) ? 0 : m_predicates.length;
117     else
118       return m_predCount;
119   }
120
121   /**
122    * Set the number of predicates that this walker has. This does more
123    * that one would think, as it creates a new predicate array of the
124    * size of the count argument, and copies count predicates into the new
125    * one from the old, and then reassigns the predicates value. All this
126    * to keep from having to have a predicate count value.
127    *
128    * @param count The number of predicates, which must be equal or less
129    * than the existing count.
130    */

131   public void setPredicateCount(int count)
132   {
133     if(count > 0)
134     {
135       Expression[] newPredicates = new Expression[count];
136       for (int i = 0; i < count; i++)
137       {
138         newPredicates[i] = m_predicates[i];
139       }
140       m_predicates = newPredicates;
141     }
142     else
143       m_predicates = null;
144     
145   }
146
147   /**
148    * Init predicate info.
149    *
150    * @param compiler The Compiler object that has information about this
151    * walker in the op map.
152    * @param opPos The op code position of this location step.
153    *
154    * @throws javax.xml.transform.TransformerException
155    */

156   protected void initPredicateInfo(Compiler JavaDoc compiler, int opPos)
157           throws javax.xml.transform.TransformerException JavaDoc
158   {
159
160     int pos = compiler.getFirstPredicateOpPos(opPos);
161
162     if(pos > 0)
163     {
164       m_predicates = compiler.getCompiledPredicates(pos);
165       if(null != m_predicates)
166       {
167         for(int i = 0; i < m_predicates.length; i++)
168         {
169             m_predicates[i].exprSetParent(this);
170         }
171       }
172     }
173   }
174
175   /**
176    * Get a predicate expression at the given index.
177    *
178    *
179    * @param index Index of the predicate.
180    *
181    * @return A predicate expression.
182    */

183   public Expression getPredicate(int index)
184   {
185     return m_predicates[index];
186   }
187   
188   /**
189    * Get the current sub-context position.
190    *
191    * @return The node position of this walker in the sub-context node list.
192    */

193   public int getProximityPosition()
194   {
195
196     // System.out.println("getProximityPosition - m_predicateIndex: "+m_predicateIndex);
197
return getProximityPosition(m_predicateIndex);
198   }
199
200   /**
201    * Get the current sub-context position.
202    *
203    * @param xctxt The XPath runtime context.
204    *
205    * @return The node position of this walker in the sub-context node list.
206    */

207   public int getProximityPosition(XPathContext xctxt)
208   {
209     return getProximityPosition();
210   }
211   
212   /**
213    * Get the index of the last node that can be itterated to.
214    *
215    *
216    * @param xctxt XPath runtime context.
217    *
218    * @return the index of the last node that can be itterated to.
219    */

220   public abstract int getLastPos(XPathContext xctxt);
221
222   /**
223    * Get the current sub-context position.
224    *
225    * @param predicateIndex The index of the predicate where the proximity
226    * should be taken from.
227    *
228    * @return The node position of this walker in the sub-context node list.
229    */

230   protected int getProximityPosition(int predicateIndex)
231   {
232     return (predicateIndex >= 0) ? m_proximityPositions[predicateIndex] : 0;
233   }
234
235   /**
236    * Reset the proximity positions counts.
237    */

238   public void resetProximityPositions()
239   {
240     int nPredicates = getPredicateCount();
241     if (nPredicates > 0)
242     {
243       if (null == m_proximityPositions)
244         m_proximityPositions = new int[nPredicates];
245
246       for (int i = 0; i < nPredicates; i++)
247       {
248         try
249         {
250           initProximityPosition(i);
251         }
252         catch(Exception JavaDoc e)
253         {
254           // TODO: Fix this...
255
throw new org.apache.xml.utils.WrappedRuntimeException(e);
256         }
257       }
258     }
259   }
260
261   /**
262    * Init the proximity position to zero for a forward axes.
263    *
264    * @param i The index into the m_proximityPositions array.
265    *
266    * @throws javax.xml.transform.TransformerException
267    */

268   public void initProximityPosition(int i) throws javax.xml.transform.TransformerException JavaDoc
269   {
270     m_proximityPositions[i] = 0;
271   }
272
273   /**
274    * Count forward one proximity position.
275    *
276    * @param i The index into the m_proximityPositions array, where the increment
277    * will occur.
278    */

279   protected void countProximityPosition(int i)
280   {
281     // Note that in the case of a UnionChildIterator, this may be a
282
// static object and so m_proximityPositions may indeed be null!
283
int[] pp = m_proximityPositions;
284     if ((null != pp) && (i < pp.length))
285       pp[i]++;
286   }
287
288   /**
289    * Tells if this is a reverse axes.
290    *
291    * @return false, unless a derived class overrides.
292    */

293   public boolean isReverseAxes()
294   {
295     return false;
296   }
297
298   /**
299    * Get which predicate is executing.
300    *
301    * @return The current predicate index, or -1 if no predicate is executing.
302    */

303   public int getPredicateIndex()
304   {
305     return m_predicateIndex;
306   }
307
308   /**
309    * Process the predicates.
310    *
311    * @param context The current context node.
312    * @param xctxt The XPath runtime context.
313    *
314    * @return the result of executing the predicate expressions.
315    *
316    * @throws javax.xml.transform.TransformerException
317    */

318   boolean executePredicates(int context, XPathContext xctxt)
319           throws javax.xml.transform.TransformerException JavaDoc
320   {
321     
322     int nPredicates = getPredicateCount();
323     // System.out.println("nPredicates: "+nPredicates);
324
if (nPredicates == 0)
325       return true;
326
327     PrefixResolver savedResolver = xctxt.getNamespaceContext();
328
329     try
330     {
331       m_predicateIndex = 0;
332       xctxt.pushSubContextList(this);
333       xctxt.pushNamespaceContext(m_lpi.getPrefixResolver());
334       xctxt.pushCurrentNode(context);
335
336       for (int i = 0; i < nPredicates; i++)
337       {
338         // System.out.println("Executing predicate expression - waiting count: "+m_lpi.getWaitingCount());
339
XObject pred = m_predicates[i].execute(xctxt);
340         // System.out.println("\nBack from executing predicate expression - waiting count: "+m_lpi.getWaitingCount());
341
// System.out.println("pred.getType(): "+pred.getType());
342
if (XObject.CLASS_NUMBER == pred.getType())
343         {
344           if (DEBUG_PREDICATECOUNTING)
345           {
346             System.out.flush();
347             System.out.println("\n===== start predicate count ========");
348             System.out.println("m_predicateIndex: " + m_predicateIndex);
349             // System.out.println("getProximityPosition(m_predicateIndex): "
350
// + getProximityPosition(m_predicateIndex));
351
System.out.println("pred.num(): " + pred.num());
352           }
353
354           int proxPos = this.getProximityPosition(m_predicateIndex);
355           int predIndex = (int) pred.num();
356           if (proxPos != predIndex)
357           {
358             if (DEBUG_PREDICATECOUNTING)
359             {
360               System.out.println("\nnode context: "+nodeToString(context));
361               System.out.println("index predicate is false: "+proxPos);
362               System.out.println("\n===== end predicate count ========");
363             }
364             return false;
365           }
366           else if (DEBUG_PREDICATECOUNTING)
367           {
368             System.out.println("\nnode context: "+nodeToString(context));
369             System.out.println("index predicate is true: "+proxPos);
370             System.out.println("\n===== end predicate count ========");
371           }
372           
373           // If there is a proximity index that will not change during the
374
// course of itteration, then we know there can be no more true
375
// occurances of this predicate, so flag that we're done after
376
// this.
377
//
378
// bugzilla 14365
379
// We can't set m_foundLast = true unless we're sure that -all-
380
// remaining parameters are stable, or else last() fails. Fixed so
381
// only sets m_foundLast if on the last predicate
382
if(m_predicates[i].isStableNumber() && i == nPredicates - 1)
383           {
384             m_foundLast = true;
385           }
386         }
387         else if (!pred.bool())
388           return false;
389
390         countProximityPosition(++m_predicateIndex);
391       }
392     }
393     finally
394     {
395       xctxt.popCurrentNode();
396       xctxt.popNamespaceContext();
397       xctxt.popSubContextList();
398       m_predicateIndex = -1;
399     }
400
401     return true;
402   }
403   
404   /**
405    * This function is used to fixup variables from QNames to stack frame
406    * indexes at stylesheet build time.
407    * @param vars List of QNames that correspond to variables. This list
408    * should be searched backwards for the first qualified name that
409    * corresponds to the variable reference qname. The position of the
410    * QName in the vector from the start of the vector will be its position
411    * in the stack frame (but variables above the globalsTop value will need
412    * to be offset to the current stack frame).
413    */

414   public void fixupVariables(java.util.Vector JavaDoc vars, int globalsSize)
415   {
416     super.fixupVariables(vars, globalsSize);
417
418     int nPredicates = getPredicateCount();
419
420     for (int i = 0; i < nPredicates; i++)
421     {
422       m_predicates[i].fixupVariables(vars, globalsSize);
423     }
424   }
425
426   
427   /**
428    * Diagnostics.
429    *
430    * @param n Node to give diagnostic information about, or null.
431    *
432    * @return Informative string about the argument.
433    */

434   protected String JavaDoc nodeToString(int n)
435   {
436     if(DTM.NULL != n)
437     {
438       DTM dtm = m_lpi.getXPathContext().getDTM(n);
439       return dtm.getNodeName(n) + "{" + (n+1) + "}";
440     }
441     else
442     {
443       return "null";
444     }
445   }
446   
447   //=============== NodeFilter Implementation ===============
448

449   /**
450    * Test whether a specified node is visible in the logical view of a
451    * TreeWalker or NodeIterator. This function will be called by the
452    * implementation of TreeWalker and NodeIterator; it is not intended to
453    * be called directly from user code.
454    * @param n The node to check to see if it passes the filter or not.
455    * @return a constant to determine whether the node is accepted,
456    * rejected, or skipped, as defined above .
457    */

458   public short acceptNode(int n)
459   {
460
461     XPathContext xctxt = m_lpi.getXPathContext();
462
463     try
464     {
465       xctxt.pushCurrentNode(n);
466
467       XObject score = execute(xctxt, n);
468
469       // System.out.println("\n::acceptNode - score: "+score.num()+"::");
470
if (score != NodeTest.SCORE_NONE)
471       {
472         if (getPredicateCount() > 0)
473         {
474           countProximityPosition(0);
475
476           if (!executePredicates(n, xctxt))
477             return DTMIterator.FILTER_SKIP;
478         }
479
480         return DTMIterator.FILTER_ACCEPT;
481       }
482     }
483     catch (javax.xml.transform.TransformerException JavaDoc se)
484     {
485
486       // TODO: Fix this.
487
throw new RuntimeException JavaDoc(se.getMessage());
488     }
489     finally
490     {
491       xctxt.popCurrentNode();
492     }
493
494     return DTMIterator.FILTER_SKIP;
495   }
496
497   
498   /**
499    * Get the owning location path iterator.
500    *
501    * @return the owning location path iterator, which should not be null.
502    */

503   public LocPathIterator getLocPathIterator()
504   {
505     return m_lpi;
506   }
507
508   /**
509    * Set the location path iterator owner for this walker. Besides
510    * initialization, this function is called during cloning operations.
511    *
512    * @param li non-null reference to the owning location path iterator.
513    */

514   public void setLocPathIterator(LocPathIterator li)
515   {
516     m_lpi = li;
517     if(this != li)
518       li.exprSetParent(this);
519   }
520   
521   /**
522    * Tell if this expression or it's subexpressions can traverse outside
523    * the current subtree.
524    *
525    * @return true if traversal outside the context node's subtree can occur.
526    */

527    public boolean canTraverseOutsideSubtree()
528    {
529     int n = getPredicateCount();
530     for (int i = 0; i < n; i++)
531     {
532       if(getPredicate(i).canTraverseOutsideSubtree())
533         return true;
534     }
535     return false;
536    }
537    
538     /**
539      * This will traverse the heararchy, calling the visitor for
540      * each member. If the called visitor method returns
541      * false, the subtree should not be called.
542      *
543      * @param owner The owner of the visitor, where that path may be
544      * rewritten if needed.
545      * @param visitor The visitor whose appropriate method will be called.
546      */

547     public void callPredicateVisitors(XPathVisitor visitor)
548     {
549       if (null != m_predicates)
550         {
551         int n = m_predicates.length;
552         for (int i = 0; i < n; i++)
553           {
554           ExpressionOwner predOwner = new PredOwner(i);
555           if (visitor.visitPredicate(predOwner, m_predicates[i]))
556             {
557             m_predicates[i].callVisitors(predOwner, visitor);
558           }
559     
560         }
561       }
562     }
563     
564     /**
565      * @see Expression#deepEquals(Expression)
566      */

567     public boolean deepEquals(Expression expr)
568     {
569       if (!super.deepEquals(expr))
570             return false;
571
572       PredicatedNodeTest pnt = (PredicatedNodeTest) expr;
573       if (null != m_predicates)
574       {
575
576         int n = m_predicates.length;
577         if ((null == pnt.m_predicates) || (pnt.m_predicates.length != n))
578               return false;
579         for (int i = 0; i < n; i++)
580         {
581           if (!m_predicates[i].deepEquals(pnt.m_predicates[i]))
582             return false;
583         }
584       }
585       else if (null != pnt.m_predicates)
586               return false;
587               
588       return true;
589     }
590     
591   /** This is true if nextNode returns null. */
592   transient protected boolean m_foundLast = false;
593     
594   /** The owning location path iterator.
595    * @serial */

596   protected LocPathIterator m_lpi;
597   
598   /**
599    * Which predicate we are executing.
600    */

601   transient int m_predicateIndex = -1;
602   
603   /** The list of predicate expressions. Is static and does not need
604    * to be deep cloned.
605    * @serial
606    */

607   private Expression[] m_predicates;
608
609   /**
610    * An array of counts that correspond to the number
611    * of predicates the step contains.
612    */

613   transient protected int[] m_proximityPositions;
614
615   /** If true, diagnostic messages about predicate execution will be posted. */
616   static final boolean DEBUG_PREDICATECOUNTING = false;
617   
618   class PredOwner implements ExpressionOwner
619   {
620     int m_index;
621     
622     PredOwner(int index)
623     {
624         m_index = index;
625     }
626     
627     /**
628      * @see ExpressionOwner#getExpression()
629      */

630     public Expression getExpression()
631     {
632       return m_predicates[m_index];
633     }
634
635
636     /**
637      * @see ExpressionOwner#setExpression(Expression)
638      */

639     public void setExpression(Expression exp)
640     {
641         exp.exprSetParent(PredicatedNodeTest.this);
642         m_predicates[m_index] = exp;
643     }
644   }
645     
646 }
647
Popular Tags