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