View Javadoc

1   /*
2    * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/pattern/PatternParser.java,v 1.15 2005/04/09 14:16:22 elharo Exp $
3    * $Revision: 1.15 $
4    * $Date: 2005/04/09 14:16:22 $
5    *
6    * ====================================================================
7    *
8    * Copyright (C) 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
13   * are met:
14   * 
15   * 1. Redistributions of source code must retain the above copyright
16   *    notice, this list of conditions, and the following disclaimer.
17   *
18   * 2. Redistributions in binary form must reproduce the above copyright
19   *    notice, this list of conditions, and the disclaimer that follows 
20   *    these conditions in the documentation and/or other materials 
21   *    provided with the distribution.
22   *
23   * 3. The name "Jaxen" must not be used to endorse or promote products
24   *    derived from this software without prior written permission.  For
25   *    written permission, please contact license@jaxen.org.
26   * 
27   * 4. Products derived from this software may not be called "Jaxen", nor
28   *    may "Jaxen" appear in their name, without prior written permission
29   *    from the Jaxen Project Management (pm@jaxen.org).
30   * 
31   * In addition, we request (but do not require) that you include in the 
32   * end-user documentation provided with the redistribution and/or in the 
33   * software itself an acknowledgement equivalent to the following:
34   *     "This product includes software developed by the
35   *      Jaxen Project (http://www.jaxen.org/)."
36   * Alternatively, the acknowledgment may be graphical using the logos 
37   * available at http://www.jaxen.org/
38   *
39   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
40   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
41   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
42   * DISCLAIMED.  IN NO EVENT SHALL THE Jaxen AUTHORS OR THE PROJECT
43   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
45   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
46   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
47   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
48   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
49   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50   * SUCH DAMAGE.
51   *
52   * ====================================================================
53   * This software consists of voluntary contributions made by many 
54   * individuals on behalf of the Jaxen Project and was originally 
55   * created by bob mcwhirter <bob@werken.com> and 
56   * James Strachan <jstrachan@apache.org>.  For more information on the 
57   * Jaxen Project, please see <http://www.jaxen.org/>.
58   * 
59   * $Id: PatternParser.java,v 1.15 2005/04/09 14:16:22 elharo Exp $
60   */
61  
62  
63  package org.jaxen.pattern;
64  
65  import java.util.Iterator;
66  import java.util.List;
67  import java.util.ListIterator;
68  
69  import org.jaxen.JaxenException;
70  import org.jaxen.JaxenHandler;
71  import org.jaxen.expr.DefaultAllNodeStep;
72  import org.jaxen.expr.DefaultCommentNodeStep;
73  import org.jaxen.expr.DefaultFilterExpr;
74  import org.jaxen.expr.DefaultNameStep;
75  import org.jaxen.expr.DefaultProcessingInstructionNodeStep;
76  import org.jaxen.expr.DefaultStep;
77  import org.jaxen.expr.DefaultTextNodeStep;
78  import org.jaxen.expr.DefaultXPathFactory;
79  import org.jaxen.expr.Expr;
80  import org.jaxen.expr.FilterExpr;
81  import org.jaxen.expr.LocationPath;
82  import org.jaxen.expr.Predicate;
83  import org.jaxen.expr.PredicateSet;
84  import org.jaxen.expr.Step;
85  import org.jaxen.expr.UnionExpr;
86  import org.jaxen.saxpath.Axis;
87  import org.jaxen.saxpath.XPathReader;
88  import org.jaxen.saxpath.helpers.XPathReaderFactory;
89  
90  
91  /*** <code>PatternParser</code> is a helper class for parsing
92    * XSLT patterns
93    *
94    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
95    */
96  public class PatternParser 
97  {
98      private static final boolean TRACE = false;
99      private static final boolean USE_HANDLER = false;
100     public static Pattern parse(String text) throws JaxenException, org.jaxen.saxpath.SAXPathException
101     {
102         if ( USE_HANDLER )
103         {
104             XPathReader reader = XPathReaderFactory.createReader();
105             PatternHandler handler = new PatternHandler();       
106             
107             handler.setXPathFactory( new DefaultXPathFactory() );            
108             reader.setXPathHandler( handler );
109             reader.parse( text );
110             
111             return handler.getPattern();
112         }
113         else
114         {
115             XPathReader reader = XPathReaderFactory.createReader();
116             JaxenHandler handler = new JaxenHandler();
117             
118             handler.setXPathFactory( new DefaultXPathFactory() );            
119             reader.setXPathHandler( handler );
120             reader.parse( text );
121 
122             Pattern pattern = convertExpr( handler.getXPathExpr().getRootExpr() );
123             return pattern.simplify();
124         }
125     }
126     
127     protected static Pattern convertExpr(Expr expr) throws JaxenException 
128     {
129         if ( TRACE )
130         {
131             System.out.println( "Converting: " + expr + " into a pattern." );
132         }
133         
134         if ( expr instanceof LocationPath )
135         {
136             return convertExpr( (LocationPath) expr );
137         }
138         else if ( expr instanceof FilterExpr )
139         {
140             LocationPathPattern answer = new LocationPathPattern();
141             answer.addFilter( (FilterExpr) expr );
142             return answer;
143         }
144         else if ( expr instanceof UnionExpr )
145         {
146             UnionExpr unionExpr = (UnionExpr) expr;
147             Pattern lhs = convertExpr( unionExpr.getLHS() );
148             Pattern rhs = convertExpr( unionExpr.getRHS() );
149             return new UnionPattern( lhs, rhs );
150         }
151         else 
152         {
153             LocationPathPattern answer = new LocationPathPattern();
154             answer.addFilter( new DefaultFilterExpr( expr,
155                                 new PredicateSet()) );
156             return answer;
157         }
158     }
159     
160     protected static LocationPathPattern convertExpr(LocationPath locationPath) throws JaxenException
161     {
162         LocationPathPattern answer = new LocationPathPattern();        
163         //answer.setAbsolute( locationPath.isAbsolute() );
164         List steps = locationPath.getSteps();
165         
166         // go through steps backwards
167         LocationPathPattern path = answer;
168         boolean first = true;
169         for ( ListIterator iter = steps.listIterator( steps.size() ); iter.hasPrevious(); ) 
170         {
171             Step step = (Step) iter.previous();
172             if ( first )
173             {
174                 first = false;
175                 path = convertStep( path, step );
176             }
177             else
178             {
179                 if ( navigationStep( step ) ) 
180                 {
181                     LocationPathPattern parent = new LocationPathPattern();
182                     int axis = step.getAxis();
183                     if ( axis == Axis.DESCENDANT || axis == Axis.DESCENDANT_OR_SELF )
184                     {
185                         path.setAncestorPattern( parent );
186                     }
187                     else
188                     {
189                         path.setParentPattern( parent );
190                     }
191                     path = parent;
192                 }
193                 path = convertStep( path, step );
194             }
195         }
196         if ( locationPath.isAbsolute() )
197         {
198             LocationPathPattern parent = new LocationPathPattern( NodeTypeTest.DOCUMENT_TEST );
199             path.setParentPattern( parent );
200         }
201         return answer;
202     }   
203     
204     protected static LocationPathPattern convertStep(LocationPathPattern path, Step step) throws JaxenException
205     {
206         if ( step instanceof DefaultAllNodeStep )
207         {
208             int axis = step.getAxis();
209             if ( axis == Axis.ATTRIBUTE )
210             {
211                 path.setNodeTest( NodeTypeTest.ATTRIBUTE_TEST );
212             }
213             else 
214             {
215                 path.setNodeTest( NodeTypeTest.ELEMENT_TEST );
216             }
217         }
218         else if ( step instanceof DefaultCommentNodeStep )
219         {
220             path.setNodeTest( NodeTypeTest.COMMENT_TEST );
221         }
222         else if ( step instanceof DefaultProcessingInstructionNodeStep )
223         {
224             path.setNodeTest( NodeTypeTest.PROCESSING_INSTRUCTION_TEST );
225         }
226         else if ( step instanceof DefaultTextNodeStep )
227         {
228             path.setNodeTest( TextNodeTest.SINGLETON );
229         }
230         else if ( step instanceof DefaultCommentNodeStep )
231         {
232             path.setNodeTest( NodeTypeTest.COMMENT_TEST );
233         }
234         else if ( step instanceof DefaultNameStep )
235         {
236             DefaultNameStep nameStep = (DefaultNameStep) step;
237             String localName = nameStep.getLocalName();
238             String prefix = nameStep.getPrefix();
239             int axis = nameStep.getAxis();
240             short nodeType = Pattern.ELEMENT_NODE;
241             if ( axis == Axis.ATTRIBUTE )
242             {
243                 nodeType = Pattern.ATTRIBUTE_NODE;
244             }
245             if ( nameStep.isMatchesAnyName() )
246             {
247                 if ( prefix.length() == 0 || prefix.equals( "*" ) ) 
248                 {
249                     if ( axis == Axis.ATTRIBUTE )
250                     {
251                         path.setNodeTest( NodeTypeTest.ATTRIBUTE_TEST );
252                     }
253                     else 
254                     {
255                         path.setNodeTest( NodeTypeTest.ELEMENT_TEST );
256                     }
257                 }
258                 else 
259                 {
260                     path.setNodeTest( new NamespaceTest( prefix, nodeType ) );
261                 }
262             }
263             else 
264             {
265                 path.setNodeTest( new NameTest( localName, nodeType ) );
266                 // XXXX: should support namespace in the test too
267             }
268             return convertDefaultStep(path, nameStep);
269         }
270         else if ( step instanceof DefaultStep )
271         {
272             return convertDefaultStep(path, (DefaultStep) step);
273         }
274         else 
275         {
276             throw new JaxenException( "Cannot convert: " + step + " to a Pattern" );            
277         }
278         return path;
279     }
280     
281     protected static LocationPathPattern convertDefaultStep(LocationPathPattern path, DefaultStep step) throws JaxenException
282     {
283         List predicates = step.getPredicates();
284         if ( ! predicates.isEmpty() ) 
285         {
286             DefaultFilterExpr filter = new DefaultFilterExpr(new PredicateSet());
287             for ( Iterator iter = predicates.iterator(); iter.hasNext(); )
288             {
289                 filter.addPredicate( (Predicate) iter.next() );
290             }
291             path.addFilter( filter );
292         }         
293         return path;
294     }
295     
296     protected static boolean navigationStep( Step step )
297     {
298         if ( step instanceof DefaultNameStep )
299         {
300             return true;
301         }
302         else
303         if ( step.getClass().equals( DefaultStep.class ) )
304         {
305             return ! step.getPredicates().isEmpty();
306         }
307         else 
308         {
309             return true;
310         }
311     }
312 
313 }
314