1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
185
186
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
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
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 }