View Javadoc

1   /*
2    * $Header$
3    * $Revision: 1128 $
4    * $Date: 2006-02-05 13:49:04 -0800 (Sun, 05 Feb 2006) $
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: PatternParser.java 1128 2006-02-05 21:49:04Z elharo $
46   */
47  
48  
49  package org.jaxen.pattern;
50  
51  import java.util.Iterator;
52  import java.util.List;
53  import java.util.ListIterator;
54  
55  import org.jaxen.JaxenException;
56  import org.jaxen.JaxenHandler;
57  import org.jaxen.expr.DefaultAllNodeStep;
58  import org.jaxen.expr.DefaultCommentNodeStep;
59  import org.jaxen.expr.DefaultFilterExpr;
60  import org.jaxen.expr.DefaultNameStep;
61  import org.jaxen.expr.DefaultProcessingInstructionNodeStep;
62  import org.jaxen.expr.DefaultStep;
63  import org.jaxen.expr.DefaultTextNodeStep;
64  import org.jaxen.expr.DefaultXPathFactory;
65  import org.jaxen.expr.Expr;
66  import org.jaxen.expr.FilterExpr;
67  import org.jaxen.expr.LocationPath;
68  import org.jaxen.expr.Predicate;
69  import org.jaxen.expr.PredicateSet;
70  import org.jaxen.expr.Step;
71  import org.jaxen.expr.UnionExpr;
72  import org.jaxen.saxpath.Axis;
73  import org.jaxen.saxpath.XPathReader;
74  import org.jaxen.saxpath.helpers.XPathReaderFactory;
75  
76  
77  /** <code>PatternParser</code> is a helper class for parsing
78    * XSLT patterns
79    *
80    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
81    */
82  public class PatternParser 
83  {
84      private static final boolean TRACE = false;
85      private static final boolean USE_HANDLER = false;
86      public static Pattern parse(String text) throws JaxenException, org.jaxen.saxpath.SAXPathException
87      {
88          if ( USE_HANDLER )
89          {
90              XPathReader reader = XPathReaderFactory.createReader();
91              PatternHandler handler = new PatternHandler();       
92              
93              handler.setXPathFactory( new DefaultXPathFactory() );            
94              reader.setXPathHandler( handler );
95              reader.parse( text );
96              
97              return handler.getPattern();
98          }
99          else
100         {
101             XPathReader reader = XPathReaderFactory.createReader();
102             JaxenHandler handler = new JaxenHandler();
103             
104             handler.setXPathFactory( new DefaultXPathFactory() );            
105             reader.setXPathHandler( handler );
106             reader.parse( text );
107 
108             Pattern pattern = convertExpr( handler.getXPathExpr().getRootExpr() );
109             return pattern.simplify();
110         }
111     }
112     
113     protected static Pattern convertExpr(Expr expr) throws JaxenException 
114     {
115         if ( TRACE )
116         {
117             System.out.println( "Converting: " + expr + " into a pattern." );
118         }
119         
120         if ( expr instanceof LocationPath )
121         {
122             return convertExpr( (LocationPath) expr );
123         }
124         else if ( expr instanceof FilterExpr )
125         {
126             LocationPathPattern answer = new LocationPathPattern();
127             answer.addFilter( (FilterExpr) expr );
128             return answer;
129         }
130         else if ( expr instanceof UnionExpr )
131         {
132             UnionExpr unionExpr = (UnionExpr) expr;
133             Pattern lhs = convertExpr( unionExpr.getLHS() );
134             Pattern rhs = convertExpr( unionExpr.getRHS() );
135             return new UnionPattern( lhs, rhs );
136         }
137         else 
138         {
139             LocationPathPattern answer = new LocationPathPattern();
140             answer.addFilter( new DefaultFilterExpr( expr,
141                                 new PredicateSet()) );
142             return answer;
143         }
144     }
145     
146     protected static LocationPathPattern convertExpr(LocationPath locationPath) throws JaxenException
147     {
148         LocationPathPattern answer = new LocationPathPattern();        
149         //answer.setAbsolute( locationPath.isAbsolute() );
150         List steps = locationPath.getSteps();
151         
152         // go through steps backwards
153         LocationPathPattern path = answer;
154         boolean first = true;
155         for ( ListIterator iter = steps.listIterator( steps.size() ); iter.hasPrevious(); ) 
156         {
157             Step step = (Step) iter.previous();
158             if ( first )
159             {
160                 first = false;
161                 path = convertStep( path, step );
162             }
163             else
164             {
165                 if ( navigationStep( step ) ) 
166                 {
167                     LocationPathPattern parent = new LocationPathPattern();
168                     int axis = step.getAxis();
169                     if ( axis == Axis.DESCENDANT || axis == Axis.DESCENDANT_OR_SELF )
170                     {
171                         path.setAncestorPattern( parent );
172                     }
173                     else
174                     {
175                         path.setParentPattern( parent );
176                     }
177                     path = parent;
178                 }
179                 path = convertStep( path, step );
180             }
181         }
182         if ( locationPath.isAbsolute() )
183         {
184             LocationPathPattern parent = new LocationPathPattern( NodeTypeTest.DOCUMENT_TEST );
185             path.setParentPattern( parent );
186         }
187         return answer;
188     }   
189     
190     protected static LocationPathPattern convertStep(LocationPathPattern path, Step step) throws JaxenException
191     {
192         if ( step instanceof DefaultAllNodeStep )
193         {
194             int axis = step.getAxis();
195             if ( axis == Axis.ATTRIBUTE )
196             {
197                 path.setNodeTest( NodeTypeTest.ATTRIBUTE_TEST );
198             }
199             else 
200             {
201                 path.setNodeTest( NodeTypeTest.ELEMENT_TEST );
202             }
203         }
204         else if ( step instanceof DefaultCommentNodeStep )
205         {
206             path.setNodeTest( NodeTypeTest.COMMENT_TEST );
207         }
208         else if ( step instanceof DefaultProcessingInstructionNodeStep )
209         {
210             path.setNodeTest( NodeTypeTest.PROCESSING_INSTRUCTION_TEST );
211         }
212         else if ( step instanceof DefaultTextNodeStep )
213         {
214             path.setNodeTest( TextNodeTest.SINGLETON );
215         }
216         else if ( step instanceof DefaultCommentNodeStep )
217         {
218             path.setNodeTest( NodeTypeTest.COMMENT_TEST );
219         }
220         else if ( step instanceof DefaultNameStep )
221         {
222             DefaultNameStep nameStep = (DefaultNameStep) step;
223             String localName = nameStep.getLocalName();
224             String prefix = nameStep.getPrefix();
225             int axis = nameStep.getAxis();
226             short nodeType = Pattern.ELEMENT_NODE;
227             if ( axis == Axis.ATTRIBUTE )
228             {
229                 nodeType = Pattern.ATTRIBUTE_NODE;
230             }
231             if ( nameStep.isMatchesAnyName() )
232             {
233                 if ( prefix.length() == 0 || prefix.equals( "*" ) ) 
234                 {
235                     if ( axis == Axis.ATTRIBUTE )
236                     {
237                         path.setNodeTest( NodeTypeTest.ATTRIBUTE_TEST );
238                     }
239                     else 
240                     {
241                         path.setNodeTest( NodeTypeTest.ELEMENT_TEST );
242                     }
243                 }
244                 else 
245                 {
246                     path.setNodeTest( new NamespaceTest( prefix, nodeType ) );
247                 }
248             }
249             else 
250             {
251                 path.setNodeTest( new NameTest( localName, nodeType ) );
252                 // XXXX: should support namespace in the test too
253             }
254             return convertDefaultStep(path, nameStep);
255         }
256         else if ( step instanceof DefaultStep )
257         {
258             return convertDefaultStep(path, (DefaultStep) step);
259         }
260         else 
261         {
262             throw new JaxenException( "Cannot convert: " + step + " to a Pattern" );            
263         }
264         return path;
265     }
266     
267     protected static LocationPathPattern convertDefaultStep(LocationPathPattern path, DefaultStep step) throws JaxenException
268     {
269         List predicates = step.getPredicates();
270         if ( ! predicates.isEmpty() ) 
271         {
272             FilterExpr filter = new DefaultFilterExpr(new PredicateSet());
273             for ( Iterator iter = predicates.iterator(); iter.hasNext(); )
274             {
275                 filter.addPredicate( (Predicate) iter.next() );
276             }
277             path.addFilter( filter );
278         }         
279         return path;
280     }
281     
282     protected static boolean navigationStep( Step step )
283     {
284         if ( step instanceof DefaultNameStep )
285         {
286             return true;
287         }
288         else
289         if ( step.getClass().equals( DefaultStep.class ) )
290         {
291             return ! step.getPredicates().isEmpty();
292         }
293         else 
294         {
295             return true;
296         }
297     }
298 
299 }
300