1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xalan.lib;
  58. import org.w3c.dom.Node;
  59. import org.w3c.dom.NodeList;
  60. import org.apache.xpath.NodeSet;
  61. /**
  62. * <meta name="usage" content="general"/>
  63. * This class contains EXSLT math extension functions.
  64. * It is accessed by specifying a namespace URI as follows:
  65. * <pre>
  66. * xmlns:math="http://exslt.org/math"
  67. * </pre>
  68. *
  69. * The documentation for each function has been copied from the relevant
  70. * EXSLT Implementer page.
  71. *
  72. * @see <a href="http://www.exslt.org/">EXSLT</a>
  73. */
  74. public class ExsltMath extends ExsltBase
  75. {
  76. // Constants
  77. private static String PI = "3.1415926535897932384626433832795028841971693993751";
  78. private static String E = "2.71828182845904523536028747135266249775724709369996";
  79. private static String SQRRT2 = "1.41421356237309504880168872420969807856967187537694";
  80. private static String LN2 = "0.69314718055994530941723212145817656807550013436025";
  81. private static String LN10 = "2.302585092994046";
  82. private static String LOG2E = "1.4426950408889633";
  83. private static String SQRT1_2 = "0.7071067811865476";
  84. /**
  85. * The math:max function returns the maximum value of the nodes passed as the argument.
  86. * The maximum value is defined as follows. The node set passed as an argument is sorted
  87. * in descending order as it would be by xsl:sort with a data type of number. The maximum
  88. * is the result of converting the string value of the first node in this sorted list to
  89. * a number using the number function.
  90. * <p>
  91. * If the node set is empty, or if the result of converting the string values of any of the
  92. * nodes to a number is NaN, then NaN is returned.
  93. *
  94. * @param nl The NodeList for the node-set to be evaluated.
  95. *
  96. * @return the maximum value found, NaN if any node cannot be converted to a number.
  97. *
  98. * @see <a href="http://www.exslt.org/">EXSLT</a>
  99. */
  100. public static double max (NodeList nl)
  101. {
  102. if (nl == null || nl.getLength() == 0)
  103. return Double.NaN;
  104. double m = - Double.MAX_VALUE;
  105. for (int i = 0; i < nl.getLength(); i++)
  106. {
  107. Node n = nl.item(i);
  108. double d = toNumber(n);
  109. if (Double.isNaN(d))
  110. return Double.NaN;
  111. else if (d > m)
  112. m = d;
  113. }
  114. return m;
  115. }
  116. /**
  117. * The math:min function returns the minimum value of the nodes passed as the argument.
  118. * The minimum value is defined as follows. The node set passed as an argument is sorted
  119. * in ascending order as it would be by xsl:sort with a data type of number. The minimum
  120. * is the result of converting the string value of the first node in this sorted list to
  121. * a number using the number function.
  122. * <p>
  123. * If the node set is empty, or if the result of converting the string values of any of
  124. * the nodes to a number is NaN, then NaN is returned.
  125. *
  126. * @param nl The NodeList for the node-set to be evaluated.
  127. *
  128. * @return the minimum value found, NaN if any node cannot be converted to a number.
  129. *
  130. * @see <a href="http://www.exslt.org/">EXSLT</a>
  131. */
  132. public static double min (NodeList nl)
  133. {
  134. if (nl == null || nl.getLength() == 0)
  135. return Double.NaN;
  136. double m = Double.MAX_VALUE;
  137. for (int i = 0; i < nl.getLength(); i++)
  138. {
  139. Node n = nl.item(i);
  140. double d = toNumber(n);
  141. if (Double.isNaN(d))
  142. return Double.NaN;
  143. else if (d < m)
  144. m = d;
  145. }
  146. return m;
  147. }
  148. /**
  149. * The math:highest function returns the nodes in the node set whose value is the maximum
  150. * value for the node set. The maximum value for the node set is the same as the value as
  151. * calculated by math:max. A node has this maximum value if the result of converting its
  152. * string value to a number as if by the number function is equal to the maximum value,
  153. * where the equality comparison is defined as a numerical comparison using the = operator.
  154. * <p>
  155. * If any of the nodes in the node set has a non-numeric value, the math:max function will
  156. * return NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any
  157. * of the nodes in the node set has a non-numeric value, math:highest will return an empty
  158. * node set.
  159. *
  160. * @param nl The NodeList for the node-set to be evaluated.
  161. *
  162. * @return node-set with nodes containing the maximum value found, an empty node-set
  163. * if any node cannot be converted to a number.
  164. */
  165. public static NodeList highest (NodeList nl)
  166. {
  167. double maxValue = max(nl);
  168. NodeSet highNodes = new NodeSet();
  169. highNodes.setShouldCacheNodes(true);
  170. if (Double.isNaN(maxValue))
  171. return highNodes; // empty Nodeset
  172. for (int i = 0; i < nl.getLength(); i++)
  173. {
  174. Node n = nl.item(i);
  175. double d = toNumber(n);
  176. if (d == maxValue)
  177. highNodes.addElement(n);
  178. }
  179. return highNodes;
  180. }
  181. /**
  182. * The math:lowest function returns the nodes in the node set whose value is the minimum value
  183. * for the node set. The minimum value for the node set is the same as the value as calculated
  184. * by math:min. A node has this minimum value if the result of converting its string value to
  185. * a number as if by the number function is equal to the minimum value, where the equality
  186. * comparison is defined as a numerical comparison using the = operator.
  187. * <p>
  188. * If any of the nodes in the node set has a non-numeric value, the math:min function will return
  189. * NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any of the nodes
  190. * in the node set has a non-numeric value, math:lowest will return an empty node set.
  191. *
  192. * @param nl The NodeList for the node-set to be evaluated.
  193. *
  194. * @return node-set with nodes containing the minimum value found, an empty node-set
  195. * if any node cannot be converted to a number.
  196. *
  197. */
  198. public static NodeList lowest (NodeList nl)
  199. {
  200. double minValue = min(nl);
  201. NodeSet lowNodes = new NodeSet();
  202. lowNodes.setShouldCacheNodes(true);
  203. if (Double.isNaN(minValue))
  204. return lowNodes; // empty Nodeset
  205. for (int i = 0; i < nl.getLength(); i++)
  206. {
  207. Node n = nl.item(i);
  208. double d = toNumber(n);
  209. if (d == minValue)
  210. lowNodes.addElement(n);
  211. }
  212. return lowNodes;
  213. }
  214. /**
  215. * The math:abs function returns the absolute value of a number.
  216. *
  217. * @param num A number
  218. * @return The absolute value of the number
  219. */
  220. public static double abs(double num)
  221. {
  222. return Math.abs(num);
  223. }
  224. /**
  225. * The math:acos function returns the arccosine value of a number.
  226. *
  227. * @param num A number
  228. * @return The arccosine value of the number
  229. */
  230. public static double acos(double num)
  231. {
  232. return Math.acos(num);
  233. }
  234. /**
  235. * The math:asin function returns the arcsine value of a number.
  236. *
  237. * @param num A number
  238. * @return The arcsine value of the number
  239. */
  240. public static double asin(double num)
  241. {
  242. return Math.asin(num);
  243. }
  244. /**
  245. * The math:atan function returns the arctangent value of a number.
  246. *
  247. * @param num A number
  248. * @return The arctangent value of the number
  249. */
  250. public static double atan(double num)
  251. {
  252. return Math.atan(num);
  253. }
  254. /**
  255. * The math:atan2 function returns the angle ( in radians ) from the X axis to a point (y,x).
  256. *
  257. * @param num1 The X axis value
  258. * @param num2 The Y axis value
  259. * @return The angle (in radians) from the X axis to a point (y,x)
  260. */
  261. public static double atan2(double num1, double num2)
  262. {
  263. return Math.atan2(num1, num2);
  264. }
  265. /**
  266. * The math:cos function returns cosine of the passed argument.
  267. *
  268. * @param num A number
  269. * @return The cosine value of the number
  270. */
  271. public static double cos(double num)
  272. {
  273. return Math.cos(num);
  274. }
  275. /**
  276. * The math:exp function returns e (the base of natural logarithms) raised to a power.
  277. *
  278. * @param num A number
  279. * @return The value of e raised to the given power
  280. */
  281. public static double exp(double num)
  282. {
  283. return Math.exp(num);
  284. }
  285. /**
  286. * The math:log function returns the natural logarithm of a number.
  287. *
  288. * @param num A number
  289. * @return The natural logarithm of the number
  290. */
  291. public static double log(double num)
  292. {
  293. return Math.log(num);
  294. }
  295. /**
  296. * The math:power function returns the value of a base expression taken to a specified power.
  297. *
  298. * @param num1 The base
  299. * @param num2 The power
  300. * @return The value of the base expression taken to the specified power
  301. */
  302. public static double power(double num1, double num2)
  303. {
  304. return Math.pow(num1, num2);
  305. }
  306. /**
  307. * The math:random function returns a random number from 0 to 1.
  308. *
  309. * @return A random double from 0 to 1
  310. */
  311. public static double random()
  312. {
  313. return Math.random();
  314. }
  315. /**
  316. * The math:sin function returns the sine of the number.
  317. *
  318. * @param num A number
  319. * @return The sine value of the number
  320. */
  321. public static double sin(double num)
  322. {
  323. return Math.sin(num);
  324. }
  325. /**
  326. * The math:sqrt function returns the square root of a number.
  327. *
  328. * @param num A number
  329. * @return The square root of the number
  330. */
  331. public static double sqrt(double num)
  332. {
  333. return Math.sqrt(num);
  334. }
  335. /**
  336. * The math:tan function returns the tangent of the number passed as an argument.
  337. *
  338. * @param num A number
  339. * @return The tangent value of the number
  340. */
  341. public static double tan(double num)
  342. {
  343. return Math.tan(num);
  344. }
  345. /**
  346. * The math:constant function returns the specified constant to a set precision.
  347. * The possible constants are:
  348. * <pre>
  349. * PI
  350. * E
  351. * SQRRT2
  352. * LN2
  353. * LN10
  354. * LOG2E
  355. * SQRT1_2
  356. * </pre>
  357. * @param name The name of the constant
  358. * @param precision The precision
  359. * @return The value of the specified constant to the given precision
  360. */
  361. public static double constant(String name, double precision)
  362. {
  363. String value = null;
  364. if (name.equals("PI"))
  365. value = PI;
  366. else if (name.equals("E"))
  367. value = E;
  368. else if (name.equals("SQRRT2"))
  369. value = SQRRT2;
  370. else if (name.equals("LN2"))
  371. value = LN2;
  372. else if (name.equals("LN10"))
  373. value = LN10;
  374. else if (name.equals("LOG2E"))
  375. value = LOG2E;
  376. else if (name.equals("SQRT1_2"))
  377. value = SQRT1_2;
  378. if (value != null)
  379. {
  380. int bits = new Double(precision).intValue();
  381. if (bits <= value.length())
  382. value = value.substring(0, bits);
  383. return new Double(value).doubleValue();
  384. }
  385. else
  386. return Double.NaN;
  387. }
  388. }