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