001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: ExsltMath.java 468639 2006-10-28 06:52:33Z minchau $ 020 */ 021 package org.apache.xalan.lib; 022 023 import org.apache.xpath.NodeSet; 024 025 import org.w3c.dom.Node; 026 import org.w3c.dom.NodeList; 027 028 /** 029 * This class contains EXSLT math extension functions. 030 * It is accessed by specifying a namespace URI as follows: 031 * <pre> 032 * xmlns:math="http://exslt.org/math" 033 * </pre> 034 * 035 * The documentation for each function has been copied from the relevant 036 * EXSLT Implementer page. 037 * 038 * @see <a href="http://www.exslt.org/">EXSLT</a> 039 040 * @xsl.usage general 041 */ 042 public class ExsltMath extends ExsltBase 043 { 044 // Constants 045 private static String PI = "3.1415926535897932384626433832795028841971693993751"; 046 private static String E = "2.71828182845904523536028747135266249775724709369996"; 047 private static String SQRRT2 = "1.41421356237309504880168872420969807856967187537694"; 048 private static String LN2 = "0.69314718055994530941723212145817656807550013436025"; 049 private static String LN10 = "2.302585092994046"; 050 private static String LOG2E = "1.4426950408889633"; 051 private static String SQRT1_2 = "0.7071067811865476"; 052 053 /** 054 * The math:max function returns the maximum value of the nodes passed as the argument. 055 * The maximum value is defined as follows. The node set passed as an argument is sorted 056 * in descending order as it would be by xsl:sort with a data type of number. The maximum 057 * is the result of converting the string value of the first node in this sorted list to 058 * a number using the number function. 059 * <p> 060 * If the node set is empty, or if the result of converting the string values of any of the 061 * nodes to a number is NaN, then NaN is returned. 062 * 063 * @param nl The NodeList for the node-set to be evaluated. 064 * 065 * @return the maximum value found, NaN if any node cannot be converted to a number. 066 * 067 * @see <a href="http://www.exslt.org/">EXSLT</a> 068 */ 069 public static double max (NodeList nl) 070 { 071 if (nl == null || nl.getLength() == 0) 072 return Double.NaN; 073 074 double m = - Double.MAX_VALUE; 075 for (int i = 0; i < nl.getLength(); i++) 076 { 077 Node n = nl.item(i); 078 double d = toNumber(n); 079 if (Double.isNaN(d)) 080 return Double.NaN; 081 else if (d > m) 082 m = d; 083 } 084 085 return m; 086 } 087 088 /** 089 * The math:min function returns the minimum value of the nodes passed as the argument. 090 * The minimum value is defined as follows. The node set passed as an argument is sorted 091 * in ascending order as it would be by xsl:sort with a data type of number. The minimum 092 * is the result of converting the string value of the first node in this sorted list to 093 * a number using the number function. 094 * <p> 095 * If the node set is empty, or if the result of converting the string values of any of 096 * the nodes to a number is NaN, then NaN is returned. 097 * 098 * @param nl The NodeList for the node-set to be evaluated. 099 * 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 = new Double(precision).intValue(); 378 379 if (bits <= value.length()) 380 value = value.substring(0, bits); 381 382 return new Double(value).doubleValue(); 383 } 384 else 385 return Double.NaN; 386 387 } 388 389 }