View Javadoc

1   /*
2    * $Header: /home/projects/jaxen/scm/jaxen/src/java/main/org/jaxen/function/BooleanFunction.java,v 1.17 2006/02/05 21:47:41 elharo Exp $
3    * $Revision: 1.17 $
4    * $Date: 2006/02/05 21:47:41 $
5    *
6    * ====================================================================
7    *
8    * Copyright 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 are
13   * met:
14   * 
15   *   * Redistributions of source code must retain the above copyright
16   *     notice, this list of conditions and the following disclaimer.
17   * 
18   *   * Redistributions in binary form must reproduce the above copyright
19   *     notice, this list of conditions and the following disclaimer in the
20   *     documentation and/or other materials provided with the distribution.
21   * 
22   *   * Neither the name of the Jaxen Project nor the names of its
23   *     contributors may be used to endorse or promote products derived 
24   *     from this software without specific prior written permission.
25   * 
26   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
27   * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
29   * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
30   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   *
38   * ====================================================================
39   * This software consists of voluntary contributions made by many 
40   * individuals on behalf of the Jaxen Project and was originally 
41   * created by bob mcwhirter <bob@werken.com> and 
42   * James Strachan <jstrachan@apache.org>.  For more information on the 
43   * Jaxen Project, please see <http://www.jaxen.org/>.
44   * 
45   * $Id: BooleanFunction.java,v 1.17 2006/02/05 21:47:41 elharo Exp $
46   */
47  
48  
49  package org.jaxen.function;
50  
51  import java.util.List;
52  
53  import org.jaxen.Context;
54  import org.jaxen.Function;
55  import org.jaxen.FunctionCallException;
56  import org.jaxen.Navigator;
57  
58  /***
59   * <p>
60   * <b>4.3</b> <code><i>boolean</i> boolean(<i>object</i>)</code>
61   * </p>
62   * 
63   * <blockquote
64   * src="http://www.w3.org/TR/xpath#section-Boolean-Functions">
65   * <p>
66   * The <b><a href="http://www.w3.org/TR/xpath#function-boolean" target="_top">boolean</a></b>
67   * function converts its argument to a boolean as follows:
68   * </p>
69   * 
70   * <ul>
71   * 
72   * <li>
73   * <p>
74   * a number is true if and only if it is neither positive or negative
75   * zero nor NaN
76   * </p>
77   * </li>
78   * 
79   * <li>
80   * <p>
81   * a node-set is true if and only if it is non-empty
82   * </p>
83   * </li>
84   * 
85   * <li>
86   * <p>
87   * a string is true if and only if its length is non-zero
88   * </p>
89   * </li>
90   * 
91   * <li>
92   * 
93   * <p>
94   * an object of a type other than the four basic types is converted to a
95   * boolean in a way that is dependent on that type
96   * </p></li></ul>
97   * </blockquote>
98   * 
99   * @author bob mcwhirter (bob @ werken.com)
100  * @see <a href="http://www.w3.org/TR/xpath#function-boolean">Section 4.3 of the XPath Specification</a>
101  */
102 public class BooleanFunction implements Function
103 {
104 
105 
106     /***
107      * Create a new <code>BooleanFunction</code> object.
108      */
109     public BooleanFunction() {}
110     
111     /*** Convert the argument to a <code>Boolean</code>
112      *
113      * @param context the context at the point in the
114      *         expression when the function is called
115      * @param args a list with exactly one item which will be converted to a 
116      *     <code>Boolean</code>
117      * 
118      * @return the result of evaluating the function; 
119      *     <code>Boolean.TRUE</code> or <code>Boolean.FALSE</code>
120      * 
121      * @throws FunctionCallException if <code>args</code> has more or less than one item
122      */
123     public Object call(Context context,
124                        List args) throws FunctionCallException
125     {
126         if ( args.size() == 1 )
127         {
128             return evaluate( args.get(0), context.getNavigator() );
129         }
130 
131         throw new FunctionCallException("boolean() requires one argument");
132     }
133 
134     /*** 
135      * <p>Convert the argument <code>obj</code> to a <code>Boolean</code> 
136      * according to the following rules:</p>
137      *
138      * <ul>
139      * <li>Lists are false if they're empty; true if they're not.</li>
140      * <li>Booleans are false if they're false; true if they're true.</li>
141      * <li>Strings are false if they're empty; true if they're not.</li>
142      * <li>Numbers are false if they're 0 or NaN; true if they're not.</li>
143      * <li>All other objects are true.</li>
144      * </ul>
145      * 
146      * @param obj the object to convert to a boolean
147      * @param nav ignored
148      * 
149      * @return <code>Boolean.TRUE</code> or <code>Boolean.FALSE</code>
150      */
151     public static Boolean evaluate(Object obj, Navigator nav)
152     {
153         if ( obj instanceof List )
154         {
155             List list = (List) obj;
156             
157             // if it's an empty list, then we have a null node-set -> false            
158             if (list.size() == 0)
159             {
160                 return Boolean.FALSE;
161             }
162      
163             // otherwise, unwrap the list and check the primitive
164             obj = list.get(0);
165         }
166         
167         // now check for primitive types
168         // otherwise a non-empty node-set is true
169 
170         // if it's a Boolean, let it decide
171         if ( obj instanceof Boolean )
172         {
173             return (Boolean) obj;
174         }
175         // if it's a Number, != 0 -> true
176         else if ( obj instanceof Number )
177         {
178             double d = ((Number) obj).doubleValue();
179             if ( d == 0 || Double.isNaN(d) )
180             {
181                 return Boolean.FALSE;
182             }
183             return Boolean.TRUE;
184         }
185         // if it's a String, "" -> false
186         else if ( obj instanceof String )
187         {
188             return ( ((String)obj).length() > 0
189                      ? Boolean.TRUE
190                      : Boolean.FALSE );
191         }
192         else 
193         {
194             // assume it's a node so that this node-set is non-empty 
195             // and so it's true
196             return ( obj != null ) ? Boolean.TRUE : Boolean.FALSE;
197         }
198 
199     }
200 }