1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. 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 package com.sun.org.apache.xalan.internal.lib; 22 23 import com.sun.org.apache.xpath.internal.NodeSet; 24 25 import org.w3c.dom.Node; 26 import org.w3c.dom.NodeList; 27 28 /** 29 * This class contains EXSLT math extension functions. 30 * It is accessed by specifying a namespace URI as follows: 31 * <pre> 32 * xmlns:math="http://exslt.org/math" 33 * </pre> 34 * 35 * The documentation for each function has been copied from the relevant 36 * EXSLT Implementer page. 37 * 38 * @see <a href="http://www.exslt.org/">EXSLT</a> 39 40 * @xsl.usage general 41 */ 42 public class ExsltMath extends ExsltBase 43 { 44 // Constants 45 private static String PI = "3.1415926535897932384626433832795028841971693993751"; 46 private static String E = "2.71828182845904523536028747135266249775724709369996"; 47 private static String SQRRT2 = "1.41421356237309504880168872420969807856967187537694"; 48 private static String LN2 = "0.69314718055994530941723212145817656807550013436025"; 49 private static String LN10 = "2.302585092994046"; 50 private static String LOG2E = "1.4426950408889633"; 51 private static String SQRT1_2 = "0.7071067811865476"; 52 53 /** 54 * The math:max function returns the maximum value of the nodes passed as the argument. 55 * The maximum value is defined as follows. The node set passed as an argument is sorted 56 * in descending order as it would be by xsl:sort with a data type of number. The maximum 57 * is the result of converting the string value of the first node in this sorted list to 58 * a number using the number function. 59 * <p> 60 * If the node set is empty, or if the result of converting the string values of any of the 61 * nodes to a number is NaN, then NaN is returned. 62 * 63 * @param nl The NodeList for the node-set to be evaluated. 64 * 65 * @return the maximum value found, NaN if any node cannot be converted to a number. 66 * 67 * @see <a href="http://www.exslt.org/">EXSLT</a> 68 */ max(NodeList nl)69 public static double max (NodeList nl) 70 { 71 if (nl == null || nl.getLength() == 0) 72 return Double.NaN; 73 74 double m = - Double.MAX_VALUE; 75 for (int i = 0; i < nl.getLength(); i++) 76 { 77 Node n = nl.item(i); 78 double d = toNumber(n); 79 if (Double.isNaN(d)) 80 return Double.NaN; 81 else if (d > m) 82 m = d; 83 } 84 85 return m; 86 } 87 88 /** 89 * The math:min function returns the minimum value of the nodes passed as the argument. 90 * The minimum value is defined as follows. The node set passed as an argument is sorted 91 * in ascending order as it would be by xsl:sort with a data type of number. The minimum 92 * is the result of converting the string value of the first node in this sorted list to 93 * a number using the number function. 94 * <p> 95 * If the node set is empty, or if the result of converting the string values of any of 96 * the nodes to a number is NaN, then NaN is returned. 97 * 98 * @param nl The NodeList for the node-set to be evaluated. 99 * 100 * @return the minimum value found, NaN if any node cannot be converted to a number. 101 * 102 * @see <a href="http://www.exslt.org/">EXSLT</a> 103 */ min(NodeList nl)104 public static double min (NodeList nl) 105 { 106 if (nl == null || nl.getLength() == 0) 107 return Double.NaN; 108 109 double m = Double.MAX_VALUE; 110 for (int i = 0; i < nl.getLength(); i++) 111 { 112 Node n = nl.item(i); 113 double d = toNumber(n); 114 if (Double.isNaN(d)) 115 return Double.NaN; 116 else if (d < m) 117 m = d; 118 } 119 120 return m; 121 } 122 123 /** 124 * The math:highest function returns the nodes in the node set whose value is the maximum 125 * value for the node set. The maximum value for the node set is the same as the value as 126 * calculated by math:max. A node has this maximum value if the result of converting its 127 * string value to a number as if by the number function is equal to the maximum value, 128 * where the equality comparison is defined as a numerical comparison using the = operator. 129 * <p> 130 * If any of the nodes in the node set has a non-numeric value, the math:max function will 131 * return NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any 132 * of the nodes in the node set has a non-numeric value, math:highest will return an empty 133 * node set. 134 * 135 * @param nl The NodeList for the node-set to be evaluated. 136 * 137 * @return node-set with nodes containing the maximum value found, an empty node-set 138 * if any node cannot be converted to a number. 139 */ highest(NodeList nl)140 public static NodeList highest (NodeList nl) 141 { 142 double maxValue = max(nl); 143 144 NodeSet highNodes = new NodeSet(); 145 highNodes.setShouldCacheNodes(true); 146 147 if (Double.isNaN(maxValue)) 148 return highNodes; // empty Nodeset 149 150 for (int i = 0; i < nl.getLength(); i++) 151 { 152 Node n = nl.item(i); 153 double d = toNumber(n); 154 if (d == maxValue) 155 highNodes.addElement(n); 156 } 157 return highNodes; 158 } 159 160 /** 161 * The math:lowest function returns the nodes in the node set whose value is the minimum value 162 * for the node set. The minimum value for the node set is the same as the value as calculated 163 * by math:min. A node has this minimum value if the result of converting its string value to 164 * a number as if by the number function is equal to the minimum value, where the equality 165 * comparison is defined as a numerical comparison using the = operator. 166 * <p> 167 * If any of the nodes in the node set has a non-numeric value, the math:min function will return 168 * NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any of the nodes 169 * in the node set has a non-numeric value, math:lowest will return an empty node set. 170 * 171 * @param nl The NodeList for the node-set to be evaluated. 172 * 173 * @return node-set with nodes containing the minimum value found, an empty node-set 174 * if any node cannot be converted to a number. 175 * 176 */ lowest(NodeList nl)177 public static NodeList lowest (NodeList nl) 178 { 179 double minValue = min(nl); 180 181 NodeSet lowNodes = new NodeSet(); 182 lowNodes.setShouldCacheNodes(true); 183 184 if (Double.isNaN(minValue)) 185 return lowNodes; // empty Nodeset 186 187 for (int i = 0; i < nl.getLength(); i++) 188 { 189 Node n = nl.item(i); 190 double d = toNumber(n); 191 if (d == minValue) 192 lowNodes.addElement(n); 193 } 194 return lowNodes; 195 } 196 197 /** 198 * The math:abs function returns the absolute value of a number. 199 * 200 * @param num A number 201 * @return The absolute value of the number 202 */ abs(double num)203 public static double abs(double num) 204 { 205 return Math.abs(num); 206 } 207 208 /** 209 * The math:acos function returns the arccosine value of a number. 210 * 211 * @param num A number 212 * @return The arccosine value of the number 213 */ acos(double num)214 public static double acos(double num) 215 { 216 return Math.acos(num); 217 } 218 219 /** 220 * The math:asin function returns the arcsine value of a number. 221 * 222 * @param num A number 223 * @return The arcsine value of the number 224 */ asin(double num)225 public static double asin(double num) 226 { 227 return Math.asin(num); 228 } 229 230 /** 231 * The math:atan function returns the arctangent value of a number. 232 * 233 * @param num A number 234 * @return The arctangent value of the number 235 */ atan(double num)236 public static double atan(double num) 237 { 238 return Math.atan(num); 239 } 240 241 /** 242 * The math:atan2 function returns the angle ( in radians ) from the X axis to a point (y,x). 243 * 244 * @param num1 The X axis value 245 * @param num2 The Y axis value 246 * @return The angle (in radians) from the X axis to a point (y,x) 247 */ atan2(double num1, double num2)248 public static double atan2(double num1, double num2) 249 { 250 return Math.atan2(num1, num2); 251 } 252 253 /** 254 * The math:cos function returns cosine of the passed argument. 255 * 256 * @param num A number 257 * @return The cosine value of the number 258 */ cos(double num)259 public static double cos(double num) 260 { 261 return Math.cos(num); 262 } 263 264 /** 265 * The math:exp function returns e (the base of natural logarithms) raised to a power. 266 * 267 * @param num A number 268 * @return The value of e raised to the given power 269 */ exp(double num)270 public static double exp(double num) 271 { 272 return Math.exp(num); 273 } 274 275 /** 276 * The math:log function returns the natural logarithm of a number. 277 * 278 * @param num A number 279 * @return The natural logarithm of the number 280 */ log(double num)281 public static double log(double num) 282 { 283 return Math.log(num); 284 } 285 286 /** 287 * The math:power function returns the value of a base expression taken to a specified power. 288 * 289 * @param num1 The base 290 * @param num2 The power 291 * @return The value of the base expression taken to the specified power 292 */ power(double num1, double num2)293 public static double power(double num1, double num2) 294 { 295 return Math.pow(num1, num2); 296 } 297 298 /** 299 * The math:random function returns a random number from 0 to 1. 300 * 301 * @return A random double from 0 to 1 302 */ random()303 public static double random() 304 { 305 return Math.random(); 306 } 307 308 /** 309 * The math:sin function returns the sine of the number. 310 * 311 * @param num A number 312 * @return The sine value of the number 313 */ sin(double num)314 public static double sin(double num) 315 { 316 return Math.sin(num); 317 } 318 319 /** 320 * The math:sqrt function returns the square root of a number. 321 * 322 * @param num A number 323 * @return The square root of the number 324 */ sqrt(double num)325 public static double sqrt(double num) 326 { 327 return Math.sqrt(num); 328 } 329 330 /** 331 * The math:tan function returns the tangent of the number passed as an argument. 332 * 333 * @param num A number 334 * @return The tangent value of the number 335 */ tan(double num)336 public static double tan(double num) 337 { 338 return Math.tan(num); 339 } 340 341 /** 342 * The math:constant function returns the specified constant to a set precision. 343 * The possible constants are: 344 * <pre> 345 * PI 346 * E 347 * SQRRT2 348 * LN2 349 * LN10 350 * LOG2E 351 * SQRT1_2 352 * </pre> 353 * @param name The name of the constant 354 * @param precision The precision 355 * @return The value of the specified constant to the given precision 356 */ constant(String name, double precision)357 public static double constant(String name, double precision) 358 { 359 String value = null; 360 if (name.equals("PI")) 361 value = PI; 362 else if (name.equals("E")) 363 value = E; 364 else if (name.equals("SQRRT2")) 365 value = SQRRT2; 366 else if (name.equals("LN2")) 367 value = LN2; 368 else if (name.equals("LN10")) 369 value = LN10; 370 else if (name.equals("LOG2E")) 371 value = LOG2E; 372 else if (name.equals("SQRT1_2")) 373 value = SQRT1_2; 374 375 if (value != null) 376 { 377 int bits = (int)precision; 378 379 if (bits <= value.length()) 380 value = value.substring(0, bits); 381 382 return Double.parseDouble(value); 383 } 384 else 385 return Double.NaN; 386 387 } 388 389 } 390