001: /*--
002:
003: $Id: JaxenXPath.java,v 1.2 2005/05/03 07:02:04 wittek Exp $
004:
005: Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
006: All rights reserved.
007:
008: Redistribution and use in source and binary forms, with or without
009: modification, are permitted provided that the following conditions
010: are met:
011:
012: 1. Redistributions of source code must retain the above copyright
013: notice, this list of conditions, and the following disclaimer.
014:
015: 2. Redistributions in binary form must reproduce the above copyright
016: notice, this list of conditions, and the disclaimer that follows
017: these conditions in the documentation and/or other materials
018: provided with the distribution.
019:
020: 3. The name "JDOM" must not be used to endorse or promote products
021: derived from this software without prior written permission. For
022: written permission, please contact <request_AT_jdom_DOT_org>.
023:
024: 4. Products derived from this software may not be called "JDOM", nor
025: may "JDOM" appear in their name, without prior written permission
026: from the JDOM Project Management <request_AT_jdom_DOT_org>.
027:
028: In addition, we request (but do not require) that you include in the
029: end-user documentation provided with the redistribution and/or in the
030: software itself an acknowledgement equivalent to the following:
031: "This product includes software developed by the
032: JDOM Project (http://www.jdom.org/)."
033: Alternatively, the acknowledgment may be graphical using the logos
034: available at http://www.jdom.org/images/logos.
035:
036: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
040: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: SUCH DAMAGE.
048:
049: This software consists of voluntary contributions made by many
050: individuals on behalf of the JDOM Project and was originally
051: created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
052: Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
053: on the JDOM Project, please see <http://www.jdom.org/>.
054:
055: */
056:
057: package org.jdom.xpath;
058:
059: import java.util.*;
060:
061: import org.jaxen.*;
062: import org.jaxen.jdom.*;
063: import org.jdom.*;
064:
065: /**
066: * A non-public concrete XPath implementation for Jaxen.
067: *
068: * @version $Revision: 1.2 $, $Date: 2005/05/03 07:02:04 $
069: * @author Laurent Bihanic
070: */
071: class JaxenXPath extends XPath { // package protected
072:
073: private static final String CVS_ID = "@(#) $RCSfile: JaxenXPath.java,v $ $Revision: 1.2 $ $Date: 2005/05/03 07:02:04 $ $Name: $";
074:
075: /**
076: * The compiled XPath object to select nodes. This attribute can
077: * not be made final as it needs to be set upon object
078: * deserialization.
079: */
080: private transient JDOMXPath xPath;
081:
082: /**
083: * The current context for XPath expression evaluation.
084: */
085: private Object currentContext;
086:
087: /**
088: * Creates a new XPath wrapper object, compiling the specified
089: * XPath expression.
090: *
091: * @param expr the XPath expression to wrap.
092: *
093: * @throws JDOMException if the XPath expression is invalid.
094: */
095: public JaxenXPath(String expr) throws JDOMException {
096: setXPath(expr);
097: }
098:
099: /**
100: * Evaluates the wrapped XPath expression and returns the list
101: * of selected items.
102: *
103: * @param context the node to use as context for evaluating
104: * the XPath expression.
105: *
106: * @return the list of selected items, which may be of types: {@link Element},
107: * {@link Attribute}, {@link Text}, {@link CDATA},
108: * {@link Comment}, {@link ProcessingInstruction}, Boolean,
109: * Double, or String.
110: *
111: * @throws JDOMException if the evaluation of the XPath
112: * expression on the specified context
113: * failed.
114: */
115: public List selectNodes(Object context) throws JDOMException {
116: try {
117: currentContext = context;
118:
119: return xPath.selectNodes(context);
120: } catch (JaxenException ex1) {
121: throw new JDOMException("XPath error while evaluating \""
122: + xPath.toString() + "\": " + ex1.getMessage(), ex1);
123: } finally {
124: currentContext = null;
125: }
126: }
127:
128: /**
129: * Evaluates the wrapped XPath expression and returns the first
130: * entry in the list of selected nodes (or atomics).
131: *
132: * @param context the node to use as context for evaluating
133: * the XPath expression.
134: *
135: * @return the first selected item, which may be of types: {@link Element},
136: * {@link Attribute}, {@link Text}, {@link CDATA},
137: * {@link Comment}, {@link ProcessingInstruction}, Boolean,
138: * Double, String, or <code>null</code> if no item was selected.
139: *
140: * @throws JDOMException if the evaluation of the XPath
141: * expression on the specified context
142: * failed.
143: */
144: public Object selectSingleNode(Object context) throws JDOMException {
145: try {
146: currentContext = context;
147:
148: return xPath.selectSingleNode(context);
149: } catch (JaxenException ex1) {
150: throw new JDOMException("XPath error while evaluating \""
151: + xPath.toString() + "\": " + ex1.getMessage(), ex1);
152: } finally {
153: currentContext = null;
154: }
155: }
156:
157: /**
158: * Returns the string value of the first node selected by applying
159: * the wrapped XPath expression to the given context.
160: *
161: * @param context the element to use as context for evaluating
162: * the XPath expression.
163: *
164: * @return the string value of the first node selected by applying
165: * the wrapped XPath expression to the given context.
166: *
167: * @throws JDOMException if the XPath expression is invalid or
168: * its evaluation on the specified context
169: * failed.
170: */
171: public String valueOf(Object context) throws JDOMException {
172: try {
173: currentContext = context;
174:
175: return xPath.stringValueOf(context);
176: } catch (JaxenException ex1) {
177: throw new JDOMException("XPath error while evaluating \""
178: + xPath.toString() + "\": " + ex1.getMessage(), ex1);
179: } finally {
180: currentContext = null;
181: }
182: }
183:
184: /**
185: * Returns the number value of the first item selected by applying
186: * the wrapped XPath expression to the given context.
187: *
188: * @param context the element to use as context for evaluating
189: * the XPath expression.
190: *
191: * @return the number value of the first item selected by applying
192: * the wrapped XPath expression to the given context,
193: * <code>null</code> if no node was selected or the
194: * special value {@link java.lang.Double#NaN}
195: * (NotElement-a-Number) if the selected value can not be
196: * converted into a number value.
197: *
198: * @throws JDOMException if the XPath expression is invalid or
199: * its evaluation on the specified context
200: * failed.
201: */
202: public Number numberValueOf(Object context) throws JDOMException {
203: try {
204: currentContext = context;
205:
206: return xPath.numberValueOf(context);
207: } catch (JaxenException ex1) {
208: throw new JDOMException("XPath error while evaluating \""
209: + xPath.toString() + "\": " + ex1.getMessage(), ex1);
210: } finally {
211: currentContext = null;
212: }
213: }
214:
215: /**
216: * Defines an XPath variable and sets its value.
217: *
218: * @param name the variable name.
219: * @param value the variable value.
220: *
221: * @throws IllegalArgumentException if <code>name</code> is not
222: * a valid XPath variable name
223: * or if the value type is not
224: * supported by the underlying
225: * implementation
226: */
227: public void setVariable(String name, Object value)
228: throws IllegalArgumentException {
229: Object o = xPath.getVariableContext();
230: if (o instanceof SimpleVariableContext) {
231: ((SimpleVariableContext) o).setVariableValue(null, name,
232: value);
233: }
234: }
235:
236: /**
237: * Adds a namespace definition to the list of namespaces known of
238: * this XPath expression.
239: * <p>
240: * <strong>Note</strong>: In XPath, there is no such thing as a
241: * 'default namespace'. The empty prefix <b>always</b> resolves
242: * to the empty namespace URI.</p>
243: *
244: * @param namespace the namespace.
245: */
246: public void addNamespace(Namespace namespace) {
247: try {
248: xPath.addNamespace(namespace.getPrefix(), namespace
249: .getURI());
250: } catch (JaxenException ex1) { /* Can't happen here. */
251: }
252: }
253:
254: /**
255: * Returns the wrapped XPath expression as a string.
256: *
257: * @return the wrapped XPath expression as a string.
258: */
259: public String getXPath() {
260: return (xPath.toString());
261: }
262:
263: /**
264: * Compiles and sets the XPath expression wrapped by this object.
265: *
266: * @param expr the XPath expression to wrap.
267: *
268: * @throws JDOMException if the XPath expression is invalid.
269: */
270: private void setXPath(String expr) throws JDOMException {
271: try {
272: xPath = new JDOMXPath(expr);
273: xPath.setNamespaceContext(new NSContext());
274: } catch (Exception ex1) {
275: throw new JDOMException("Invalid XPath expression: \""
276: + expr + "\"", ex1);
277: }
278: }
279:
280: public String toString() {
281: return (xPath.toString());
282: }
283:
284: public boolean equals(Object o) {
285: if (o instanceof JaxenXPath) {
286: JaxenXPath x = (JaxenXPath) o;
287:
288: return (super .equals(o) && xPath.toString().equals(
289: x.xPath.toString()));
290: }
291: return false;
292: }
293:
294: public int hashCode() {
295: return xPath.hashCode();
296: }
297:
298: private class NSContext extends SimpleNamespaceContext {
299: public NSContext() {
300: super ();
301: }
302:
303: /**
304: * <i>[Jaxen NamespaceContext interface support]</i> Translates
305: * the provided namespace prefix into the matching bound
306: * namespace URI.
307: *
308: * @param prefix the namespace prefix to resolve.
309: *
310: * @return the namespace URI matching the prefix.
311: */
312: public String translateNamespacePrefixToUri(String prefix) {
313: if ((prefix == null) || (prefix.length() == 0)) {
314: return null;
315: }
316:
317: String uri = super .translateNamespacePrefixToUri(prefix);
318: if (uri == null) {
319: Object ctx = currentContext;
320: if (ctx != null) {
321: Element elt = null;
322:
323: // Get closer element node
324: if (ctx instanceof Element) {
325: elt = (Element) ctx;
326: } else if (ctx instanceof Attribute) {
327: elt = ((Attribute) ctx).getParent();
328: } else if (ctx instanceof Content) {
329: elt = ((Content) ctx).getParentElement();
330: } else if (ctx instanceof Document) {
331: elt = ((Document) ctx).getRootElement();
332: }
333:
334: if (elt != null) {
335: Namespace ns = elt.getNamespace(prefix);
336: if (ns != null) {
337: uri = ns.getURI();
338: }
339: }
340: }
341: }
342: return uri;
343: }
344: }
345: }
|