1 /*
2 * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/function/BooleanFunction.java,v 1.15 2005/06/26 16:07:22 elharo Exp $
3 * $Revision: 1.15 $
4 * $Date: 2005/06/26 16:07:22 $
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: BooleanFunction.java,v 1.15 2005/06/26 16:07:22 elharo Exp $
60 */
61
62
63 package org.jaxen.function;
64
65 import java.util.List;
66
67 import org.jaxen.Context;
68 import org.jaxen.Function;
69 import org.jaxen.FunctionCallException;
70 import org.jaxen.Navigator;
71
72 /***
73 * <p>
74 * <b>4.3</b> <code><i>boolean</i> boolean(<i>object</i>)</code>
75 * </p>
76 *
77 * <blockquote
78 * src="http://www.w3.org/TR/xpath#section-Boolean-Functions">
79 * <p>
80 * The <b><a href="http://www.w3.org/TR/xpath#function-boolean" target="_top">boolean</a></b>
81 * function converts its argument to a boolean as follows:
82 * </p>
83 *
84 * <ul>
85 *
86 * <li>
87 * <p>
88 * a number is true if and only if it is neither positive or negative
89 * zero nor NaN
90 * </p>
91 * </li>
92 *
93 * <li>
94 * <p>
95 * a node-set is true if and only if it is non-empty
96 * </p>
97 * </li>
98 *
99 * <li>
100 * <p>
101 * a string is true if and only if its length is non-zero
102 * </p>
103 * </li>
104 *
105 * <li>
106 *
107 * <p>
108 * an object of a type other than the four basic types is converted to a
109 * boolean in a way that is dependent on that type
110 * </p></li></ul>
111 * </blockquote>
112 *
113 * @author bob mcwhirter (bob @ werken.com)
114 * @see <a href="http://www.w3.org/TR/xpath#function-boolean">Section 4.3 of the XPath Specification</a>
115 */
116 public class BooleanFunction implements Function
117 {
118
119
120 /***
121 * Create a new <code>BooleanFunction</code> object.
122 */
123 public BooleanFunction() {}
124
125 /*** Convert the argument to a <code>Boolean</code>
126 *
127 * @param context the context at the point in the
128 * expression when the function is called
129 * @param args a list with exactly one item which will be converted to a
130 * <code>Boolean</code>
131 *
132 * @return the result of evaluating the function;
133 * <code>Boolean.TRUE</code> or <code>Boolean.FALSE</code>
134 *
135 * @throws FunctionCallException if <code>args</code> has more or less than one item
136 */
137 public Object call(Context context,
138 List args) throws FunctionCallException
139 {
140 if ( args.size() == 1 )
141 {
142 return evaluate( args.get(0), context.getNavigator() );
143 }
144
145 throw new FunctionCallException("boolean() requires one argument");
146 }
147
148 /***
149 * <p>Convert the argument <code>obj</code> to a <code>Boolean</code>
150 * according to the following rules:</p>
151 *
152 * <ul>
153 * <li>Lists are false if they're empty; true if they're not.</li>
154 * <li>Booleans are false if they're false; true if they're true.</li>
155 * <li>Strings are false if they're empty; true if they're not.</li>
156 * <li>Numbers are false if they're 0 or NaN; true if they're not.</li>
157 * <li>All other objects are true.</li>
158 * </ul>
159 *
160 * @param obj the object to convert to a boolean
161 * @param nav ignored
162 *
163 * @return <code>Boolean.TRUE</code> or <code>Boolean.FALSE</code>
164 */
165 public static Boolean evaluate(Object obj, Navigator nav)
166 {
167 if ( obj instanceof List )
168 {
169 List list = (List) obj;
170
171 // if it's an empty list, then we have a null node-set -> false
172 if (list.size() == 0)
173 {
174 return Boolean.FALSE;
175 }
176
177 // otherwise, unwrap the list and check the primitive
178 obj = list.get(0);
179 }
180
181 // now check for primitive types
182 // otherwise a non-empty node-set is true
183
184 // if it's a Boolean, let it decide
185 if ( obj instanceof Boolean )
186 {
187 return (Boolean) obj;
188 }
189 // if it's a Number, != 0 -> true
190 else if ( obj instanceof Number )
191 {
192 double d = ((Number) obj).doubleValue();
193 if ( d == 0 || Double.isNaN(d) )
194 {
195 return Boolean.FALSE;
196 }
197 return Boolean.TRUE;
198 }
199 // if it's a String, "" -> false
200 else if ( obj instanceof String )
201 {
202 return ( ((String)obj).length() > 0
203 ? Boolean.TRUE
204 : Boolean.FALSE );
205 }
206 else
207 {
208 // assume it's a node so that this node-set is non-empty
209 // and so it's true
210 return ( obj != null ) ? Boolean.TRUE : Boolean.FALSE;
211 }
212
213 }
214 }