KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dom4j > xpath > DefaultXPath


1 /*
2  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3  *
4  * This software is open source.
5  * See the bottom of this file for the licence.
6  */

7
8 package org.dom4j.xpath;
9
10 import java.io.Serializable JavaDoc;
11 import java.util.Collections JavaDoc;
12 import java.util.Comparator JavaDoc;
13 import java.util.HashMap JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Map JavaDoc;
18
19 import org.dom4j.InvalidXPathException;
20 import org.dom4j.Node;
21 import org.dom4j.NodeFilter;
22 import org.dom4j.XPathException;
23
24 import org.jaxen.FunctionContext;
25 import org.jaxen.JaxenException;
26 import org.jaxen.NamespaceContext;
27 import org.jaxen.SimpleNamespaceContext;
28 import org.jaxen.VariableContext;
29 import org.jaxen.XPath;
30 import org.jaxen.dom4j.Dom4jXPath;
31
32 /**
33  * <p>
34  * Default implementation of {@link org.dom4j.XPath}which uses the <a
35  * HREF="http://jaxen.org">Jaxen </a> project.
36  * </p>
37  *
38  * @author bob mcwhirter
39  * @author <a HREF="mailto:jstrachan@apache.org">James Strachan </a>
40  */

41 public class DefaultXPath implements org.dom4j.XPath, NodeFilter, Serializable JavaDoc {
42     private String JavaDoc text;
43
44     private XPath xpath;
45
46     private NamespaceContext namespaceContext;
47
48     /**
49      * Construct an XPath
50      *
51      * @param text
52      * DOCUMENT ME!
53      *
54      * @throws InvalidXPathException
55      * DOCUMENT ME!
56      */

57     public DefaultXPath(String JavaDoc text) throws InvalidXPathException {
58         this.text = text;
59         this.xpath = parse(text);
60     }
61
62     public String JavaDoc toString() {
63         return "[XPath: " + xpath + "]";
64     }
65
66     // XPath interface
67

68     /**
69      * Retrieve the textual XPath string used to initialize this Object
70      *
71      * @return The XPath string
72      */

73     public String JavaDoc getText() {
74         return text;
75     }
76
77     public FunctionContext getFunctionContext() {
78         return xpath.getFunctionContext();
79     }
80
81     public void setFunctionContext(FunctionContext functionContext) {
82         xpath.setFunctionContext(functionContext);
83     }
84
85     public NamespaceContext getNamespaceContext() {
86         return namespaceContext;
87     }
88
89     public void setNamespaceURIs(Map JavaDoc map) {
90         setNamespaceContext(new SimpleNamespaceContext(map));
91     }
92
93     public void setNamespaceContext(NamespaceContext namespaceContext) {
94         this.namespaceContext = namespaceContext;
95         xpath.setNamespaceContext(namespaceContext);
96     }
97
98     public VariableContext getVariableContext() {
99         return xpath.getVariableContext();
100     }
101
102     public void setVariableContext(VariableContext variableContext) {
103         xpath.setVariableContext(variableContext);
104     }
105
106     public Object JavaDoc evaluate(Object JavaDoc context) {
107         try {
108             setNSContext(context);
109
110             List JavaDoc answer = xpath.selectNodes(context);
111
112             if ((answer != null) && (answer.size() == 1)) {
113                 return answer.get(0);
114             }
115
116             return answer;
117         } catch (JaxenException e) {
118             handleJaxenException(e);
119
120             return null;
121         }
122     }
123
124     public Object JavaDoc selectObject(Object JavaDoc context) {
125         return evaluate(context);
126     }
127
128     public List JavaDoc selectNodes(Object JavaDoc context) {
129         try {
130             setNSContext(context);
131
132             return xpath.selectNodes(context);
133         } catch (JaxenException e) {
134             handleJaxenException(e);
135
136             return Collections.EMPTY_LIST;
137         }
138     }
139
140     public List JavaDoc selectNodes(Object JavaDoc context, org.dom4j.XPath sortXPath) {
141         List JavaDoc answer = selectNodes(context);
142         sortXPath.sort(answer);
143
144         return answer;
145     }
146
147     public List JavaDoc selectNodes(Object JavaDoc context, org.dom4j.XPath sortXPath,
148             boolean distinct) {
149         List JavaDoc answer = selectNodes(context);
150         sortXPath.sort(answer, distinct);
151
152         return answer;
153     }
154
155     public Node selectSingleNode(Object JavaDoc context) {
156         try {
157             setNSContext(context);
158
159             Object JavaDoc answer = xpath.selectSingleNode(context);
160
161             if (answer instanceof Node) {
162                 return (Node) answer;
163             }
164
165             if (answer == null) {
166                 return null;
167             }
168
169             throw new XPathException("The result of the XPath expression is "
170                     + "not a Node. It was: " + answer + " of type: "
171                     + answer.getClass().getName());
172         } catch (JaxenException e) {
173             handleJaxenException(e);
174
175             return null;
176         }
177     }
178
179     public String JavaDoc valueOf(Object JavaDoc context) {
180         try {
181             setNSContext(context);
182
183             return xpath.stringValueOf(context);
184         } catch (JaxenException e) {
185             handleJaxenException(e);
186
187             return "";
188         }
189     }
190
191     public Number JavaDoc numberValueOf(Object JavaDoc context) {
192         try {
193             setNSContext(context);
194
195             return xpath.numberValueOf(context);
196         } catch (JaxenException e) {
197             handleJaxenException(e);
198
199             return null;
200         }
201     }
202
203     public boolean booleanValueOf(Object JavaDoc context) {
204         try {
205             setNSContext(context);
206
207             return xpath.booleanValueOf(context);
208         } catch (JaxenException e) {
209             handleJaxenException(e);
210
211             return false;
212         }
213     }
214
215     /**
216      * <p>
217      * <code>sort</code> sorts the given List of Nodes using this XPath
218      * expression as a {@link Comparator}.
219      * </p>
220      *
221      * @param list
222      * is the list of Nodes to sort
223      */

224     public void sort(List JavaDoc list) {
225         sort(list, false);
226     }
227
228     /**
229      * <p>
230      * <code>sort</code> sorts the given List of Nodes using this XPath
231      * expression as a {@link Comparator}and optionally removing duplicates.
232      * </p>
233      *
234      * @param list
235      * is the list of Nodes to sort
236      * @param distinct
237      * if true then duplicate values (using the sortXPath for
238      * comparisions) will be removed from the List
239      */

240     public void sort(List JavaDoc list, boolean distinct) {
241         if ((list != null) && !list.isEmpty()) {
242             int size = list.size();
243             HashMap JavaDoc sortValues = new HashMap JavaDoc(size);
244
245             for (int i = 0; i < size; i++) {
246                 Object JavaDoc object = list.get(i);
247
248                 if (object instanceof Node) {
249                     Node node = (Node) object;
250                     Object JavaDoc expression = getCompareValue(node);
251                     sortValues.put(node, expression);
252                 }
253             }
254
255             sort(list, sortValues);
256
257             if (distinct) {
258                 removeDuplicates(list, sortValues);
259             }
260         }
261     }
262
263     public boolean matches(Node node) {
264         try {
265             setNSContext(node);
266
267             List JavaDoc answer = xpath.selectNodes(node);
268
269             if ((answer != null) && (answer.size() > 0)) {
270                 Object JavaDoc item = answer.get(0);
271
272                 if (item instanceof Boolean JavaDoc) {
273                     return ((Boolean JavaDoc) item).booleanValue();
274                 }
275
276                 return answer.contains(node);
277             }
278
279             return false;
280         } catch (JaxenException e) {
281             handleJaxenException(e);
282
283             return false;
284         }
285     }
286
287     /**
288      * Sorts the list based on the sortValues for each node
289      *
290      * @param list
291      * DOCUMENT ME!
292      * @param sortValues
293      * DOCUMENT ME!
294      */

295     protected void sort(List JavaDoc list, final Map JavaDoc sortValues) {
296         Collections.sort(list, new Comparator JavaDoc() {
297             public int compare(Object JavaDoc o1, Object JavaDoc o2) {
298                 o1 = sortValues.get(o1);
299                 o2 = sortValues.get(o2);
300
301                 if (o1 == o2) {
302                     return 0;
303                 } else if (o1 instanceof Comparable JavaDoc) {
304                     Comparable JavaDoc c1 = (Comparable JavaDoc) o1;
305
306                     return c1.compareTo(o2);
307                 } else if (o1 == null) {
308                     return 1;
309                 } else if (o2 == null) {
310                     return -1;
311                 } else {
312                     return o1.equals(o2) ? 0 : (-1);
313                 }
314             }
315         });
316     }
317
318     // Implementation methods
319

320     /**
321      * Removes items from the list which have duplicate values
322      *
323      * @param list
324      * DOCUMENT ME!
325      * @param sortValues
326      * DOCUMENT ME!
327      */

328     protected void removeDuplicates(List JavaDoc list, Map JavaDoc sortValues) {
329         // remove distinct
330
HashSet JavaDoc distinctValues = new HashSet JavaDoc();
331
332         for (Iterator JavaDoc iter = list.iterator(); iter.hasNext();) {
333             Object JavaDoc node = iter.next();
334             Object JavaDoc value = sortValues.get(node);
335
336             if (distinctValues.contains(value)) {
337                 iter.remove();
338             } else {
339                 distinctValues.add(value);
340             }
341         }
342     }
343
344     /**
345      * DOCUMENT ME!
346      *
347      * @param node
348      * DOCUMENT ME!
349      *
350      * @return the node expression used for sorting comparisons
351      */

352     protected Object JavaDoc getCompareValue(Node node) {
353         return valueOf(node);
354     }
355
356     protected static XPath parse(String JavaDoc text) {
357         try {
358             return new Dom4jXPath(text);
359         } catch (JaxenException e) {
360             throw new InvalidXPathException(text, e.getMessage());
361         } catch (Throwable JavaDoc t) {
362             throw new InvalidXPathException(text, t);
363         }
364     }
365
366     protected void setNSContext(Object JavaDoc context) {
367         if (namespaceContext == null) {
368             xpath.setNamespaceContext(DefaultNamespaceContext.create(context));
369         }
370     }
371
372     protected void handleJaxenException(JaxenException exception)
373             throws XPathException {
374         throw new XPathException(text, exception);
375     }
376 }
377
378 /*
379  * Redistribution and use of this software and associated documentation
380  * ("Software"), with or without modification, are permitted provided that the
381  * following conditions are met:
382  *
383  * 1. Redistributions of source code must retain copyright statements and
384  * notices. Redistributions must also contain a copy of this document.
385  *
386  * 2. Redistributions in binary form must reproduce the above copyright notice,
387  * this list of conditions and the following disclaimer in the documentation
388  * and/or other materials provided with the distribution.
389  *
390  * 3. The name "DOM4J" must not be used to endorse or promote products derived
391  * from this Software without prior written permission of MetaStuff, Ltd. For
392  * written permission, please contact dom4j-info@metastuff.com.
393  *
394  * 4. Products derived from this Software may not be called "DOM4J" nor may
395  * "DOM4J" appear in their names without prior written permission of MetaStuff,
396  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
397  *
398  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
399  *
400  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
401  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
402  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
403  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
404  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
405  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
406  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
407  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
408  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
409  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
410  * POSSIBILITY OF SUCH DAMAGE.
411  *
412  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
413  */

414
Popular Tags