12005
|
1 |
/*
|
|
2 |
* reserved comment block
|
|
3 |
* DO NOT REMOVE OR ALTER!
|
|
4 |
*/
|
|
5 |
/*
|
|
6 |
* Copyright 1999-2004 The Apache Software Foundation.
|
|
7 |
*
|
|
8 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
9 |
* you may not use this file except in compliance with the License.
|
|
10 |
* You may obtain a copy of the License at
|
|
11 |
*
|
|
12 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
13 |
*
|
|
14 |
* Unless required by applicable law or agreed to in writing, software
|
|
15 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17 |
* See the License for the specific language governing permissions and
|
|
18 |
* limitations under the License.
|
|
19 |
*/
|
|
20 |
/*
|
|
21 |
* $Id: XNumber.java,v 1.2.4.2 2005/09/14 20:34:46 jeffsuttor Exp $
|
|
22 |
*/
|
|
23 |
package com.sun.org.apache.xpath.internal.objects;
|
|
24 |
|
|
25 |
import com.sun.org.apache.xpath.internal.ExpressionOwner;
|
|
26 |
import com.sun.org.apache.xpath.internal.XPathContext;
|
|
27 |
import com.sun.org.apache.xpath.internal.XPathVisitor;
|
|
28 |
|
|
29 |
/**
|
|
30 |
* This class represents an XPath number, and is capable of
|
|
31 |
* converting the number to other types, such as a string.
|
|
32 |
* @xsl.usage general
|
|
33 |
*/
|
|
34 |
public class XNumber extends XObject
|
|
35 |
{
|
|
36 |
static final long serialVersionUID = -2720400709619020193L;
|
|
37 |
|
|
38 |
/** Value of the XNumber object.
|
|
39 |
* @serial */
|
|
40 |
double m_val;
|
|
41 |
|
|
42 |
/**
|
|
43 |
* Construct a XNodeSet object.
|
|
44 |
*
|
|
45 |
* @param d Value of the object
|
|
46 |
*/
|
|
47 |
public XNumber(double d)
|
|
48 |
{
|
|
49 |
super();
|
|
50 |
|
|
51 |
m_val = d;
|
|
52 |
}
|
|
53 |
|
|
54 |
/**
|
|
55 |
* Construct a XNodeSet object.
|
|
56 |
*
|
|
57 |
* @param num Value of the object
|
|
58 |
*/
|
|
59 |
public XNumber(Number num)
|
|
60 |
{
|
|
61 |
|
|
62 |
super();
|
|
63 |
|
|
64 |
m_val = num.doubleValue();
|
|
65 |
setObject(num);
|
|
66 |
}
|
|
67 |
|
|
68 |
/**
|
|
69 |
* Tell that this is a CLASS_NUMBER.
|
|
70 |
*
|
|
71 |
* @return node type CLASS_NUMBER
|
|
72 |
*/
|
|
73 |
public int getType()
|
|
74 |
{
|
|
75 |
return CLASS_NUMBER;
|
|
76 |
}
|
|
77 |
|
|
78 |
/**
|
|
79 |
* Given a request type, return the equivalent string.
|
|
80 |
* For diagnostic purposes.
|
|
81 |
*
|
|
82 |
* @return type string "#NUMBER"
|
|
83 |
*/
|
|
84 |
public String getTypeString()
|
|
85 |
{
|
|
86 |
return "#NUMBER";
|
|
87 |
}
|
|
88 |
|
|
89 |
/**
|
|
90 |
* Cast result object to a number.
|
|
91 |
*
|
|
92 |
* @return the value of the XNumber object
|
|
93 |
*/
|
|
94 |
public double num()
|
|
95 |
{
|
|
96 |
return m_val;
|
|
97 |
}
|
|
98 |
|
|
99 |
/**
|
|
100 |
* Evaluate expression to a number.
|
|
101 |
*
|
|
102 |
* @return 0.0
|
|
103 |
*
|
|
104 |
* @throws javax.xml.transform.TransformerException
|
|
105 |
*/
|
|
106 |
public double num(XPathContext xctxt)
|
|
107 |
throws javax.xml.transform.TransformerException
|
|
108 |
{
|
|
109 |
|
|
110 |
return m_val;
|
|
111 |
}
|
|
112 |
|
|
113 |
/**
|
|
114 |
* Cast result object to a boolean.
|
|
115 |
*
|
|
116 |
* @return false if the value is NaN or equal to 0.0
|
|
117 |
*/
|
|
118 |
public boolean bool()
|
|
119 |
{
|
|
120 |
return (Double.isNaN(m_val) || (m_val == 0.0)) ? false : true;
|
|
121 |
}
|
|
122 |
|
|
123 |
// /**
|
|
124 |
// * Cast result object to a string.
|
|
125 |
// *
|
|
126 |
// * @return "NaN" if the number is NaN, Infinity or -Infinity if
|
|
127 |
// * the number is infinite or the string value of the number.
|
|
128 |
// */
|
|
129 |
// private static final int PRECISION = 16;
|
|
130 |
// public String str()
|
|
131 |
// {
|
|
132 |
//
|
|
133 |
// if (Double.isNaN(m_val))
|
|
134 |
// {
|
|
135 |
// return "NaN";
|
|
136 |
// }
|
|
137 |
// else if (Double.isInfinite(m_val))
|
|
138 |
// {
|
|
139 |
// if (m_val > 0)
|
|
140 |
// return "Infinity";
|
|
141 |
// else
|
|
142 |
// return "-Infinity";
|
|
143 |
// }
|
|
144 |
//
|
|
145 |
// long longVal = (long)m_val;
|
|
146 |
// if ((double)longVal == m_val)
|
|
147 |
// return Long.toString(longVal);
|
|
148 |
//
|
|
149 |
//
|
|
150 |
// String s = Double.toString(m_val);
|
|
151 |
// int len = s.length();
|
|
152 |
//
|
|
153 |
// if (s.charAt(len - 2) == '.' && s.charAt(len - 1) == '0')
|
|
154 |
// {
|
|
155 |
// return s.substring(0, len - 2);
|
|
156 |
// }
|
|
157 |
//
|
|
158 |
// int exp = 0;
|
|
159 |
// int e = s.indexOf('E');
|
|
160 |
// if (e != -1)
|
|
161 |
// {
|
|
162 |
// exp = Integer.parseInt(s.substring(e + 1));
|
|
163 |
// s = s.substring(0,e);
|
|
164 |
// len = e;
|
|
165 |
// }
|
|
166 |
//
|
|
167 |
// // Calculate Significant Digits:
|
|
168 |
// // look from start of string for first digit
|
|
169 |
// // look from end for last digit
|
|
170 |
// // significant digits = end - start + (0 or 1 depending on decimal location)
|
|
171 |
//
|
|
172 |
// int decimalPos = -1;
|
|
173 |
// int start = (s.charAt(0) == '-') ? 1 : 0;
|
|
174 |
// findStart: for( ; start < len; start++ )
|
|
175 |
// {
|
|
176 |
// switch (s.charAt(start))
|
|
177 |
// {
|
|
178 |
// case '0':
|
|
179 |
// break;
|
|
180 |
// case '.':
|
|
181 |
// decimalPos = start;
|
|
182 |
// break;
|
|
183 |
// default:
|
|
184 |
// break findStart;
|
|
185 |
// }
|
|
186 |
// }
|
|
187 |
// int end = s.length() - 1;
|
|
188 |
// findEnd: for( ; end > start; end-- )
|
|
189 |
// {
|
|
190 |
// switch (s.charAt(end))
|
|
191 |
// {
|
|
192 |
// case '0':
|
|
193 |
// break;
|
|
194 |
// case '.':
|
|
195 |
// decimalPos = end;
|
|
196 |
// break;
|
|
197 |
// default:
|
|
198 |
// break findEnd;
|
|
199 |
// }
|
|
200 |
// }
|
|
201 |
//
|
|
202 |
// int sigDig = end - start;
|
|
203 |
//
|
|
204 |
// // clarify decimal location if it has not yet been found
|
|
205 |
// if (decimalPos == -1)
|
|
206 |
// decimalPos = s.indexOf('.');
|
|
207 |
//
|
|
208 |
// // if decimal is not between start and end, add one to sigDig
|
|
209 |
// if (decimalPos < start || decimalPos > end)
|
|
210 |
// ++sigDig;
|
|
211 |
//
|
|
212 |
// // reduce significant digits to PRECISION if necessary
|
|
213 |
// if (sigDig > PRECISION)
|
|
214 |
// {
|
|
215 |
// // re-scale BigDecimal in order to get significant digits = PRECISION
|
|
216 |
// BigDecimal num = new BigDecimal(s);
|
|
217 |
// int newScale = num.scale() - (sigDig - PRECISION);
|
|
218 |
// if (newScale < 0)
|
|
219 |
// newScale = 0;
|
|
220 |
// s = num.setScale(newScale, BigDecimal.ROUND_HALF_UP).toString();
|
|
221 |
//
|
|
222 |
// // remove trailing '0's; keep track of decimalPos
|
|
223 |
// int truncatePoint = s.length();
|
|
224 |
// while (s.charAt(--truncatePoint) == '0')
|
|
225 |
// ;
|
|
226 |
//
|
|
227 |
// if (s.charAt(truncatePoint) == '.')
|
|
228 |
// {
|
|
229 |
// decimalPos = truncatePoint;
|
|
230 |
// }
|
|
231 |
// else
|
|
232 |
// {
|
|
233 |
// decimalPos = s.indexOf('.');
|
|
234 |
// truncatePoint += 1;
|
|
235 |
// }
|
|
236 |
//
|
|
237 |
// s = s.substring(0, truncatePoint);
|
|
238 |
// len = s.length();
|
|
239 |
// }
|
|
240 |
//
|
|
241 |
// // Account for exponent by adding zeros as needed
|
|
242 |
// // and moving the decimal place
|
|
243 |
//
|
|
244 |
// if (exp == 0)
|
|
245 |
// return s;
|
|
246 |
//
|
|
247 |
// start = 0;
|
|
248 |
// String sign;
|
|
249 |
// if (s.charAt(0) == '-')
|
|
250 |
// {
|
|
251 |
// sign = "-";
|
|
252 |
// start++;
|
|
253 |
// }
|
|
254 |
// else
|
|
255 |
// sign = "";
|
|
256 |
//
|
|
257 |
// String wholePart = s.substring(start, decimalPos);
|
|
258 |
// String decimalPart = s.substring(decimalPos + 1);
|
|
259 |
//
|
|
260 |
// // get the number of digits right of the decimal
|
|
261 |
// int decimalLen = decimalPart.length();
|
|
262 |
//
|
|
263 |
// if (exp >= decimalLen)
|
|
264 |
// return sign + wholePart + decimalPart + zeros(exp - decimalLen);
|
|
265 |
//
|
|
266 |
// if (exp > 0)
|
|
267 |
// return sign + wholePart + decimalPart.substring(0, exp) + "."
|
|
268 |
// + decimalPart.substring(exp);
|
|
269 |
//
|
|
270 |
// return sign + "0." + zeros(-1 - exp) + wholePart + decimalPart;
|
|
271 |
// }
|
|
272 |
|
|
273 |
/**
|
|
274 |
* Cast result object to a string.
|
|
275 |
*
|
|
276 |
* @return "NaN" if the number is NaN, Infinity or -Infinity if
|
|
277 |
* the number is infinite or the string value of the number.
|
|
278 |
*/
|
|
279 |
public String str()
|
|
280 |
{
|
|
281 |
|
|
282 |
if (Double.isNaN(m_val))
|
|
283 |
{
|
|
284 |
return "NaN";
|
|
285 |
}
|
|
286 |
else if (Double.isInfinite(m_val))
|
|
287 |
{
|
|
288 |
if (m_val > 0)
|
|
289 |
return "Infinity";
|
|
290 |
else
|
|
291 |
return "-Infinity";
|
|
292 |
}
|
|
293 |
|
|
294 |
double num = m_val;
|
|
295 |
String s = Double.toString(num);
|
|
296 |
int len = s.length();
|
|
297 |
|
|
298 |
if (s.charAt(len - 2) == '.' && s.charAt(len - 1) == '0')
|
|
299 |
{
|
|
300 |
s = s.substring(0, len - 2);
|
|
301 |
|
|
302 |
if (s.equals("-0"))
|
|
303 |
return "0";
|
|
304 |
|
|
305 |
return s;
|
|
306 |
}
|
|
307 |
|
|
308 |
int e = s.indexOf('E');
|
|
309 |
|
|
310 |
if (e < 0)
|
|
311 |
{
|
|
312 |
if (s.charAt(len - 1) == '0')
|
|
313 |
return s.substring(0, len - 1);
|
|
314 |
else
|
|
315 |
return s;
|
|
316 |
}
|
|
317 |
|
|
318 |
int exp = Integer.parseInt(s.substring(e + 1));
|
|
319 |
String sign;
|
|
320 |
|
|
321 |
if (s.charAt(0) == '-')
|
|
322 |
{
|
|
323 |
sign = "-";
|
|
324 |
s = s.substring(1);
|
|
325 |
|
|
326 |
--e;
|
|
327 |
}
|
|
328 |
else
|
|
329 |
sign = "";
|
|
330 |
|
|
331 |
int nDigits = e - 2;
|
|
332 |
|
|
333 |
if (exp >= nDigits)
|
|
334 |
return sign + s.substring(0, 1) + s.substring(2, e)
|
|
335 |
+ zeros(exp - nDigits);
|
|
336 |
|
|
337 |
// Eliminate trailing 0's - bugzilla 14241
|
|
338 |
while (s.charAt(e-1) == '0')
|
|
339 |
e--;
|
|
340 |
|
|
341 |
if (exp > 0)
|
|
342 |
return sign + s.substring(0, 1) + s.substring(2, 2 + exp) + "."
|
|
343 |
+ s.substring(2 + exp, e);
|
|
344 |
|
|
345 |
return sign + "0." + zeros(-1 - exp) + s.substring(0, 1)
|
|
346 |
+ s.substring(2, e);
|
|
347 |
}
|
|
348 |
|
|
349 |
|
|
350 |
/**
|
|
351 |
* Return a string of '0' of the given length
|
|
352 |
*
|
|
353 |
*
|
|
354 |
* @param n Length of the string to be returned
|
|
355 |
*
|
|
356 |
* @return a string of '0' with the given length
|
|
357 |
*/
|
|
358 |
static private String zeros(int n)
|
|
359 |
{
|
|
360 |
if (n < 1)
|
|
361 |
return "";
|
|
362 |
|
|
363 |
char[] buf = new char[n];
|
|
364 |
|
|
365 |
for (int i = 0; i < n; i++)
|
|
366 |
{
|
|
367 |
buf[i] = '0';
|
|
368 |
}
|
|
369 |
|
|
370 |
return new String(buf);
|
|
371 |
}
|
|
372 |
|
|
373 |
/**
|
|
374 |
* Return a java object that's closest to the representation
|
|
375 |
* that should be handed to an extension.
|
|
376 |
*
|
|
377 |
* @return The value of this XNumber as a Double object
|
|
378 |
*/
|
|
379 |
public Object object()
|
|
380 |
{
|
|
381 |
if(null == m_obj)
|
|
382 |
setObject(new Double(m_val));
|
|
383 |
return m_obj;
|
|
384 |
}
|
|
385 |
|
|
386 |
/**
|
|
387 |
* Tell if two objects are functionally equal.
|
|
388 |
*
|
|
389 |
* @param obj2 Object to compare this to
|
|
390 |
*
|
|
391 |
* @return true if the two objects are equal
|
|
392 |
*
|
|
393 |
* @throws javax.xml.transform.TransformerException
|
|
394 |
*/
|
|
395 |
public boolean equals(XObject obj2)
|
|
396 |
{
|
|
397 |
|
|
398 |
// In order to handle the 'all' semantics of
|
|
399 |
// nodeset comparisons, we always call the
|
|
400 |
// nodeset function.
|
|
401 |
int t = obj2.getType();
|
|
402 |
try
|
|
403 |
{
|
|
404 |
if (t == XObject.CLASS_NODESET)
|
|
405 |
return obj2.equals(this);
|
|
406 |
else if(t == XObject.CLASS_BOOLEAN)
|
|
407 |
return obj2.bool() == bool();
|
|
408 |
else
|
|
409 |
return m_val == obj2.num();
|
|
410 |
}
|
|
411 |
catch(javax.xml.transform.TransformerException te)
|
|
412 |
{
|
|
413 |
throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(te);
|
|
414 |
}
|
|
415 |
}
|
|
416 |
|
|
417 |
/**
|
|
418 |
* Tell if this expression returns a stable number that will not change during
|
|
419 |
* iterations within the expression. This is used to determine if a proximity
|
|
420 |
* position predicate can indicate that no more searching has to occur.
|
|
421 |
*
|
|
422 |
*
|
|
423 |
* @return true if the expression represents a stable number.
|
|
424 |
*/
|
|
425 |
public boolean isStableNumber()
|
|
426 |
{
|
|
427 |
return true;
|
|
428 |
}
|
|
429 |
|
|
430 |
/**
|
|
431 |
* @see com.sun.org.apache.xpath.internal.XPathVisitable#callVisitors(ExpressionOwner, XPathVisitor)
|
|
432 |
*/
|
|
433 |
public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
|
|
434 |
{
|
|
435 |
visitor.visitNumberLiteral(owner, this);
|
|
436 |
}
|
|
437 |
|
|
438 |
|
|
439 |
}
|