View Javadoc
1   /*
2    * $Header$
3    * $Revision$
4    * $Date$
5    *
6    * ====================================================================
7    *
8    * Copyright 2000-2002 bob mcwhirter & James Strachan.
9    * All rights reserved.
10   *
11   * Redistribution and use in source and binary forms, with or without
12   * modification, are permitted provided that the following conditions are
13   * met:
14   * 
15   *   * Redistributions of source code must retain the above copyright
16   *     notice, this list of conditions and the following disclaimer.
17   * 
18   *   * Redistributions in binary form must reproduce the above copyright
19   *     notice, this list of conditions and the following disclaimer in the
20   *     documentation and/or other materials provided with the distribution.
21   * 
22   *   * Neither the name of the Jaxen Project nor the names of its
23   *     contributors may be used to endorse or promote products derived 
24   *     from this software without specific prior written permission.
25   * 
26   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
27   * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
29   * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
30   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   *
38   * ====================================================================
39   * This software consists of voluntary contributions made by many 
40   * individuals on behalf of the Jaxen Project and was originally 
41   * created by bob mcwhirter <bob@werken.com> and 
42   * James Strachan <jstrachan@apache.org>.  For more information on the 
43   * Jaxen Project, please see <http://www.jaxen.org/>.
44   * 
45   * $Id$
46   */
47  
48  
49  
50  package org.jaxen;
51  
52  import java.util.Iterator;
53  import java.util.LinkedList;
54  
55  import org.jaxen.expr.DefaultXPathFactory;
56  import org.jaxen.expr.Expr;
57  import org.jaxen.expr.FilterExpr;
58  import org.jaxen.expr.FunctionCallExpr;
59  import org.jaxen.expr.LocationPath;
60  import org.jaxen.expr.Predicate;
61  import org.jaxen.expr.Predicated;
62  import org.jaxen.expr.Step;
63  import org.jaxen.expr.XPathExpr;
64  import org.jaxen.expr.XPathFactory;
65  import org.jaxen.saxpath.Operator;
66  import org.jaxen.saxpath.XPathHandler;
67  
68  /** SAXPath <code>XPathHandler</code> implementation capable
69   *  of building Jaxen expression trees which can walk various
70   *  different object models.
71   *
72   *  @author bob mcwhirter (bob@werken.com)
73   */
74  public class JaxenHandler implements XPathHandler
75  {
76      private XPathFactory xpathFactory;
77      private XPathExpr    xpath;
78      
79      /**
80       * ????
81       */
82      protected boolean simplified;
83  
84      /**
85       * This may be changed to an ArrayList in the future (i.e. version &gt;= 1.2). 
86       * You really shouldn't be accessing this field directly, but
87       * if you are please try to use it as a generic List. Don't use the 
88       * methods that are only available in LinkedList.
89       */
90      protected LinkedList stack;
91  
92      /** Constructor
93       */
94      public JaxenHandler()
95      {
96          this.stack        = new LinkedList();
97          this.xpathFactory = new DefaultXPathFactory();
98      }
99      
100     /** Set the Jaxen <code>XPathFactory</code> that constructs
101      *  the XPath expression tree during the parse.
102      *
103      *  @param xpathFactory the factory to use during the parse
104      */
105     public void setXPathFactory(XPathFactory xpathFactory)
106     {
107         this.xpathFactory = xpathFactory;
108     }
109 
110     /** Retrieve the Jaxen <code>XPathFactory</code> used
111      *  during the parse to construct the XPath expression tree.
112      *
113      *  @return the <code>XPathFactory</code> used during the parse.
114      */
115     public XPathFactory getXPathFactory()
116     {
117         return this.xpathFactory;
118     }
119 
120     /** Retrieve the simplified Jaxen XPath expression tree.
121      *
122      *  <p>
123      *  This method is only valid once <code>XPathReader.parse(...)</code>
124      *  successfully returned.
125      *  </p>
126      *
127      *  @return the XPath expression tree
128      */
129     public XPathExpr getXPathExpr()
130     {
131         return getXPathExpr( true );
132     }
133 
134     /** Retrieve the Jaxen XPath expression tree, optionally
135      *  simplified.
136      *
137      *  <p>
138      *  This method is only valid once <code>XPathReader.parse(...)</code>
139      *  successfully returned.
140      *  </p>
141      *  
142      *  @param shouldSimplify ????
143      *
144      *  @return the XPath expression tree
145      */
146     public XPathExpr getXPathExpr(boolean shouldSimplify)
147     {
148         if ( shouldSimplify && ! this.simplified )
149         {
150             this.xpath.simplify();
151             this.simplified = true;
152         }
153 
154         return this.xpath;
155     }
156 
157     public void startXPath()
158     {
159         this.simplified = false;
160         pushFrame();
161     }
162     
163     public void endXPath() throws JaxenException
164     {
165         this.xpath = getXPathFactory().createXPath( (Expr) pop() );
166         popFrame();
167     }
168 
169     public void startPathExpr()
170     {
171         pushFrame();
172     }
173 
174     public void endPathExpr() throws JaxenException
175     {
176 
177         // PathExpr ::=   LocationPath
178         //              | FilterExpr
179         //              | FilterExpr / RelativeLocationPath
180         //              | FilterExpr // RelativeLocationPath
181         //
182         // If the current stack-frame has two items, it's a
183         // FilterExpr and a LocationPath (of some flavor).
184         //
185         // If the current stack-frame has one item, it's simply
186         // a FilterExpr, and more than likely boils down to a
187         // primary expr of some flavor.  But that's for another
188         // method...
189 
190         FilterExpr   filterExpr;
191         LocationPath locationPath;
192 
193         Object       popped;
194 
195         if ( stackSize() == 2 )
196         {
197             locationPath = (LocationPath) pop();
198             filterExpr   = (FilterExpr) pop();
199         }
200         else
201         {
202             popped = pop();
203 
204             if ( popped instanceof LocationPath )
205             {
206                 locationPath = (LocationPath) popped;
207                 filterExpr   = null;
208             }
209             else
210             {
211                 locationPath = null;
212                 filterExpr   = (FilterExpr) popped;
213             }
214         }
215         popFrame();
216 
217         push( getXPathFactory().createPathExpr( filterExpr,
218                                                locationPath ) );
219     }
220 
221     public void startAbsoluteLocationPath() throws JaxenException
222     {
223         pushFrame();
224 
225         push( getXPathFactory().createAbsoluteLocationPath() );
226     }
227 
228     public void endAbsoluteLocationPath() throws JaxenException
229     {
230         endLocationPath();
231     }
232 
233     public void startRelativeLocationPath() throws JaxenException
234     {
235         pushFrame();
236 
237         push( getXPathFactory().createRelativeLocationPath() );
238     }
239 
240     public void endRelativeLocationPath() throws JaxenException
241     {
242         endLocationPath();
243     }
244 
245     protected void endLocationPath() throws JaxenException 
246     {
247         LocationPath path = (LocationPath) peekFrame().removeFirst();
248 
249         addSteps( path,
250                   popFrame().iterator() );
251 
252         push( path );
253     }
254 
255     protected void addSteps(LocationPath locationPath,
256                           Iterator stepIter)
257     {
258         while ( stepIter.hasNext() )
259         {
260             locationPath.addStep( (Step) stepIter.next() );
261         }
262     }
263 
264     public void startNameStep(int axis,
265                               String prefix,
266                               String localName) throws JaxenException
267     {
268         pushFrame();
269 
270         push( getXPathFactory().createNameStep( axis,
271                                                prefix,
272                                                localName ) );
273     }
274 
275     public void endNameStep() 
276     {
277         endStep();
278     }
279     
280     public void startTextNodeStep(int axis) throws JaxenException
281     {
282         //System.err.println("startTextNodeStep()");
283         pushFrame();
284         
285         push( getXPathFactory().createTextNodeStep( axis ) );
286     }
287     
288     public void endTextNodeStep()
289     {
290         endStep();
291     }
292 
293     public void startCommentNodeStep(int axis) throws JaxenException
294     {
295         pushFrame();
296 
297         push( getXPathFactory().createCommentNodeStep( axis ) );
298     }
299 
300     public void endCommentNodeStep()
301     {
302         endStep();
303     }
304         
305     public void startAllNodeStep(int axis) throws JaxenException
306     {
307         pushFrame();
308 
309         push( getXPathFactory().createAllNodeStep( axis ) );
310     }
311 
312     public void endAllNodeStep()
313     {
314         endStep();
315     }
316 
317     public void startProcessingInstructionNodeStep(int axis,
318                                                    String name) throws JaxenException
319     {
320         pushFrame();
321 
322         push( getXPathFactory().createProcessingInstructionNodeStep( axis,
323                                                                     name ) );
324     }
325     
326     public void endProcessingInstructionNodeStep()
327     {
328         endStep();
329     }
330 
331     protected void endStep()
332     {
333         Step step = (Step) peekFrame().removeFirst();
334 
335         addPredicates( step,
336                        popFrame().iterator() );
337 
338         push( step );
339     }
340     
341     public void startPredicate()
342     {
343         pushFrame();
344     }
345     
346     public void endPredicate() throws JaxenException
347     {
348         Predicate predicate = getXPathFactory().createPredicate( (Expr) pop() );
349 
350         popFrame();
351 
352         push( predicate );
353     }
354 
355     public void startFilterExpr() 
356     {
357         pushFrame();
358     }
359 
360     public void endFilterExpr() throws JaxenException
361     {
362         Expr expr = (Expr) peekFrame().removeFirst();
363         
364         FilterExpr filter = getXPathFactory().createFilterExpr( expr );
365 
366         Iterator predIter = popFrame().iterator();
367 
368         addPredicates( filter,
369                        predIter );
370 
371         push( filter );
372     }
373 
374     protected void addPredicates(Predicated obj,
375                                Iterator predIter)
376     {
377         while ( predIter.hasNext() )
378         {
379             obj.addPredicate( (Predicate) predIter.next() );
380         }
381     }
382 
383     protected void returnExpr()
384     {
385         Expr expr = (Expr) pop();
386         popFrame();
387         push( expr );
388     }
389 
390     public void startOrExpr()
391     {
392     }
393 
394     public void endOrExpr(boolean create) throws JaxenException
395     {
396 
397         if ( create )
398         {
399             Expr rhs = (Expr) pop();
400             Expr lhs = (Expr) pop();
401 
402             push( getXPathFactory().createOrExpr( lhs,
403                                                  rhs ) );
404         }
405     }
406 
407     public void startAndExpr()
408     {
409     }
410 
411     public void endAndExpr(boolean create) throws JaxenException
412     {
413 
414         if ( create )
415         {
416 
417             Expr rhs = (Expr) pop();
418             Expr lhs = (Expr) pop();
419 
420             push( getXPathFactory().createAndExpr( lhs,
421                                                   rhs ) );
422         }
423     }
424 
425     public void startEqualityExpr()
426     {
427     }
428 
429     public void endEqualityExpr(int operator) throws JaxenException
430     {
431 
432         if ( operator != Operator.NO_OP )
433         {
434             
435             Expr rhs = (Expr) pop();
436             Expr lhs = (Expr) pop();
437             
438             push( getXPathFactory().createEqualityExpr( lhs,
439                                                         rhs,
440                                                         operator ) );
441         }
442     }
443 
444     public void startRelationalExpr()
445     {
446     }
447 
448     public void endRelationalExpr(int operator) throws JaxenException
449     {
450 
451         if ( operator != Operator.NO_OP )
452         {
453 
454             Expr rhs = (Expr) pop();
455             Expr lhs = (Expr) pop();
456 
457             push( getXPathFactory().createRelationalExpr( lhs,
458                                                          rhs,
459                                                          operator ) );
460         }
461     }
462 
463     public void startAdditiveExpr()
464     {
465     }
466 
467     public void endAdditiveExpr(int operator) throws JaxenException
468     {
469 
470         if ( operator != Operator.NO_OP )
471         {
472             
473             Expr rhs = (Expr) pop();
474             Expr lhs = (Expr) pop();
475             
476             push( getXPathFactory().createAdditiveExpr( lhs,
477                                                         rhs,
478                                                         operator ) );
479         }
480     }
481 
482     public void startMultiplicativeExpr()
483     {
484     }
485 
486     public void endMultiplicativeExpr(int operator) throws JaxenException
487     {
488 
489         if ( operator != Operator.NO_OP )
490         {
491 
492             Expr rhs = (Expr) pop();
493             Expr lhs = (Expr) pop();
494             
495             push( getXPathFactory().createMultiplicativeExpr( lhs,
496                                                              rhs,
497                                                              operator ) );
498         }
499     }
500 
501     public void startUnaryExpr()
502     {
503      }
504 
505     public void endUnaryExpr(int operator) throws JaxenException
506     {
507 
508         if ( operator != Operator.NO_OP )
509         {
510             push( getXPathFactory().createUnaryExpr( (Expr) pop(),
511                                                     operator ) );
512         }
513     }
514 
515     public void startUnionExpr() 
516     {
517     }
518 
519     public void endUnionExpr(boolean create) throws JaxenException
520     {
521 
522         if ( create )
523         {
524 
525             Expr rhs = (Expr) pop();
526             Expr lhs = (Expr) pop();
527 
528             push( getXPathFactory().createUnionExpr( lhs,
529                                                     rhs ) );
530         }
531     }
532 
533     public void number(int number) throws JaxenException
534     {
535         push( getXPathFactory().createNumberExpr( number ) );
536     }
537 
538     public void number(double number) throws JaxenException
539     {
540         push( getXPathFactory().createNumberExpr( number ) );
541     }
542 
543     public void literal(String literal) throws JaxenException
544     {
545         push( getXPathFactory().createLiteralExpr( literal ) );
546     }
547 
548     public void variableReference(String prefix,
549                                   String variableName) throws JaxenException
550     {
551         push( getXPathFactory().createVariableReferenceExpr( prefix,
552                                                              variableName ) );
553     }
554 
555     public void startFunction(String prefix,
556                               String functionName) throws JaxenException
557     {
558         pushFrame();
559         push( getXPathFactory().createFunctionCallExpr( prefix,
560                                                         functionName ) );
561     }
562 
563     public void endFunction()
564     {
565         FunctionCallExpr function = (FunctionCallExpr) peekFrame().removeFirst();
566 
567         addParameters( function,
568                        popFrame().iterator() );
569 
570         push( function );
571     }
572 
573     protected void addParameters(FunctionCallExpr function,
574                                Iterator paramIter)
575     {
576         while ( paramIter.hasNext() )
577         {
578             function.addParameter( (Expr) paramIter.next() );
579         }
580     }
581 
582     protected int stackSize()
583     {
584         return peekFrame().size();
585     }
586 
587     protected void push(Object obj)
588     {
589         peekFrame().addLast( obj );
590     }
591 
592     protected Object pop()
593     {
594         return peekFrame().removeLast();
595     }
596 
597     protected boolean canPop()
598     {
599         return ( peekFrame().size() > 0 );
600     }
601 
602     protected void pushFrame()
603     {
604         this.stack.addLast( new LinkedList() );
605     }
606 
607     protected LinkedList popFrame()
608     {
609         return (LinkedList) this.stack.removeLast();
610     }
611 
612     protected LinkedList peekFrame()
613     {
614         return (LinkedList) this.stack.getLast();
615     }
616 }