You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
440 lines
9.9 KiB
440 lines
9.9 KiB
/*
|
|
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*/
|
|
/*
|
|
* Copyright 1999-2004 The Apache Software Foundation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/*
|
|
* $Id: XNumber.java,v 1.2.4.2 2005/09/14 20:34:46 jeffsuttor Exp $
|
|
*/
|
|
package com.sun.org.apache.xpath.internal.objects;
|
|
|
|
import com.sun.org.apache.xpath.internal.ExpressionOwner;
|
|
import com.sun.org.apache.xpath.internal.XPathContext;
|
|
import com.sun.org.apache.xpath.internal.XPathVisitor;
|
|
|
|
/**
|
|
* This class represents an XPath number, and is capable of
|
|
* converting the number to other types, such as a string.
|
|
* @xsl.usage general
|
|
*/
|
|
public class XNumber extends XObject
|
|
{
|
|
static final long serialVersionUID = -2720400709619020193L;
|
|
|
|
/** Value of the XNumber object.
|
|
* @serial */
|
|
double m_val;
|
|
|
|
/**
|
|
* Construct a XNodeSet object.
|
|
*
|
|
* @param d Value of the object
|
|
*/
|
|
public XNumber(double d)
|
|
{
|
|
super();
|
|
|
|
m_val = d;
|
|
}
|
|
|
|
/**
|
|
* Construct a XNodeSet object.
|
|
*
|
|
* @param num Value of the object
|
|
*/
|
|
public XNumber(Number num)
|
|
{
|
|
|
|
super();
|
|
|
|
m_val = num.doubleValue();
|
|
setObject(num);
|
|
}
|
|
|
|
/**
|
|
* Tell that this is a CLASS_NUMBER.
|
|
*
|
|
* @return node type CLASS_NUMBER
|
|
*/
|
|
public int getType()
|
|
{
|
|
return CLASS_NUMBER;
|
|
}
|
|
|
|
/**
|
|
* Given a request type, return the equivalent string.
|
|
* For diagnostic purposes.
|
|
*
|
|
* @return type string "#NUMBER"
|
|
*/
|
|
public String getTypeString()
|
|
{
|
|
return "#NUMBER";
|
|
}
|
|
|
|
/**
|
|
* Cast result object to a number.
|
|
*
|
|
* @return the value of the XNumber object
|
|
*/
|
|
public double num()
|
|
{
|
|
return m_val;
|
|
}
|
|
|
|
/**
|
|
* Evaluate expression to a number.
|
|
*
|
|
* @return 0.0
|
|
*
|
|
* @throws javax.xml.transform.TransformerException
|
|
*/
|
|
public double num(XPathContext xctxt)
|
|
throws javax.xml.transform.TransformerException
|
|
{
|
|
|
|
return m_val;
|
|
}
|
|
|
|
/**
|
|
* Cast result object to a boolean.
|
|
*
|
|
* @return false if the value is NaN or equal to 0.0
|
|
*/
|
|
public boolean bool()
|
|
{
|
|
return (Double.isNaN(m_val) || (m_val == 0.0)) ? false : true;
|
|
}
|
|
|
|
// /**
|
|
// * Cast result object to a string.
|
|
// *
|
|
// * @return "NaN" if the number is NaN, Infinity or -Infinity if
|
|
// * the number is infinite or the string value of the number.
|
|
// */
|
|
// private static final int PRECISION = 16;
|
|
// public String str()
|
|
// {
|
|
//
|
|
// if (Double.isNaN(m_val))
|
|
// {
|
|
// return "NaN";
|
|
// }
|
|
// else if (Double.isInfinite(m_val))
|
|
// {
|
|
// if (m_val > 0)
|
|
// return "Infinity";
|
|
// else
|
|
// return "-Infinity";
|
|
// }
|
|
//
|
|
// long longVal = (long)m_val;
|
|
// if ((double)longVal == m_val)
|
|
// return Long.toString(longVal);
|
|
//
|
|
//
|
|
// String s = Double.toString(m_val);
|
|
// int len = s.length();
|
|
//
|
|
// if (s.charAt(len - 2) == '.' && s.charAt(len - 1) == '0')
|
|
// {
|
|
// return s.substring(0, len - 2);
|
|
// }
|
|
//
|
|
// int exp = 0;
|
|
// int e = s.indexOf('E');
|
|
// if (e != -1)
|
|
// {
|
|
// exp = Integer.parseInt(s.substring(e + 1));
|
|
// s = s.substring(0,e);
|
|
// len = e;
|
|
// }
|
|
//
|
|
// // Calculate Significant Digits:
|
|
// // look from start of string for first digit
|
|
// // look from end for last digit
|
|
// // significant digits = end - start + (0 or 1 depending on decimal location)
|
|
//
|
|
// int decimalPos = -1;
|
|
// int start = (s.charAt(0) == '-') ? 1 : 0;
|
|
// findStart: for( ; start < len; start++ )
|
|
// {
|
|
// switch (s.charAt(start))
|
|
// {
|
|
// case '0':
|
|
// break;
|
|
// case '.':
|
|
// decimalPos = start;
|
|
// break;
|
|
// default:
|
|
// break findStart;
|
|
// }
|
|
// }
|
|
// int end = s.length() - 1;
|
|
// findEnd: for( ; end > start; end-- )
|
|
// {
|
|
// switch (s.charAt(end))
|
|
// {
|
|
// case '0':
|
|
// break;
|
|
// case '.':
|
|
// decimalPos = end;
|
|
// break;
|
|
// default:
|
|
// break findEnd;
|
|
// }
|
|
// }
|
|
//
|
|
// int sigDig = end - start;
|
|
//
|
|
// // clarify decimal location if it has not yet been found
|
|
// if (decimalPos == -1)
|
|
// decimalPos = s.indexOf('.');
|
|
//
|
|
// // if decimal is not between start and end, add one to sigDig
|
|
// if (decimalPos < start || decimalPos > end)
|
|
// ++sigDig;
|
|
//
|
|
// // reduce significant digits to PRECISION if necessary
|
|
// if (sigDig > PRECISION)
|
|
// {
|
|
// // re-scale BigDecimal in order to get significant digits = PRECISION
|
|
// BigDecimal num = new BigDecimal(s);
|
|
// int newScale = num.scale() - (sigDig - PRECISION);
|
|
// if (newScale < 0)
|
|
// newScale = 0;
|
|
// s = num.setScale(newScale, BigDecimal.ROUND_HALF_UP).toString();
|
|
//
|
|
// // remove trailing '0's; keep track of decimalPos
|
|
// int truncatePoint = s.length();
|
|
// while (s.charAt(--truncatePoint) == '0')
|
|
// ;
|
|
//
|
|
// if (s.charAt(truncatePoint) == '.')
|
|
// {
|
|
// decimalPos = truncatePoint;
|
|
// }
|
|
// else
|
|
// {
|
|
// decimalPos = s.indexOf('.');
|
|
// truncatePoint += 1;
|
|
// }
|
|
//
|
|
// s = s.substring(0, truncatePoint);
|
|
// len = s.length();
|
|
// }
|
|
//
|
|
// // Account for exponent by adding zeros as needed
|
|
// // and moving the decimal place
|
|
//
|
|
// if (exp == 0)
|
|
// return s;
|
|
//
|
|
// start = 0;
|
|
// String sign;
|
|
// if (s.charAt(0) == '-')
|
|
// {
|
|
// sign = "-";
|
|
// start++;
|
|
// }
|
|
// else
|
|
// sign = "";
|
|
//
|
|
// String wholePart = s.substring(start, decimalPos);
|
|
// String decimalPart = s.substring(decimalPos + 1);
|
|
//
|
|
// // get the number of digits right of the decimal
|
|
// int decimalLen = decimalPart.length();
|
|
//
|
|
// if (exp >= decimalLen)
|
|
// return sign + wholePart + decimalPart + zeros(exp - decimalLen);
|
|
//
|
|
// if (exp > 0)
|
|
// return sign + wholePart + decimalPart.substring(0, exp) + "."
|
|
// + decimalPart.substring(exp);
|
|
//
|
|
// return sign + "0." + zeros(-1 - exp) + wholePart + decimalPart;
|
|
// }
|
|
|
|
/**
|
|
* Cast result object to a string.
|
|
*
|
|
* @return "NaN" if the number is NaN, Infinity or -Infinity if
|
|
* the number is infinite or the string value of the number.
|
|
*/
|
|
public String str()
|
|
{
|
|
|
|
if (Double.isNaN(m_val))
|
|
{
|
|
return "NaN";
|
|
}
|
|
else if (Double.isInfinite(m_val))
|
|
{
|
|
if (m_val > 0)
|
|
return "Infinity";
|
|
else
|
|
return "-Infinity";
|
|
}
|
|
|
|
double num = m_val;
|
|
String s = Double.toString(num);
|
|
int len = s.length();
|
|
|
|
if (s.charAt(len - 2) == '.' && s.charAt(len - 1) == '0')
|
|
{
|
|
s = s.substring(0, len - 2);
|
|
|
|
if (s.equals("-0"))
|
|
return "0";
|
|
|
|
return s;
|
|
}
|
|
|
|
int e = s.indexOf('E');
|
|
|
|
if (e < 0)
|
|
{
|
|
if (s.charAt(len - 1) == '0')
|
|
return s.substring(0, len - 1);
|
|
else
|
|
return s;
|
|
}
|
|
|
|
int exp = Integer.parseInt(s.substring(e + 1));
|
|
String sign;
|
|
|
|
if (s.charAt(0) == '-')
|
|
{
|
|
sign = "-";
|
|
s = s.substring(1);
|
|
|
|
--e;
|
|
}
|
|
else
|
|
sign = "";
|
|
|
|
int nDigits = e - 2;
|
|
|
|
if (exp >= nDigits)
|
|
return sign + s.substring(0, 1) + s.substring(2, e)
|
|
+ zeros(exp - nDigits);
|
|
|
|
// Eliminate trailing 0's - bugzilla 14241
|
|
while (s.charAt(e-1) == '0')
|
|
e--;
|
|
|
|
if (exp > 0)
|
|
return sign + s.substring(0, 1) + s.substring(2, 2 + exp) + "."
|
|
+ s.substring(2 + exp, e);
|
|
|
|
return sign + "0." + zeros(-1 - exp) + s.substring(0, 1)
|
|
+ s.substring(2, e);
|
|
}
|
|
|
|
|
|
/**
|
|
* Return a string of '0' of the given length
|
|
*
|
|
*
|
|
* @param n Length of the string to be returned
|
|
*
|
|
* @return a string of '0' with the given length
|
|
*/
|
|
static private String zeros(int n)
|
|
{
|
|
if (n < 1)
|
|
return "";
|
|
|
|
char[] buf = new char[n];
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
buf[i] = '0';
|
|
}
|
|
|
|
return new String(buf);
|
|
}
|
|
|
|
/**
|
|
* Return a java object that's closest to the representation
|
|
* that should be handed to an extension.
|
|
*
|
|
* @return The value of this XNumber as a Double object
|
|
*/
|
|
public Object object()
|
|
{
|
|
if(null == m_obj)
|
|
setObject(new Double(m_val));
|
|
return m_obj;
|
|
}
|
|
|
|
/**
|
|
* Tell if two objects are functionally equal.
|
|
*
|
|
* @param obj2 Object to compare this to
|
|
*
|
|
* @return true if the two objects are equal
|
|
*
|
|
* @throws javax.xml.transform.TransformerException
|
|
*/
|
|
public boolean equals(XObject obj2)
|
|
{
|
|
|
|
// In order to handle the 'all' semantics of
|
|
// nodeset comparisons, we always call the
|
|
// nodeset function.
|
|
int t = obj2.getType();
|
|
try
|
|
{
|
|
if (t == XObject.CLASS_NODESET)
|
|
return obj2.equals(this);
|
|
else if(t == XObject.CLASS_BOOLEAN)
|
|
return obj2.bool() == bool();
|
|
else
|
|
return m_val == obj2.num();
|
|
}
|
|
catch(javax.xml.transform.TransformerException te)
|
|
{
|
|
throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(te);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tell if this expression returns a stable number that will not change during
|
|
* iterations within the expression. This is used to determine if a proximity
|
|
* position predicate can indicate that no more searching has to occur.
|
|
*
|
|
*
|
|
* @return true if the expression represents a stable number.
|
|
*/
|
|
public boolean isStableNumber()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @see com.sun.org.apache.xpath.internal.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
|
|
*/
|
|
public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
|
|
{
|
|
visitor.visitNumberLiteral(owner, this);
|
|
}
|
|
|
|
|
|
}
|