Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
BaseXPath |
|
| 1.8148148148148149;1.815 |
1 | /* |
|
2 | * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/BaseXPath.java,v 1.48 2005/09/24 23:05:15 elharo Exp $ |
|
3 | * $Revision: 1.48 $ |
|
4 | * $Date: 2005/09/24 23:05:15 $ |
|
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: BaseXPath.java,v 1.48 2005/09/24 23:05:15 elharo Exp $ |
|
60 | */ |
|
61 | ||
62 | ||
63 | package org.jaxen; |
|
64 | ||
65 | import java.io.Serializable; |
|
66 | import java.util.List; |
|
67 | ||
68 | import org.jaxen.expr.Expr; |
|
69 | import org.jaxen.expr.XPathExpr; |
|
70 | import org.jaxen.function.BooleanFunction; |
|
71 | import org.jaxen.function.NumberFunction; |
|
72 | import org.jaxen.function.StringFunction; |
|
73 | import org.jaxen.saxpath.SAXPathException; |
|
74 | import org.jaxen.saxpath.XPathReader; |
|
75 | import org.jaxen.saxpath.helpers.XPathReaderFactory; |
|
76 | import org.jaxen.util.SingletonList; |
|
77 | ||
78 | /** Base functionality for all concrete, implementation-specific XPaths. |
|
79 | * |
|
80 | * <p> |
|
81 | * This class provides generic functionality for further-defined |
|
82 | * implementation-specific XPaths. |
|
83 | * </p> |
|
84 | * |
|
85 | * <p> |
|
86 | * If you want to adapt the Jaxen engine so that it can traverse your own |
|
87 | * object model, then this is a good base class to derive from. |
|
88 | * Typically you only really need to provide your own |
|
89 | * {@link org.jaxen.Navigator} implementation. |
|
90 | * </p> |
|
91 | * |
|
92 | * @see org.jaxen.dom4j.Dom4jXPath XPath for dom4j |
|
93 | * @see org.jaxen.jdom.JDOMXPath XPath for JDOM |
|
94 | * @see org.jaxen.dom.DOMXPath XPath for W3C DOM |
|
95 | * |
|
96 | * @author <a href="mailto:bob@werken.com">bob mcwhirter</a> |
|
97 | * @author <a href="mailto:jstrachan@apache.org">James Strachan</a> |
|
98 | */ |
|
99 | public class BaseXPath implements XPath, Serializable |
|
100 | { |
|
101 | /** Original expression text. */ |
|
102 | private String exprText; |
|
103 | ||
104 | /** the parsed form of the XPath expression */ |
|
105 | private XPathExpr xpath; |
|
106 | ||
107 | /** the support information and function, namespace and variable contexts */ |
|
108 | private ContextSupport support; |
|
109 | ||
110 | /** the implementation-specific Navigator for retrieving XML nodes **/ |
|
111 | private Navigator navigator; |
|
112 | ||
113 | /** Construct given an XPath expression string. |
|
114 | * |
|
115 | * @param xpathExpr the XPath expression |
|
116 | * |
|
117 | * @throws JaxenException if there is a syntax error while |
|
118 | * parsing the expression |
|
119 | */ |
|
120 | protected BaseXPath(String xpathExpr) throws JaxenException |
|
121 | 10578 | { |
122 | try |
|
123 | { |
|
124 | 10578 | XPathReader reader = XPathReaderFactory.createReader(); |
125 | 10572 | JaxenHandler handler = new JaxenHandler(); |
126 | 10572 | reader.setXPathHandler( handler ); |
127 | 10572 | reader.parse( xpathExpr ); |
128 | 10356 | this.xpath = handler.getXPathExpr(); |
129 | } |
|
130 | 216 | catch (org.jaxen.saxpath.XPathSyntaxException e) |
131 | { |
|
132 | 216 | throw new org.jaxen.XPathSyntaxException( e ); |
133 | } |
|
134 | 6 | catch (SAXPathException e) |
135 | { |
|
136 | 6 | throw new JaxenException( e ); |
137 | 10356 | } |
138 | ||
139 | 10356 | this.exprText = xpathExpr; |
140 | 10356 | } |
141 | ||
142 | /** Construct given an XPath expression string. |
|
143 | * |
|
144 | * @param xpathExpr the XPath expression |
|
145 | * |
|
146 | * @param navigator the XML navigator to use |
|
147 | * |
|
148 | * @throws JaxenException if there is a syntax error while |
|
149 | * parsing the expression |
|
150 | */ |
|
151 | public BaseXPath(String xpathExpr, Navigator navigator) throws JaxenException |
|
152 | { |
|
153 | 3510 | this( xpathExpr ); |
154 | 3480 | this.navigator = navigator; |
155 | 3480 | } |
156 | ||
157 | /** Evaluate this XPath against a given context. |
|
158 | * The context of evaluation may be any object type |
|
159 | * the navigator recognizes as a node. |
|
160 | * The return value is either a <code>String</code>, |
|
161 | * <code>Double</code>, <code>Boolean</code>, or <code>List</code> |
|
162 | * of nodes. |
|
163 | * |
|
164 | * <p> |
|
165 | * When using this method, one must be careful to |
|
166 | * test the class of the returned object. If the returned |
|
167 | * object is a list, then the items in this |
|
168 | * list will be the actual <code>Document</code>, |
|
169 | * <code>Element</code>, <code>Attribute</code>, etc. objects |
|
170 | * as defined by the concrete XML object-model implementation, |
|
171 | * directly from the context document. This method <strong>does |
|
172 | * not return <em>copies</em> of anything</strong>, but merely |
|
173 | * returns references to objects within the source document. |
|
174 | * </p> |
|
175 | * |
|
176 | * @param context the node, node-set or Context object for evaluation. |
|
177 | * This value can be null. |
|
178 | * |
|
179 | * @return the result of evaluating the XPath expression |
|
180 | * against the supplied context |
|
181 | * @throws JaxenException if an XPath error occurs during expression evaluation |
|
182 | * @throws ClassCastException if the context is not a node |
|
183 | */ |
|
184 | public Object evaluate(Object context) throws JaxenException |
|
185 | { |
|
186 | 4644 | List answer = selectNodes(context); |
187 | ||
188 | 4584 | if ( answer != null |
189 | && |
|
190 | answer.size() == 1 ) |
|
191 | { |
|
192 | 4566 | Object first = answer.get(0); |
193 | ||
194 | 4566 | if ( first instanceof String |
195 | || |
|
196 | first instanceof Number |
|
197 | || |
|
198 | first instanceof Boolean ) |
|
199 | { |
|
200 | 3762 | return first; |
201 | } |
|
202 | } |
|
203 | 822 | return answer; |
204 | } |
|
205 | ||
206 | /** Select all nodes that are selected by this XPath |
|
207 | * expression. If multiple nodes match, multiple nodes |
|
208 | * will be returned. Nodes will be returned |
|
209 | * in document-order, as defined by the XPath |
|
210 | * specification. If the expression selects a non-node-set |
|
211 | * (i.e. a number, boolean, or string) then a List |
|
212 | * containing just that one object is returned. |
|
213 | * </p> |
|
214 | * |
|
215 | * @param node the node, node-set or Context object for evaluation. |
|
216 | * This value can be null. |
|
217 | * |
|
218 | * @return the node-set of all items selected |
|
219 | * by this XPath expression |
|
220 | * @throws JaxenException if an XPath error occurs during expression evaluation |
|
221 | * |
|
222 | * @see #selectNodesForContext |
|
223 | */ |
|
224 | public List selectNodes(Object node) throws JaxenException |
|
225 | { |
|
226 | 10236 | Context context = getContext( node ); |
227 | 10236 | return selectNodesForContext( context ); |
228 | } |
|
229 | ||
230 | /** Select only the first node selected by this XPath |
|
231 | * expression. If multiple nodes match, only one node will be |
|
232 | * returned. The selected node will be the first |
|
233 | * selected node in document-order, as defined by the XPath |
|
234 | * specification. |
|
235 | * </p> |
|
236 | * |
|
237 | * @param node the node, node-set or Context object for evaluation. |
|
238 | * This value can be null. |
|
239 | * |
|
240 | * @return the node-set of all items selected |
|
241 | * by this XPath expression |
|
242 | * @throws JaxenException if an XPath error occurs during expression evaluation |
|
243 | * |
|
244 | * @see #selectNodes |
|
245 | */ |
|
246 | public Object selectSingleNode(Object node) throws JaxenException |
|
247 | { |
|
248 | 12 | List results = selectNodes( node ); |
249 | ||
250 | 12 | if ( results.isEmpty() ) |
251 | { |
|
252 | 6 | return null; |
253 | } |
|
254 | ||
255 | 6 | return results.get( 0 ); |
256 | } |
|
257 | ||
258 | /** |
|
259 | * Returns the XPath string-value of the argument node. |
|
260 | * |
|
261 | * @param node the node whose value to take |
|
262 | * @return the XPath string value of this node |
|
263 | * @throws JaxenException if an XPath error occurs during expression evaluation |
|
264 | * @deprecated replaced by {@link #stringValueOf} |
|
265 | */ |
|
266 | public String valueOf(Object node) throws JaxenException |
|
267 | { |
|
268 | 0 | return stringValueOf( node ); |
269 | } |
|
270 | ||
271 | /** Retrieves the string-value of the result of |
|
272 | * evaluating this XPath expression when evaluated |
|
273 | * against the specified context. |
|
274 | * |
|
275 | * <p> |
|
276 | * The string-value of the expression is determined per |
|
277 | * the <code>string(..)</code> core function defined |
|
278 | * in the XPath specification. This means that an expression |
|
279 | * that selects zero nodes will return the empty string, |
|
280 | * while an expression that selects one-or-more nodes will |
|
281 | * return the string-value of the first node. |
|
282 | * </p> |
|
283 | * |
|
284 | * @param node the node, node-set or Context object for evaluation. This value can be null. |
|
285 | * |
|
286 | * @return the string-value of the result of evaluating this expression with the specified context node |
|
287 | * @throws JaxenException if an XPath error occurs during expression evaluation |
|
288 | */ |
|
289 | public String stringValueOf(Object node) throws JaxenException |
|
290 | { |
|
291 | 18 | Context context = getContext( node ); |
292 | ||
293 | 18 | Object result = selectSingleNodeForContext( context ); |
294 | ||
295 | 18 | if ( result == null ) |
296 | { |
|
297 | 6 | return ""; |
298 | } |
|
299 | ||
300 | 12 | return StringFunction.evaluate( result, |
301 | context.getNavigator() ); |
|
302 | } |
|
303 | ||
304 | /** Retrieve a boolean-value interpretation of this XPath |
|
305 | * expression when evaluated against a given context. |
|
306 | * |
|
307 | * <p> |
|
308 | * The boolean-value of the expression is determined per |
|
309 | * the <code>boolean(..)</code> function defined |
|
310 | * in the XPath specification. This means that an expression |
|
311 | * that selects zero nodes will return <code>false</code>, |
|
312 | * while an expression that selects one or more nodes will |
|
313 | * return <code>true</code>. |
|
314 | * </p> |
|
315 | * |
|
316 | * @param node the node, node-set or Context object for evaluation. This value can be null. |
|
317 | * |
|
318 | * @return the boolean-value of the result of evaluating this expression with the specified context node |
|
319 | * @throws JaxenException if an XPath error occurs during expression evaluation |
|
320 | */ |
|
321 | public boolean booleanValueOf(Object node) throws JaxenException |
|
322 | { |
|
323 | 24 | Context context = getContext( node ); |
324 | 24 | List result = selectNodesForContext( context ); |
325 | 24 | if ( result == null ) return false; |
326 | 24 | return BooleanFunction.evaluate( result, context.getNavigator() ).booleanValue(); |
327 | } |
|
328 | ||
329 | /** Retrieve a number-value interpretation of this XPath |
|
330 | * expression when evaluated against a given context. |
|
331 | * |
|
332 | * <p> |
|
333 | * The number-value of the expression is determined per |
|
334 | * the <code>number(..)</code> core function as defined |
|
335 | * in the XPath specification. This means that if this |
|
336 | * expression selects multiple nodes, the number-value |
|
337 | * of the first node is returned. |
|
338 | * </p> |
|
339 | * |
|
340 | * @param node the node, node-set or Context object for evaluation. This value can be null. |
|
341 | * |
|
342 | * @return a <code>Double</code> indicating the numeric value of |
|
343 | * evaluating this expression against the specified context |
|
344 | * @throws JaxenException if an XPath error occurs during expression evaluation |
|
345 | */ |
|
346 | public Number numberValueOf(Object node) throws JaxenException |
|
347 | { |
|
348 | 18 | Context context = getContext( node ); |
349 | 18 | Object result = selectSingleNodeForContext( context ); |
350 | 18 | return NumberFunction.evaluate( result, |
351 | context.getNavigator() ); |
|
352 | } |
|
353 | ||
354 | // Helpers |
|
355 | ||
356 | /** Add a namespace prefix-to-URI mapping for this XPath |
|
357 | * expression. |
|
358 | * |
|
359 | * <p> |
|
360 | * Namespace prefix-to-URI mappings in an XPath are independent |
|
361 | * of those used within any document. Only the mapping explicitly |
|
362 | * added to this XPath will be available for resolving the |
|
363 | * XPath expression. |
|
364 | * </p> |
|
365 | * |
|
366 | * <p> |
|
367 | * This is a convenience method for adding mappings to the |
|
368 | * default {@link NamespaceContext} in place for this XPath. |
|
369 | * If you have installed a custom <code>NamespaceContext</code> |
|
370 | * that is not a <code>SimpleNamespaceContext</code>, |
|
371 | * then this method will throw a <code>JaxenException</code>. |
|
372 | * </p> |
|
373 | * |
|
374 | * @param prefix the namespace prefix |
|
375 | * @param uri the namespace URI |
|
376 | * |
|
377 | * @throws JaxenException if the <code>NamespaceContext</code> |
|
378 | * used by this XPath is not a <code>SimpleNamespaceContext</code> |
|
379 | */ |
|
380 | public void addNamespace(String prefix, |
|
381 | String uri) throws JaxenException |
|
382 | { |
|
383 | 18 | NamespaceContext nsContext = getNamespaceContext(); |
384 | 18 | if ( nsContext instanceof SimpleNamespaceContext ) |
385 | { |
|
386 | 12 | ((SimpleNamespaceContext)nsContext).addNamespace( prefix, |
387 | uri ); |
|
388 | 12 | return; |
389 | } |
|
390 | ||
391 | 6 | throw new JaxenException("Operation not permitted while using a non-simple namespace context."); |
392 | } |
|
393 | ||
394 | ||
395 | // ------------------------------------------------------------ |
|
396 | // ------------------------------------------------------------ |
|
397 | // Properties |
|
398 | // ------------------------------------------------------------ |
|
399 | // ------------------------------------------------------------ |
|
400 | ||
401 | ||
402 | /** Set a <code>NamespaceContext</code> for use with this |
|
403 | * XPath expression. |
|
404 | * |
|
405 | * <p> |
|
406 | * A <code>NamespaceContext</code> is responsible for translating |
|
407 | * namespace prefixes within the expression into namespace URIs. |
|
408 | * </p> |
|
409 | * |
|
410 | * @param namespaceContext the <code>NamespaceContext</code> to |
|
411 | * install for this expression |
|
412 | * |
|
413 | * @see NamespaceContext |
|
414 | * @see NamespaceContext#translateNamespacePrefixToUri |
|
415 | */ |
|
416 | public void setNamespaceContext(NamespaceContext namespaceContext) |
|
417 | { |
|
418 | 192 | getContextSupport().setNamespaceContext(namespaceContext); |
419 | 192 | } |
420 | ||
421 | /** Set a <code>FunctionContext</code> for use with this XPath |
|
422 | * expression. |
|
423 | * |
|
424 | * <p> |
|
425 | * A <code>FunctionContext</code> is responsible for resolving |
|
426 | * all function calls used within the expression. |
|
427 | * </p> |
|
428 | * |
|
429 | * @param functionContext the <code>FunctionContext</code> to |
|
430 | * install for this expression |
|
431 | * |
|
432 | * @see FunctionContext |
|
433 | * @see FunctionContext#getFunction |
|
434 | */ |
|
435 | public void setFunctionContext(FunctionContext functionContext) |
|
436 | { |
|
437 | 174 | getContextSupport().setFunctionContext(functionContext); |
438 | 174 | } |
439 | ||
440 | /** Set a <code>VariableContext</code> for use with this XPath |
|
441 | * expression. |
|
442 | * |
|
443 | * <p> |
|
444 | * A <code>VariableContext</code> is responsible for resolving |
|
445 | * all variables referenced within the expression. |
|
446 | * </p> |
|
447 | * |
|
448 | * @param variableContext The <code>VariableContext</code> to |
|
449 | * install for this expression |
|
450 | * |
|
451 | * @see VariableContext |
|
452 | * @see VariableContext#getVariableValue |
|
453 | */ |
|
454 | public void setVariableContext(VariableContext variableContext) |
|
455 | { |
|
456 | 168 | getContextSupport().setVariableContext(variableContext); |
457 | 168 | } |
458 | ||
459 | /** Retrieve the <code>NamespaceContext</code> used by this XPath |
|
460 | * expression. |
|
461 | * |
|
462 | * <p> |
|
463 | * A <code>NamespaceContext</code> is responsible for mapping |
|
464 | * prefixes used within the expression to namespace URIs. |
|
465 | * </p> |
|
466 | * |
|
467 | * <p> |
|
468 | * If this XPath expression has not previously had a <code>NamespaceContext</code> |
|
469 | * installed, a new default <code>NamespaceContext</code> will be created, |
|
470 | * installed and returned. |
|
471 | * </p> |
|
472 | * |
|
473 | * @return the <code>NamespaceContext</code> used by this expression |
|
474 | * |
|
475 | * @see NamespaceContext |
|
476 | */ |
|
477 | public NamespaceContext getNamespaceContext() |
|
478 | { |
|
479 | 24 | return getContextSupport().getNamespaceContext(); |
480 | } |
|
481 | ||
482 | /** Retrieve the <code>FunctionContext</code> used by this XPath |
|
483 | * expression. |
|
484 | * |
|
485 | * <p> |
|
486 | * A <code>FunctionContext</code> is responsible for resolving |
|
487 | * all function calls used within the expression. |
|
488 | * </p> |
|
489 | * |
|
490 | * <p> |
|
491 | * If this XPath expression has not previously had a <code>FunctionContext</code> |
|
492 | * installed, a new default <code>FunctionContext</code> will be created, |
|
493 | * installed and returned. |
|
494 | * </p> |
|
495 | * |
|
496 | * @return the <code>FunctionContext</code> used by this expression |
|
497 | * |
|
498 | * @see FunctionContext |
|
499 | */ |
|
500 | public FunctionContext getFunctionContext() |
|
501 | { |
|
502 | 12 | return getContextSupport().getFunctionContext(); |
503 | } |
|
504 | ||
505 | /** Retrieve the <code>VariableContext</code> used by this XPath |
|
506 | * expression. |
|
507 | * |
|
508 | * <p> |
|
509 | * A <code>VariableContext</code> is responsible for resolving |
|
510 | * all variables referenced within the expression. |
|
511 | * </p> |
|
512 | * |
|
513 | * <p> |
|
514 | * If this XPath expression has not previously had a <code>VariableContext</code> |
|
515 | * installed, a new default <code>VariableContext</code> will be created, |
|
516 | * installed and returned. |
|
517 | * </p> |
|
518 | * |
|
519 | * @return the <code>VariableContext</code> used by this expression |
|
520 | * |
|
521 | * @see VariableContext |
|
522 | */ |
|
523 | public VariableContext getVariableContext() |
|
524 | { |
|
525 | 6 | return getContextSupport().getVariableContext(); |
526 | } |
|
527 | ||
528 | ||
529 | /** Retrieve the root expression of the internal |
|
530 | * compiled form of this XPath expression. |
|
531 | * |
|
532 | * <p> |
|
533 | * Internally, Jaxen maintains a form of Abstract Syntax |
|
534 | * Tree (AST) to represent the structure of the XPath expression. |
|
535 | * This is normally not required during normal consumer-grade |
|
536 | * usage of Jaxen. This method is provided for hard-core users |
|
537 | * who wish to manipulate or inspect a tree-based version of |
|
538 | * the expression. |
|
539 | * </p> |
|
540 | * |
|
541 | * @return the root of the AST of this expression |
|
542 | */ |
|
543 | public Expr getRootExpr() |
|
544 | { |
|
545 | 6 | return xpath.getRootExpr(); |
546 | } |
|
547 | ||
548 | /** Return the original expression text. |
|
549 | * |
|
550 | * @return the normalized XPath expression string |
|
551 | */ |
|
552 | public String toString() |
|
553 | { |
|
554 | 1488 | return this.exprText; |
555 | } |
|
556 | ||
557 | /** Returns a string representation of the parse tree. |
|
558 | * |
|
559 | * @return a string representation of the parse tree. |
|
560 | */ |
|
561 | public String debug() |
|
562 | { |
|
563 | 6 | return this.xpath.toString(); |
564 | } |
|
565 | ||
566 | // ------------------------------------------------------------ |
|
567 | // ------------------------------------------------------------ |
|
568 | // Implementation methods |
|
569 | // ------------------------------------------------------------ |
|
570 | // ------------------------------------------------------------ |
|
571 | ||
572 | ||
573 | /** Create a {@link Context} wrapper for the provided |
|
574 | * implementation-specific object. |
|
575 | * |
|
576 | * @param node the implementation-specific object |
|
577 | * to be used as the context |
|
578 | * |
|
579 | * @return a <code>Context</code> wrapper around the object |
|
580 | */ |
|
581 | protected Context getContext(Object node) |
|
582 | { |
|
583 | 10296 | if ( node instanceof Context ) |
584 | { |
|
585 | 7032 | return (Context) node; |
586 | } |
|
587 | ||
588 | 3264 | Context fullContext = new Context( getContextSupport() ); |
589 | ||
590 | 3264 | if ( node instanceof List ) |
591 | { |
|
592 | 6 | fullContext.setNodeSet( (List) node ); |
593 | } |
|
594 | else |
|
595 | { |
|
596 | 3258 | List list = new SingletonList(node); |
597 | 3258 | fullContext.setNodeSet( list ); |
598 | } |
|
599 | ||
600 | 3264 | return fullContext; |
601 | } |
|
602 | ||
603 | /** Retrieve the {@link ContextSupport} aggregation of |
|
604 | * <code>NamespaceContext</code>, <code>FunctionContext</code>, |
|
605 | * <code>VariableContext</code>, and {@link Navigator}. |
|
606 | * |
|
607 | * @return aggregate <code>ContextSupport</code> for this |
|
608 | * XPath expression |
|
609 | */ |
|
610 | protected ContextSupport getContextSupport() |
|
611 | { |
|
612 | 3840 | if ( support == null ) |
613 | { |
|
614 | 3450 | support = new ContextSupport( |
615 | createNamespaceContext(), |
|
616 | createFunctionContext(), |
|
617 | createVariableContext(), |
|
618 | getNavigator() |
|
619 | ); |
|
620 | } |
|
621 | ||
622 | 3840 | return support; |
623 | } |
|
624 | ||
625 | /** Retrieve the XML object-model-specific {@link Navigator} |
|
626 | * for us in evaluating this XPath expression. |
|
627 | * |
|
628 | * @return the implementation-specific <code>Navigator</code> |
|
629 | */ |
|
630 | public Navigator getNavigator() |
|
631 | { |
|
632 | 3456 | return navigator; |
633 | } |
|
634 | ||
635 | ||
636 | ||
637 | // ------------------------------------------------------------ |
|
638 | // ------------------------------------------------------------ |
|
639 | // Factory methods for default contexts |
|
640 | // ------------------------------------------------------------ |
|
641 | // ------------------------------------------------------------ |
|
642 | ||
643 | /** Create a default <code>FunctionContext</code>. |
|
644 | * |
|
645 | * @return a default <code>FunctionContext</code> |
|
646 | */ |
|
647 | protected FunctionContext createFunctionContext() |
|
648 | { |
|
649 | 3450 | return XPathFunctionContext.getInstance(); |
650 | } |
|
651 | ||
652 | /** Create a default <code>NamespaceContext</code>. |
|
653 | * |
|
654 | * @return a default <code>NamespaceContext</code> instance |
|
655 | */ |
|
656 | protected NamespaceContext createNamespaceContext() |
|
657 | { |
|
658 | 3450 | return new SimpleNamespaceContext(); |
659 | } |
|
660 | ||
661 | /** Create a default <code>VariableContext</code>. |
|
662 | * |
|
663 | * @return a default <code>VariableContext</code> instance |
|
664 | */ |
|
665 | protected VariableContext createVariableContext() |
|
666 | { |
|
667 | 3450 | return new SimpleVariableContext(); |
668 | } |
|
669 | ||
670 | /** Select all nodes that match this XPath |
|
671 | * expression on the given Context object. |
|
672 | * If multiple nodes match, multiple nodes |
|
673 | * will be returned in document-order, as defined by the XPath |
|
674 | * specification. If the expression selects a non-node-set |
|
675 | * (i.e. a number, boolean, or string) then a List |
|
676 | * containing just that one object is returned. |
|
677 | * </p> |
|
678 | * |
|
679 | * @param context the Context which gets evaluated |
|
680 | * |
|
681 | * @return the node-set of all items selected |
|
682 | * by this XPath expression |
|
683 | * @throws JaxenException if an XPath error occurs during expression evaluation |
|
684 | * |
|
685 | */ |
|
686 | protected List selectNodesForContext(Context context) throws JaxenException |
|
687 | { |
|
688 | 10296 | List list = this.xpath.asList( context ); |
689 | 9930 | return list; |
690 | ||
691 | } |
|
692 | ||
693 | ||
694 | /** Return only the first node that is selected by this XPath |
|
695 | * expression. If multiple nodes match, only one node will be |
|
696 | * returned. The selected node will be the first |
|
697 | * selected node in document-order, as defined by the XPath |
|
698 | * specification. If the XPath expression selects a double, |
|
699 | * String, or boolean, then that object is returned. |
|
700 | * </p> |
|
701 | * |
|
702 | * @param context the Context against which this expression is evaluated |
|
703 | * |
|
704 | * @return the first node in document order of all nodes selected |
|
705 | * by this XPath expression |
|
706 | * @throws JaxenException if an XPath error occurs during expression evaluation |
|
707 | * |
|
708 | * @see #selectNodesForContext |
|
709 | */ |
|
710 | protected Object selectSingleNodeForContext(Context context) throws JaxenException |
|
711 | { |
|
712 | 36 | List results = selectNodesForContext( context ); |
713 | ||
714 | 36 | if ( results.isEmpty() ) |
715 | { |
|
716 | 12 | return null; |
717 | } |
|
718 | ||
719 | 24 | return results.get( 0 ); |
720 | } |
|
721 | ||
722 | } |