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