View Javadoc

1   /*
2    * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/pattern/LocationPathPattern.java,v 1.13 2003/06/29 18:01:52 ssanders Exp $
3    * $Revision: 1.13 $
4    * $Date: 2003/06/29 18:01:52 $
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: LocationPathPattern.java,v 1.13 2003/06/29 18:01:52 ssanders Exp $
60   */
61  
62  package org.jaxen.pattern;
63  
64  import java.util.ArrayList;
65  import java.util.Iterator;
66  import java.util.List;
67  
68  import org.jaxen.Context;
69  import org.jaxen.JaxenException;
70  import org.jaxen.Navigator;
71  import org.jaxen.expr.FilterExpr;
72  import org.jaxen.util.SingletonList;
73  
74  /*** <p><code>LocationPathPattern</code> matches any node using a
75    * location path such as A/B/C.
76    * The parentPattern and ancestorPattern properties are used to
77    * chain location path patterns together</p>
78    *
79    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
80    * @version $Revision: 1.13 $
81    */
82  public class LocationPathPattern extends Pattern {
83  
84      /*** The node test to perform on this step of the path */
85      private NodeTest nodeTest = AnyNodeTest.getInstance();
86      
87      /*** Patterns matching my parent node */
88      private Pattern parentPattern;
89      
90      /*** Patterns matching one of my ancestors */
91      private Pattern ancestorPattern;
92          
93      /*** The filters to match against */
94      private List filters;
95  
96      /*** Whether this lcoation path is absolute or not */
97      private boolean absolute;
98      
99      
100     public LocationPathPattern()   
101     {
102     }
103 
104     public LocationPathPattern(NodeTest nodeTest)   
105     {
106         this.nodeTest = nodeTest;
107     }
108 
109     public Pattern simplify()
110     {
111         if ( parentPattern != null )
112         {
113             parentPattern = parentPattern.simplify();
114         }
115         if ( ancestorPattern != null )
116         {
117             ancestorPattern = ancestorPattern.simplify();
118         }
119         if ( filters == null )
120         {
121             if ( parentPattern == null && ancestorPattern == null )
122             {
123                 return nodeTest;
124             }
125             if ( parentPattern != null && ancestorPattern == null )
126             {
127                 if ( nodeTest instanceof AnyNodeTest )
128                 {
129                     return parentPattern;
130                 }
131             }
132         }
133         return this;
134     }
135     
136     /*** Adds a filter to this pattern
137      */
138     public void addFilter(FilterExpr filter) 
139     {
140         if ( filters == null )
141         {
142             filters = new ArrayList();
143         }
144         filters.add( filter );
145     }
146     
147     /*** Adds a pattern for the parent of the current
148      * context node used in this pattern.
149      */
150     public void setParentPattern(Pattern parentPattern) 
151     {
152         this.parentPattern = parentPattern;
153     }
154     
155     /*** Adds a pattern for an ancestor of the current
156      * context node used in this pattern.
157      */
158     public void setAncestorPattern(Pattern ancestorPattern) 
159     {
160         this.ancestorPattern = ancestorPattern;
161     }
162     
163     /*** Allows the NodeTest to be set
164      */
165     public void setNodeTest(NodeTest nodeTest) throws JaxenException
166     {
167         if ( this.nodeTest instanceof AnyNodeTest )
168         {
169             this.nodeTest = nodeTest;
170         }   
171         else 
172         {
173             throw new JaxenException( "Attempt to overwrite nodeTest: " + this.nodeTest + " with: " + nodeTest );
174         }
175     }
176     
177     /*** @return true if the pattern matches the given node
178       */
179     public boolean matches( Object node, Context context ) throws JaxenException
180     {
181         Navigator navigator = context.getNavigator();
182 
183 /*        
184         if ( isAbsolute() )
185         {
186             node = navigator.getDocumentNode( node );
187         }
188 */
189         if (! nodeTest.matches(node, context) )
190         {
191             return false;
192         }
193         
194         if (parentPattern != null) 
195         {
196             Object parent = navigator.getParentNode( node );
197             if ( parent == null ) 
198             {
199                 return false;
200             }
201             if ( ! parentPattern.matches( parent, context ) ) 
202             {
203                 return false;
204             }
205         }
206 
207         if (ancestorPattern != null) {
208             Object ancestor = navigator.getParentNode( node );
209             while (true)
210             {
211                 if ( ancestorPattern.matches( ancestor, context ) )
212                 {
213                     break;
214                 }
215                 if ( ancestor == null )
216                 {
217                     return false;
218                 }
219                 if ( navigator.isDocument( ancestor ) )
220                 {
221                     return false;
222                 }
223                 ancestor = navigator.getParentNode( ancestor );
224             }
225         }
226         
227         if (filters != null) 
228         {
229             List list = new SingletonList(node);
230 
231             context.setNodeSet( list );
232             
233             // XXXX: filters aren't positional, so should we clone context?
234 
235             boolean answer = true;
236 
237             for (Iterator iter = filters.iterator(); iter.hasNext(); ) 
238             {
239                 FilterExpr filter = (FilterExpr) iter.next();
240 
241                 if ( ! filter.asBoolean( context ) )
242                 {
243                     answer = false;
244                     break;
245                 }
246             }
247             // restore context
248 
249             context.setNodeSet( list );
250 
251             return answer;
252         }
253         return true;
254     }
255     
256     public double getPriority() 
257     {
258         if ( filters != null ) 
259         {
260             return 0.5;
261         }
262         return nodeTest.getPriority();
263     }
264 
265 
266     public short getMatchType() 
267     {
268         return nodeTest.getMatchType();
269     }
270     
271     public String getText() 
272     {
273         StringBuffer buffer = new StringBuffer();
274         if ( absolute )
275         {
276             buffer.append( "/" );
277         }
278         if (ancestorPattern != null) 
279         {
280             String text = ancestorPattern.getText();
281             if ( text.length() > 0 )
282             {
283                 buffer.append( text );
284                 buffer.append( "//" );
285             }
286         }
287         if (parentPattern != null) 
288         {
289             String text = parentPattern.getText();
290             if ( text.length() > 0 )
291             {
292                 buffer.append( text );
293                 buffer.append( "/" );
294             }
295         }
296         buffer.append( nodeTest.getText() );
297         
298         if ( filters != null ) 
299         {
300             buffer.append( "[" );
301             for (Iterator iter = filters.iterator(); iter.hasNext(); ) 
302             {
303                 FilterExpr filter = (FilterExpr) iter.next();
304                 buffer.append( filter.getText() );
305             }
306             buffer.append( "]" );
307         }        
308         return buffer.toString();
309     }
310     
311     public String toString()
312     {
313         return super.toString() + "[ absolute: " + absolute + " parent: " + parentPattern + " ancestor: " 
314             + ancestorPattern + " filters: " + filters + " nodeTest: " 
315             + nodeTest + " ]";
316     }
317     
318     public boolean isAbsolute()
319     {
320         return absolute;
321     }
322     
323     public void setAbsolute(boolean absolute)
324     {
325         this.absolute = absolute;
326     }
327     
328     public boolean hasAnyNodeTest()
329     {
330         return nodeTest instanceof AnyNodeTest;
331     }
332         
333 }