dom4j - 1.6.1

Clover coverage report - dom4j - 1.6.1
Coverage timestamp: ma mei 16 2005 14:23:01 GMT+01:00
FRAMES NO FRAMES

file stats: | LOC: | 413 |  | Methods: | 29
| NCLOC: | 229 |  | Classes: | 1

Source file | Conditionals | Statements | Methods | TOTAL

DefaultXPath.java

61,8%

69,7%

72,4%

68,6%

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;
11 |  | import java.util.Collections;
12 |  | import java.util.Comparator;
13 |  | import java.util.HashMap;
14 |  | import java.util.HashSet;
15 |  | import java.util.Iterator;
16 |  | import java.util.List;
17 |  | import java.util.Map;
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 {
42 |  | private String 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 | 592 | public DefaultXPath(String text) throws InvalidXPathException {
58 | 592 | this.text = text;
59 | 592 | this.xpath = parse(text);
60 |  | }
61 |  |
62 | 11 | public String toString() {
63 | 11 | 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 | 0 | public String getText() {
74 | 0 | return text;
75 |  | }
76 |  |
77 | 0 | public FunctionContext getFunctionContext() {
78 | 0 | return xpath.getFunctionContext();
79 |  | }
80 |  |
81 | 0 | public void setFunctionContext(FunctionContext functionContext) {
82 | 0 | xpath.setFunctionContext(functionContext);
83 |  | }
84 |  |
85 | 0 | public NamespaceContext getNamespaceContext() {
86 | 0 | return namespaceContext;
87 |  | }
88 |  |
89 | 4 | public void setNamespaceURIs(Map map) {
90 | 4 | setNamespaceContext(new SimpleNamespaceContext(map));
91 |  | }
92 |  |
93 | 8 | public void setNamespaceContext(NamespaceContext namespaceContext) {
94 | 8 | this.namespaceContext = namespaceContext;
95 | 8 | xpath.setNamespaceContext(namespaceContext);
96 |  | }
97 |  |
98 | 0 | public VariableContext getVariableContext() {
99 | 0 | return xpath.getVariableContext();
100 |  | }
101 |  |
102 | 7 | public void setVariableContext(VariableContext variableContext) {
103 | 7 | xpath.setVariableContext(variableContext);
104 |  | }
105 |  |
106 | 7 | public Object evaluate(Object context) {
107 | 7 | try {
108 | 7 | setNSContext(context);
109 |  |
110 | 7 | List answer = xpath.selectNodes(context);
111 |  |
112 | 7 | if ((answer != null) && (answer.size() == 1)) {
113 | 6 | return answer.get(0);
114 |  | }
115 |  |
116 | 1 | return answer;
117 |  | } catch (JaxenException e) {
118 | 0 | handleJaxenException(e);
119 |  |
120 | 0 | return null;
121 |  | }
122 |  | }
123 |  |
124 | 0 | public Object selectObject(Object context) {
125 | 0 | return evaluate(context);
126 |  | }
127 |  |
128 | 289 | public List selectNodes(Object context) {
129 | 289 | try {
130 | 289 | setNSContext(context);
131 |  |
132 | 289 | return xpath.selectNodes(context);
133 |  | } catch (JaxenException e) {
134 | 1 | handleJaxenException(e);
135 |  |
136 | 0 | return Collections.EMPTY_LIST;
137 |  | }
138 |  | }
139 |  |
140 | 0 | public List selectNodes(Object context, org.dom4j.XPath sortXPath) {
141 | 0 | List answer = selectNodes(context);
142 | 0 | sortXPath.sort(answer);
143 |  |
144 | 0 | return answer;
145 |  | }
146 |  |
147 | 2 | public List selectNodes(Object context, org.dom4j.XPath sortXPath,
148 |  | boolean distinct) {
149 | 2 | List answer = selectNodes(context);
150 | 2 | sortXPath.sort(answer, distinct);
151 |  |
152 | 2 | return answer;
153 |  | }
154 |  |
155 | 71 | public Node selectSingleNode(Object context) {
156 | 71 | try {
157 | 71 | setNSContext(context);
158 |  |
159 | 71 | Object answer = xpath.selectSingleNode(context);
160 |  |
161 | 71 | if (answer instanceof Node) {
162 | 71 | return (Node) answer;
163 |  | }
164 |  |
165 | 0 | if (answer == null) {
166 | 0 | return null;
167 |  | }
168 |  |
169 | 0 | 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 | 0 | handleJaxenException(e);
174 |  |
175 | 0 | return null;
176 |  | }
177 |  | }
178 |  |
179 | 2151 | public String valueOf(Object context) {
180 | 2151 | try {
181 | 2151 | setNSContext(context);
182 |  |
183 | 2151 | return xpath.stringValueOf(context);
184 |  | } catch (JaxenException e) {
185 | 0 | handleJaxenException(e);
186 |  |
187 | 0 | return "";
188 |  | }
189 |  | }
190 |  |
191 | 38 | public Number numberValueOf(Object context) {
192 | 38 | try {
193 | 38 | setNSContext(context);
194 |  |
195 | 38 | return xpath.numberValueOf(context);
196 |  | } catch (JaxenException e) {
197 | 0 | handleJaxenException(e);
198 |  |
199 | 0 | return null;
200 |  | }
201 |  | }
202 |  |
203 | 2 | public boolean booleanValueOf(Object context) {
204 | 2 | try {
205 | 2 | setNSContext(context);
206 |  |
207 | 2 | return xpath.booleanValueOf(context);
208 |  | } catch (JaxenException e) {
209 | 0 | handleJaxenException(e);
210 |  |
211 | 0 | 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 | 0 | public void sort(List list) {
225 | 0 | 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 | 2 | public void sort(List list, boolean distinct) {
241 | 2 | if ((list != null) && !list.isEmpty()) {
242 | 2 | int size = list.size();
243 | 2 | HashMap sortValues = new HashMap(size);
244 |  |
245 | 2 | for (int i = 0; i < size; i++) {
246 | 1958 | Object object = list.get(i);
247 |  |
248 | 1958 | if (object instanceof Node) {
249 | 1958 | Node node = (Node) object;
250 | 1958 | Object expression = getCompareValue(node);
251 | 1958 | sortValues.put(node, expression);
252 |  | }
253 |  | }
254 |  |
255 | 2 | sort(list, sortValues);
256 |  |
257 | 2 | if (distinct) {
258 | 1 | removeDuplicates(list, sortValues);
259 |  | }
260 |  | }
261 |  | }
262 |  |
263 | 12 | public boolean matches(Node node) {
264 | 12 | try {
265 | 12 | setNSContext(node);
266 |  |
267 | 12 | List answer = xpath.selectNodes(node);
268 |  |
269 | 12 | if ((answer != null) && (answer.size() > 0)) {
270 | 6 | Object item = answer.get(0);
271 |  |
272 | 6 | if (item instanceof Boolean) {
273 | 0 | return ((Boolean) item).booleanValue();
274 |  | }
275 |  |
276 | 6 | return answer.contains(node);
277 |  | }
278 |  |
279 | 6 | return false;
280 |  | } catch (JaxenException e) {
281 | 0 | handleJaxenException(e);
282 |  |
283 | 0 | 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 | 2 | protected void sort(List list, final Map sortValues) {
296 | 2 | Collections.sort(list, new Comparator() {
297 | 9366 | public int compare(Object o1, Object o2) {
298 | 9366 | o1 = sortValues.get(o1);
299 | 9366 | o2 = sortValues.get(o2);
300 |  |
301 | 9366 | if (o1 == o2) {
302 | 978 | return 0;
303 | 8388 | } else if (o1 instanceof Comparable) {
304 | 8388 | Comparable c1 = (Comparable) o1;
305 |  |
306 | 8388 | return c1.compareTo(o2);
307 | 0 | } else if (o1 == null) {
308 | 0 | return 1;
309 | 0 | } else if (o2 == null) {
310 | 0 | return -1;
311 |  | } else {
312 | 0 | 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 | 1 | protected void removeDuplicates(List list, Map sortValues) {
329 |  | // remove distinct
330 | 1 | HashSet distinctValues = new HashSet();
331 |  |
332 | 1 | for (Iterator iter = list.iterator(); iter.hasNext();) {
333 | 979 | Object node = iter.next();
334 | 979 | Object value = sortValues.get(node);
335 |  |
336 | 979 | if (distinctValues.contains(value)) {
337 | 956 | iter.remove();
338 |  | } else {
339 | 23 | 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 | 1958 | protected Object getCompareValue(Node node) {
353 | 1958 | return valueOf(node);
354 |  | }
355 |  |
356 | 592 | protected static XPath parse(String text) {
357 | 592 | try {
358 | 592 | return new Dom4jXPath(text);
359 |  | } catch (JaxenException e) {
360 | 4 | throw new InvalidXPathException(text, e.getMessage());
361 |  | } catch (Throwable t) {
362 | 0 | throw new InvalidXPathException(text, t);
363 |  | }
364 |  | }
365 |  |
366 | 2570 | protected void setNSContext(Object context) {
367 | 2570 | if (namespaceContext == null) {
368 | 2561 | xpath.setNamespaceContext(DefaultNamespaceContext.create(context));
369 |  | }
370 |  | }
371 |  |
372 | 1 | protected void handleJaxenException(JaxenException exception)
373 |  | throws XPathException {
374 | 1 | 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 |  | */