001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.jxpath.ri;
019
020import org.apache.commons.jxpath.Pointer;
021import org.apache.commons.jxpath.ri.model.NodePointer;
022import org.apache.commons.jxpath.ri.model.VariablePointer;
023
024/**
025 * Type conversions, XPath style.
026 */
027public class InfoSetUtil {
028
029    private static final Double ZERO = Double.valueOf(0);
030    private static final Double ONE = Double.valueOf(1);
031    private static final Double NOT_A_NUMBER = Double.valueOf(Double.NaN);
032
033    /**
034     * Converts the supplied object to boolean.
035     *
036     * @param object to convert
037     * @return boolean
038     */
039    public static boolean booleanValue(final Object object) {
040        if (object instanceof Number) {
041            final double value = ((Number) object).doubleValue();
042            final int negZero = -0;
043            return value != 0 && value != negZero && !Double.isNaN(value);
044        }
045        if (object instanceof Boolean) {
046            return ((Boolean) object).booleanValue();
047        }
048        if (object instanceof EvalContext) {
049            final EvalContext ctx = (EvalContext) object;
050            final Pointer ptr = ctx.getSingleNodePointer();
051            return ptr != null && booleanValue(ptr);
052        }
053        if (object instanceof String) {
054            return ((String) object).length() != 0;
055        }
056        if (object instanceof NodePointer) {
057            NodePointer pointer = (NodePointer) object;
058            if (pointer instanceof VariablePointer) {
059                return booleanValue(pointer.getNode());
060            }
061            pointer = pointer.getValuePointer();
062            return pointer.isActual();
063        }
064        return object != null;
065    }
066
067    /**
068     * Converts the supplied object to double.
069     *
070     * @param object to convert
071     * @return double
072     */
073    public static double doubleValue(final Object object) {
074        if (object instanceof Number) {
075            return ((Number) object).doubleValue();
076        }
077        if (object instanceof Boolean) {
078            return ((Boolean) object).booleanValue() ? 0.0 : 1.0;
079        }
080        if (object instanceof String) {
081            if (object.equals("")) {
082                return 0.0;
083            }
084            try {
085                return Double.parseDouble((String) object);
086            } catch (final NumberFormatException ex) {
087                return Double.NaN;
088            }
089        }
090        if (object instanceof NodePointer) {
091            return doubleValue(((NodePointer) object).getValue());
092        }
093        if (object instanceof EvalContext) {
094            final EvalContext ctx = (EvalContext) object;
095            final Pointer ptr = ctx.getSingleNodePointer();
096            return ptr == null ? Double.NaN : doubleValue(ptr);
097        }
098        return doubleValue(stringValue(object));
099    }
100
101    /**
102     * Converts the supplied object to Number.
103     *
104     * @param object to convert
105     * @return Number result
106     */
107    public static Number number(final Object object) {
108        if (object instanceof Number) {
109            return (Number) object;
110        }
111        if (object instanceof Boolean) {
112            return ((Boolean) object).booleanValue() ? ONE : ZERO;
113        }
114        if (object instanceof String) {
115            try {
116                return Double.valueOf((String) object);
117            } catch (final NumberFormatException ex) {
118                return NOT_A_NUMBER;
119            }
120        }
121        if (object instanceof EvalContext) {
122            final EvalContext ctx = (EvalContext) object;
123            final Pointer ptr = ctx.getSingleNodePointer();
124            return ptr == null ? NOT_A_NUMBER : number(ptr);
125        }
126        if (object instanceof NodePointer) {
127            return number(((NodePointer) object).getValue());
128        }
129        return number(stringValue(object));
130    }
131
132    /**
133     * Converts the supplied object to String.
134     *
135     * @param object to convert
136     * @return String value
137     */
138    public static String stringValue(final Object object) {
139        if (object instanceof String) {
140            return (String) object;
141        }
142        if (object instanceof Number) {
143            final double d = ((Number) object).doubleValue();
144            final long l = ((Number) object).longValue();
145            return d == l ? String.valueOf(l) : String.valueOf(d);
146        }
147        if (object instanceof Boolean) {
148            return ((Boolean) object).booleanValue() ? "true" : "false";
149        }
150        if (object == null) {
151            return "";
152        }
153        if (object instanceof NodePointer) {
154            return stringValue(((NodePointer) object).getValue());
155        }
156        if (object instanceof EvalContext) {
157            final EvalContext ctx = (EvalContext) object;
158            final Pointer ptr = ctx.getSingleNodePointer();
159            return ptr == null ? "" : stringValue(ptr);
160        }
161        return String.valueOf(object);
162    }
163
164    /**
165     * Constructs a new instance.
166     *
167     * @deprecated Will be private in the next major version.
168     */
169    @Deprecated
170    public InfoSetUtil() {
171        // empty
172    }
173}