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 <https://github.com/jaxen-xpath/jaxen/>.
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  /**
69   * SAXPath <code>XPathHandler</code> implementation capable
70   * of building Jaxen expression trees which can walk various
71   * different object models.
72   *
73   * @author bob mcwhirter (bob@werken.com)
74   */
75  public class JaxenHandler implements XPathHandler
76  {
77      private XPathFactory xpathFactory;
78      private XPathExpr    xpath;
79      
80      /**
81       * ????
82       */
83      protected boolean simplified;
84  
85      /**
86       * This may be changed to an ArrayList in the future (i.e. version &gt;= 1.2).
87       * You really shouldn't be accessing this field directly, but
88       * if you are please try to use it as a generic List. Don't use the
89       * methods that are only available in LinkedList.
90       */
91      protected LinkedList stack;
92  
93      /**
94       * Constructor.
95       */
96      public JaxenHandler()
97      {
98          this.stack        = new LinkedList();
99          this.xpathFactory = new DefaultXPathFactory();
100     }
101     
102     /**
103      * Set the Jaxen <code>XPathFactory</code> that constructs
104      * the XPath expression tree during the parse.
105      *
106      * @param xpathFactory the factory to use during the parse
107      */
108     public void setXPathFactory(XPathFactory xpathFactory)
109     {
110         this.xpathFactory = xpathFactory;
111     }
112 
113     /**
114      * Retrieve the Jaxen <code>XPathFactory</code> used
115      * during the parse to construct the XPath expression tree.
116      *
117      * @return the <code>XPathFactory</code> used during the parse
118      */
119     public XPathFactory getXPathFactory()
120     {
121         return this.xpathFactory;
122     }
123 
124     /**
125      * Retrieve the simplified Jaxen XPath expression tree.
126      *
127      * <p>
128      * This method is only valid once <code>XPathReader.parse(...)</code>
129      * successfully returned.
130      * </p>
131      *
132      * @return the XPath expression tree
133      */
134     public XPathExpr getXPathExpr()
135     {
136         return getXPathExpr( true );
137     }
138 
139     /**
140      * Retrieve the Jaxen XPath expression tree, optionally
141      * simplified.
142      *
143      * <p>
144      * This method is only valid once <code>XPathReader.parse(...)</code>
145      * successfully returned.
146      * </p>
147      *
148      * @param shouldSimplify ????
149      * @return the XPath expression tree
150      */
151     public XPathExpr getXPathExpr(boolean shouldSimplify)
152     {
153         if ( shouldSimplify && ! this.simplified )
154         {
155             this.xpath.simplify();
156             this.simplified = true;
157         }
158 
159         return this.xpath;
160     }
161 
162     public void startXPath()
163     {
164         this.simplified = false;
165         pushFrame();
166     }
167     
168     public void endXPath() throws JaxenException
169     {
170         this.xpath = getXPathFactory().createXPath( (Expr) pop() );
171         popFrame();
172     }
173 
174     public void startPathExpr()
175     {
176         pushFrame();
177     }
178 
179     public void endPathExpr() throws JaxenException
180     {
181 
182         // PathExpr ::=   LocationPath
183         //              | FilterExpr
184         //              | FilterExpr / RelativeLocationPath
185         //              | FilterExpr // RelativeLocationPath
186         //
187         // If the current stack-frame has two items, it's a
188         // FilterExpr and a LocationPath (of some flavor).
189         //
190         // If the current stack-frame has one item, it's simply
191         // a FilterExpr, and more than likely boils down to a
192         // primary expr of some flavor.  But that's for another
193         // method...
194 
195         FilterExpr   filterExpr;
196         LocationPath locationPath;
197 
198         Object       popped;
199 
200         if ( stackSize() == 2 )
201         {
202             locationPath = (LocationPath) pop();
203             filterExpr   = (FilterExpr) pop();
204         }
205         else
206         {
207             popped = pop();
208 
209             if ( popped instanceof LocationPath )
210             {
211                 locationPath = (LocationPath) popped;
212                 filterExpr   = null;
213             }
214             else
215             {
216                 locationPath = null;
217                 filterExpr   = (FilterExpr) popped;
218             }
219         }
220         popFrame();
221 
222         push( getXPathFactory().createPathExpr( filterExpr,
223                                                locationPath ) );
224     }
225 
226     public void startAbsoluteLocationPath() throws JaxenException
227     {
228         pushFrame();
229 
230         push( getXPathFactory().createAbsoluteLocationPath() );
231     }
232 
233     public void endAbsoluteLocationPath() throws JaxenException
234     {
235         endLocationPath();
236     }
237 
238     public void startRelativeLocationPath() throws JaxenException
239     {
240         pushFrame();
241 
242         push( getXPathFactory().createRelativeLocationPath() );
243     }
244 
245     public void endRelativeLocationPath() throws JaxenException
246     {
247         endLocationPath();
248     }
249 
250     protected void endLocationPath() throws JaxenException 
251     {
252         LocationPath path = (LocationPath) peekFrame().removeFirst();
253 
254         addSteps( path,
255                   popFrame().iterator() );
256 
257         push( path );
258     }
259 
260     protected void addSteps(LocationPath locationPath,
261                           Iterator stepIter)
262     {
263         while ( stepIter.hasNext() )
264         {
265             locationPath.addStep( (Step) stepIter.next() );
266         }
267     }
268 
269     public void startNameStep(int axis,
270                               String prefix,
271                               String localName) throws JaxenException
272     {
273         pushFrame();
274 
275         push( getXPathFactory().createNameStep( axis,
276                                                prefix,
277                                                localName ) );
278     }
279 
280     public void endNameStep() 
281     {
282         endStep();
283     }
284     
285     public void startTextNodeStep(int axis) throws JaxenException
286     {
287         //System.err.println("startTextNodeStep()");
288         pushFrame();
289         
290         push( getXPathFactory().createTextNodeStep( axis ) );
291     }
292     
293     public void endTextNodeStep()
294     {
295         endStep();
296     }
297 
298     public void startCommentNodeStep(int axis) throws JaxenException
299     {
300         pushFrame();
301 
302         push( getXPathFactory().createCommentNodeStep( axis ) );
303     }
304 
305     public void endCommentNodeStep()
306     {
307         endStep();
308     }
309         
310     public void startAllNodeStep(int axis) throws JaxenException
311     {
312         pushFrame();
313 
314         push( getXPathFactory().createAllNodeStep( axis ) );
315     }
316 
317     public void endAllNodeStep()
318     {
319         endStep();
320     }
321 
322     public void startProcessingInstructionNodeStep(int axis,
323                                                    String name) throws JaxenException
324     {
325         pushFrame();
326 
327         push( getXPathFactory().createProcessingInstructionNodeStep( axis,
328                                                                     name ) );
329     }
330     
331     public void endProcessingInstructionNodeStep()
332     {
333         endStep();
334     }
335 
336     protected void endStep()
337     {
338         Step step = (Step) peekFrame().removeFirst();
339 
340         addPredicates( step,
341                        popFrame().iterator() );
342 
343         push( step );
344     }
345     
346     public void startPredicate()
347     {
348         pushFrame();
349     }
350     
351     public void endPredicate() throws JaxenException
352     {
353         Predicate predicate = getXPathFactory().createPredicate( (Expr) pop() );
354 
355         popFrame();
356 
357         push( predicate );
358     }
359 
360     public void startFilterExpr() 
361     {
362         pushFrame();
363     }
364 
365     public void endFilterExpr() throws JaxenException
366     {
367         Expr expr = (Expr) peekFrame().removeFirst();
368         
369         FilterExpr filter = getXPathFactory().createFilterExpr( expr );
370 
371         Iterator predIter = popFrame().iterator();
372 
373         addPredicates( filter,
374                        predIter );
375 
376         push( filter );
377     }
378 
379     protected void addPredicates(Predicated obj,
380                                Iterator predIter)
381     {
382         while ( predIter.hasNext() )
383         {
384             obj.addPredicate( (Predicate) predIter.next() );
385         }
386     }
387 
388     protected void returnExpr()
389     {
390         Expr expr = (Expr) pop();
391         popFrame();
392         push( expr );
393     }
394 
395     public void startOrExpr()
396     {
397     }
398 
399     public void endOrExpr(boolean create) throws JaxenException
400     {
401 
402         if ( create )
403         {
404             Expr rhs = (Expr) pop();
405             Expr lhs = (Expr) pop();
406 
407             push( getXPathFactory().createOrExpr( lhs,
408                                                  rhs ) );
409         }
410     }
411 
412     public void startAndExpr()
413     {
414     }
415 
416     public void endAndExpr(boolean create) throws JaxenException
417     {
418 
419         if ( create )
420         {
421 
422             Expr rhs = (Expr) pop();
423             Expr lhs = (Expr) pop();
424 
425             push( getXPathFactory().createAndExpr( lhs,
426                                                   rhs ) );
427         }
428     }
429 
430     public void startEqualityExpr()
431     {
432     }
433 
434     public void endEqualityExpr(int operator) throws JaxenException
435     {
436 
437         if ( operator != Operator.NO_OP )
438         {
439             
440             Expr rhs = (Expr) pop();
441             Expr lhs = (Expr) pop();
442             
443             push( getXPathFactory().createEqualityExpr( lhs,
444                                                         rhs,
445                                                         operator ) );
446         }
447     }
448 
449     public void startRelationalExpr()
450     {
451     }
452 
453     public void endRelationalExpr(int operator) throws JaxenException
454     {
455 
456         if ( operator != Operator.NO_OP )
457         {
458 
459             Expr rhs = (Expr) pop();
460             Expr lhs = (Expr) pop();
461 
462             push( getXPathFactory().createRelationalExpr( lhs,
463                                                          rhs,
464                                                          operator ) );
465         }
466     }
467 
468     public void startAdditiveExpr()
469     {
470     }
471 
472     public void endAdditiveExpr(int operator) throws JaxenException
473     {
474 
475         if ( operator != Operator.NO_OP )
476         {
477             
478             Expr rhs = (Expr) pop();
479             Expr lhs = (Expr) pop();
480             
481             push( getXPathFactory().createAdditiveExpr( lhs,
482                                                         rhs,
483                                                         operator ) );
484         }
485     }
486 
487     public void startMultiplicativeExpr()
488     {
489     }
490 
491     public void endMultiplicativeExpr(int operator) throws JaxenException
492     {
493 
494         if ( operator != Operator.NO_OP )
495         {
496 
497             Expr rhs = (Expr) pop();
498             Expr lhs = (Expr) pop();
499             
500             push( getXPathFactory().createMultiplicativeExpr( lhs,
501                                                              rhs,
502                                                              operator ) );
503         }
504     }
505 
506     public void startUnaryExpr()
507     {
508      }
509 
510     public void endUnaryExpr(int operator) throws JaxenException
511     {
512 
513         if ( operator != Operator.NO_OP )
514         {
515             push( getXPathFactory().createUnaryExpr( (Expr) pop(),
516                                                     operator ) );
517         }
518     }
519 
520     public void startUnionExpr() 
521     {
522     }
523 
524     public void endUnionExpr(boolean create) throws JaxenException
525     {
526 
527         if ( create )
528         {
529 
530             Expr rhs = (Expr) pop();
531             Expr lhs = (Expr) pop();
532 
533             push( getXPathFactory().createUnionExpr( lhs,
534                                                     rhs ) );
535         }
536     }
537 
538     public void number(int number) throws JaxenException
539     {
540         push( getXPathFactory().createNumberExpr( number ) );
541     }
542 
543     public void number(double number) throws JaxenException
544     {
545         push( getXPathFactory().createNumberExpr( number ) );
546     }
547 
548     public void literal(String literal) throws JaxenException
549     {
550         push( getXPathFactory().createLiteralExpr( literal ) );
551     }
552 
553     public void variableReference(String prefix,
554                                   String variableName) throws JaxenException
555     {
556         push( getXPathFactory().createVariableReferenceExpr( prefix,
557                                                              variableName ) );
558     }
559 
560     public void startFunction(String prefix,
561                               String functionName) throws JaxenException
562     {
563         pushFrame();
564         push( getXPathFactory().createFunctionCallExpr( prefix,
565                                                         functionName ) );
566     }
567 
568     public void endFunction()
569     {
570         FunctionCallExpr function = (FunctionCallExpr) peekFrame().removeFirst();
571 
572         addParameters( function,
573                        popFrame().iterator() );
574 
575         push( function );
576     }
577 
578     protected void addParameters(FunctionCallExpr function,
579                                Iterator paramIter)
580     {
581         while ( paramIter.hasNext() )
582         {
583             function.addParameter( (Expr) paramIter.next() );
584         }
585     }
586 
587     protected int stackSize()
588     {
589         return peekFrame().size();
590     }
591 
592     protected void push(Object obj)
593     {
594         peekFrame().addLast( obj );
595     }
596 
597     protected Object pop()
598     {
599         return peekFrame().removeLast();
600     }
601 
602     protected boolean canPop()
603     {
604         return ( peekFrame().size() > 0 );
605     }
606 
607     protected void pushFrame()
608     {
609         this.stack.addLast( new LinkedList() );
610     }
611 
612     protected LinkedList popFrame()
613     {
614         return (LinkedList) this.stack.removeLast();
615     }
616 
617     protected LinkedList peekFrame()
618     {
619         return (LinkedList) this.stack.getLast();
620     }
621 }