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