1 16 package org.apache.commons.jxpath.ri.compiler; 17 18 import java.text.DecimalFormat ; 19 import java.text.DecimalFormatSymbols ; 20 import java.text.NumberFormat ; 21 import java.util.Collection ; 22 import java.util.Locale ; 23 24 import org.apache.commons.jxpath.JXPathContext; 25 import org.apache.commons.jxpath.JXPathException; 26 import org.apache.commons.jxpath.ri.Compiler; 27 import org.apache.commons.jxpath.ri.EvalContext; 28 import org.apache.commons.jxpath.ri.InfoSetUtil; 29 import org.apache.commons.jxpath.ri.model.NodePointer; 30 31 38 public class CoreFunction extends Operation { 39 40 private static final Double ZERO = new Double (0); 41 private int functionCode; 42 43 public CoreFunction(int functionCode, Expression args[]) { 44 super(args); 45 this.functionCode = functionCode; 46 } 47 48 public int getFunctionCode() { 49 return functionCode; 50 } 51 52 protected String getFunctionName() { 53 switch (functionCode) { 54 case Compiler.FUNCTION_LAST : 55 return "last"; 56 case Compiler.FUNCTION_POSITION : 57 return "position"; 58 case Compiler.FUNCTION_COUNT : 59 return "count"; 60 case Compiler.FUNCTION_ID : 61 return "id"; 62 case Compiler.FUNCTION_LOCAL_NAME : 63 return "local-name"; 64 case Compiler.FUNCTION_NAMESPACE_URI : 65 return "namespace-uri"; 66 case Compiler.FUNCTION_NAME : 67 return "name"; 68 case Compiler.FUNCTION_STRING : 69 return "string"; 70 case Compiler.FUNCTION_CONCAT : 71 return "concat"; 72 case Compiler.FUNCTION_STARTS_WITH : 73 return "starts-with"; 74 case Compiler.FUNCTION_CONTAINS : 75 return "contains"; 76 case Compiler.FUNCTION_SUBSTRING_BEFORE : 77 return "substring-before"; 78 case Compiler.FUNCTION_SUBSTRING_AFTER : 79 return "substring-after"; 80 case Compiler.FUNCTION_SUBSTRING : 81 return "substring"; 82 case Compiler.FUNCTION_STRING_LENGTH : 83 return "string-length"; 84 case Compiler.FUNCTION_NORMALIZE_SPACE : 85 return "normalize-space"; 86 case Compiler.FUNCTION_TRANSLATE : 87 return "translate"; 88 case Compiler.FUNCTION_BOOLEAN : 89 return "boolean"; 90 case Compiler.FUNCTION_NOT : 91 return "not"; 92 case Compiler.FUNCTION_TRUE : 93 return "true"; 94 case Compiler.FUNCTION_FALSE : 95 return "false"; 96 case Compiler.FUNCTION_LANG : 97 return "lang"; 98 case Compiler.FUNCTION_NUMBER : 99 return "number"; 100 case Compiler.FUNCTION_SUM : 101 return "sum"; 102 case Compiler.FUNCTION_FLOOR : 103 return "floor"; 104 case Compiler.FUNCTION_CEILING : 105 return "ceiling"; 106 case Compiler.FUNCTION_ROUND : 107 return "round"; 108 case Compiler.FUNCTION_KEY : 109 return "key"; 110 case Compiler.FUNCTION_FORMAT_NUMBER: 111 return "format-number"; 112 } 113 return "unknownFunction" + functionCode + "()"; 114 } 115 116 public Expression getArg1() { 117 return args[0]; 118 } 119 120 public Expression getArg2() { 121 return args[1]; 122 } 123 124 public Expression getArg3() { 125 return args[2]; 126 } 127 128 public int getArgumentCount() { 129 if (args == null) { 130 return 0; 131 } 132 return args.length; 133 } 134 135 140 public boolean computeContextDependent() { 141 if (super.computeContextDependent()) { 142 return true; 143 } 144 145 switch(functionCode) { 146 case Compiler.FUNCTION_LAST: 147 case Compiler.FUNCTION_POSITION: 148 return true; 149 150 case Compiler.FUNCTION_BOOLEAN: 151 case Compiler.FUNCTION_LOCAL_NAME: 152 case Compiler.FUNCTION_NAME: 153 case Compiler.FUNCTION_NAMESPACE_URI: 154 case Compiler.FUNCTION_STRING: 155 case Compiler.FUNCTION_LANG: 156 case Compiler.FUNCTION_NUMBER: 157 return args == null || args.length == 0; 158 159 case Compiler.FUNCTION_COUNT: 160 case Compiler.FUNCTION_ID: 161 case Compiler.FUNCTION_CONCAT: 162 case Compiler.FUNCTION_STARTS_WITH: 163 case Compiler.FUNCTION_CONTAINS: 164 case Compiler.FUNCTION_SUBSTRING_BEFORE: 165 case Compiler.FUNCTION_SUBSTRING_AFTER: 166 case Compiler.FUNCTION_SUBSTRING: 167 case Compiler.FUNCTION_STRING_LENGTH: 168 case Compiler.FUNCTION_NORMALIZE_SPACE: 169 case Compiler.FUNCTION_TRANSLATE: 170 case Compiler.FUNCTION_NOT: 171 case Compiler.FUNCTION_TRUE: 172 case Compiler.FUNCTION_FALSE: 173 case Compiler.FUNCTION_SUM: 174 case Compiler.FUNCTION_FLOOR: 175 case Compiler.FUNCTION_CEILING: 176 case Compiler.FUNCTION_ROUND: 177 return false; 178 179 case Compiler.FUNCTION_FORMAT_NUMBER: 180 return args != null && args.length == 2; 181 } 182 183 return false; 184 } 185 186 public String toString() { 187 StringBuffer buffer = new StringBuffer (); 188 buffer.append(getFunctionName()); 189 buffer.append('('); 190 Expression args[] = getArguments(); 191 if (args != null) { 192 for (int i = 0; i < args.length; i++) { 193 if (i > 0) { 194 buffer.append(", "); 195 } 196 buffer.append(args[i]); 197 } 198 } 199 buffer.append(')'); 200 return buffer.toString(); 201 } 202 203 public Object compute(EvalContext context) { 204 return computeValue(context); 205 } 206 207 210 public Object computeValue(EvalContext context) { 211 switch (functionCode) { 212 case Compiler.FUNCTION_LAST : 213 return functionLast(context); 214 case Compiler.FUNCTION_POSITION : 215 return functionPosition(context); 216 case Compiler.FUNCTION_COUNT : 217 return functionCount(context); 218 case Compiler.FUNCTION_LANG : 219 return functionLang(context); 220 case Compiler.FUNCTION_ID : 221 return functionID(context); 222 case Compiler.FUNCTION_LOCAL_NAME : 223 return functionLocalName(context); 224 case Compiler.FUNCTION_NAMESPACE_URI : 225 return functionNamespaceURI(context); 226 case Compiler.FUNCTION_NAME : 227 return functionName(context); 228 case Compiler.FUNCTION_STRING : 229 return functionString(context); 230 case Compiler.FUNCTION_CONCAT : 231 return functionConcat(context); 232 case Compiler.FUNCTION_STARTS_WITH : 233 return functionStartsWith(context); 234 case Compiler.FUNCTION_CONTAINS : 235 return functionContains(context); 236 case Compiler.FUNCTION_SUBSTRING_BEFORE : 237 return functionSubstringBefore(context); 238 case Compiler.FUNCTION_SUBSTRING_AFTER : 239 return functionSubstringAfter(context); 240 case Compiler.FUNCTION_SUBSTRING : 241 return functionSubstring(context); 242 case Compiler.FUNCTION_STRING_LENGTH : 243 return functionStringLength(context); 244 case Compiler.FUNCTION_NORMALIZE_SPACE : 245 return functionNormalizeSpace(context); 246 case Compiler.FUNCTION_TRANSLATE : 247 return functionTranslate(context); 248 case Compiler.FUNCTION_BOOLEAN : 249 return functionBoolean(context); 250 case Compiler.FUNCTION_NOT : 251 return functionNot(context); 252 case Compiler.FUNCTION_TRUE : 253 return functionTrue(context); 254 case Compiler.FUNCTION_FALSE : 255 return functionFalse(context); 256 case Compiler.FUNCTION_NULL : 257 return functionNull(context); 258 case Compiler.FUNCTION_NUMBER : 259 return functionNumber(context); 260 case Compiler.FUNCTION_SUM : 261 return functionSum(context); 262 case Compiler.FUNCTION_FLOOR : 263 return functionFloor(context); 264 case Compiler.FUNCTION_CEILING : 265 return functionCeiling(context); 266 case Compiler.FUNCTION_ROUND : 267 return functionRound(context); 268 case Compiler.FUNCTION_KEY : 269 return functionKey(context); 270 case Compiler.FUNCTION_FORMAT_NUMBER : 271 return functionFormatNumber(context); 272 } 273 return null; 274 } 275 276 protected Object functionLast(EvalContext context) { 277 assertArgCount(0); 278 int old = context.getCurrentPosition(); 281 context.reset(); 282 int count = 0; 283 while (context.nextNode()) { 284 count++; 285 } 286 287 if (old != 0) { 289 context.setPosition(old); 290 } 291 return new Double (count); 292 } 293 294 protected Object functionPosition(EvalContext context) { 295 assertArgCount(0); 296 return new Integer (context.getCurrentPosition()); 297 } 298 299 protected Object functionCount(EvalContext context) { 300 assertArgCount(1); 301 Expression arg1 = getArg1(); 302 int count = 0; 303 Object value = arg1.compute(context); 304 if (value instanceof NodePointer) { 305 value = ((NodePointer) value).getValue(); 306 } 307 if (value instanceof EvalContext) { 308 EvalContext ctx = (EvalContext) value; 309 while (ctx.hasNext()) { 310 ctx.next(); 311 count++; 312 } 313 } 314 else if (value instanceof Collection ) { 315 count = ((Collection ) value).size(); 316 } 317 else if (value == null) { 318 count = 0; 319 } 320 else { 321 count = 1; 322 } 323 return new Double (count); 324 } 325 326 protected Object functionLang(EvalContext context) { 327 assertArgCount(1); 328 String lang = InfoSetUtil.stringValue(getArg1().computeValue(context)); 329 NodePointer pointer = (NodePointer) context.getSingleNodePointer(); 330 if (pointer == null) { 331 return Boolean.FALSE; 332 } 333 return pointer.isLanguage(lang) ? Boolean.TRUE : Boolean.FALSE; 334 } 335 336 protected Object functionID(EvalContext context) { 337 assertArgCount(1); 338 String id = InfoSetUtil.stringValue(getArg1().computeValue(context)); 339 JXPathContext jxpathContext = context.getJXPathContext(); 340 NodePointer pointer = (NodePointer) jxpathContext.getContextPointer(); 341 return pointer.getPointerByID(jxpathContext, id); 342 } 343 344 protected Object functionKey(EvalContext context) { 345 assertArgCount(2); 346 String key = InfoSetUtil.stringValue(getArg1().computeValue(context)); 347 String value = InfoSetUtil.stringValue(getArg2().computeValue(context)); 348 JXPathContext jxpathContext = context.getJXPathContext(); 349 NodePointer pointer = (NodePointer) jxpathContext.getContextPointer(); 350 return pointer.getPointerByKey(jxpathContext, key, value); 351 } 352 353 protected Object functionNamespaceURI(EvalContext context) { 354 if (getArgumentCount() == 0) { 355 NodePointer ptr = context.getCurrentNodePointer(); 356 String str = ptr.getNamespaceURI(); 357 return str == null ? "" : str; 358 } 359 assertArgCount(1); 360 Object set = getArg1().compute(context); 361 if (set instanceof EvalContext) { 362 EvalContext ctx = (EvalContext) set; 363 if (ctx.hasNext()) { 364 NodePointer ptr = (NodePointer) ctx.next(); 365 String str = ptr.getNamespaceURI(); 366 return str == null ? "" : str; 367 } 368 } 369 return ""; 370 } 371 372 protected Object functionLocalName(EvalContext context) { 373 if (getArgumentCount() == 0) { 374 NodePointer ptr = context.getCurrentNodePointer(); 375 return ptr.getName().getName(); 376 } 377 assertArgCount(1); 378 Object set = getArg1().compute(context); 379 if (set instanceof EvalContext) { 380 EvalContext ctx = (EvalContext) set; 381 if (ctx.hasNext()) { 382 NodePointer ptr = (NodePointer) ctx.next(); 383 return ptr.getName().getName(); 384 } 385 } 386 return ""; 387 } 388 389 protected Object functionName(EvalContext context) { 390 if (getArgumentCount() == 0) { 391 NodePointer ptr = context.getCurrentNodePointer(); 392 return ptr.getName().toString(); 393 } 394 assertArgCount(1); 395 Object set = getArg1().compute(context); 396 if (set instanceof EvalContext) { 397 EvalContext ctx = (EvalContext) set; 398 if (ctx.hasNext()) { 399 NodePointer ptr = (NodePointer) ctx.next(); 400 return ptr.getName().toString(); 401 } 402 } 403 return ""; 404 } 405 406 protected Object functionString(EvalContext context) { 407 if (getArgumentCount() == 0) { 408 return InfoSetUtil.stringValue(context.getCurrentNodePointer()); 409 } 410 assertArgCount(1); 411 return InfoSetUtil.stringValue(getArg1().computeValue(context)); 412 } 413 414 protected Object functionConcat(EvalContext context) { 415 if (getArgumentCount() < 2) { 416 assertArgCount(2); 417 } 418 StringBuffer buffer = new StringBuffer (); 419 Expression args[] = getArguments(); 420 for (int i = 0; i < args.length; i++) { 421 buffer.append(InfoSetUtil.stringValue(args[i].compute(context))); 422 } 423 return buffer.toString(); 424 } 425 426 protected Object functionStartsWith(EvalContext context) { 427 assertArgCount(2); 428 String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context)); 429 String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context)); 430 return s1.startsWith(s2) ? Boolean.TRUE : Boolean.FALSE; 431 } 432 433 protected Object functionContains(EvalContext context) { 434 assertArgCount(2); 435 String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context)); 436 String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context)); 437 return s1.indexOf(s2) != -1 ? Boolean.TRUE : Boolean.FALSE; 438 } 439 440 protected Object functionSubstringBefore(EvalContext context) { 441 assertArgCount(2); 442 String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context)); 443 String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context)); 444 int index = s1.indexOf(s2); 445 if (index == -1) { 446 return ""; 447 } 448 return s1.substring(0, index); 449 } 450 451 protected Object functionSubstringAfter(EvalContext context) { 452 assertArgCount(2); 453 String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context)); 454 String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context)); 455 int index = s1.indexOf(s2); 456 if (index == -1) { 457 return ""; 458 } 459 return s1.substring(index + s2.length()); 460 } 461 462 protected Object functionSubstring(EvalContext context) { 463 int ac = getArgumentCount(); 464 if (ac != 2 && ac != 3) { 465 assertArgCount(2); 466 } 467 468 String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context)); 469 double from = InfoSetUtil.doubleValue(getArg2().computeValue(context)); 470 if (Double.isNaN(from)) { 471 return ""; 472 } 473 474 from = Math.round(from); 475 if (ac == 2) { 476 if (from < 1) { 477 from = 1; 478 } 479 return s1.substring((int) from - 1); 480 } 481 else { 482 double length = 483 InfoSetUtil.doubleValue(getArg3().computeValue(context)); 484 length = Math.round(length); 485 if (length < 0) { 486 return ""; 487 } 488 489 double to = from + length; 490 if (to < 1) { 491 return ""; 492 } 493 494 if (to > s1.length() + 1) { 495 if (from < 1) { 496 from = 1; 497 } 498 return s1.substring((int) from - 1); 499 } 500 501 if (from < 1) { 502 from = 1; 503 } 504 return s1.substring((int) from - 1, (int) (to - 1)); 505 } 506 } 507 508 protected Object functionStringLength(EvalContext context) { 509 String s; 510 if (getArgumentCount() == 0) { 511 s = InfoSetUtil.stringValue(context.getCurrentNodePointer()); 512 } 513 else { 514 assertArgCount(1); 515 s = InfoSetUtil.stringValue(getArg1().computeValue(context)); 516 } 517 return new Double (s.length()); 518 } 519 520 protected Object functionNormalizeSpace(EvalContext context) { 521 assertArgCount(1); 522 String s = InfoSetUtil.stringValue(getArg1().computeValue(context)); 523 char chars[] = s.toCharArray(); 524 int out = 0; 525 int phase = 0; 526 for (int in = 0; in < chars.length; in++) { 527 switch(chars[in]) { 528 case 0x20: 529 case 0x9: 530 case 0xD: 531 case 0xA: 532 if (phase == 0) { ; 534 } 535 else if (phase == 1) { phase = 2; 537 chars[out++] = ' '; 538 } 539 break; 540 default: 541 chars[out++] = chars[in]; 542 phase = 1; 543 } 544 } 545 if (phase == 2) { out--; 547 } 548 return new String (chars, 0, out); 549 } 550 551 protected Object functionTranslate(EvalContext context) { 552 assertArgCount(3); 553 String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context)); 554 String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context)); 555 String s3 = InfoSetUtil.stringValue(getArg3().computeValue(context)); 556 char chars[] = s1.toCharArray(); 557 int out = 0; 558 for (int in = 0; in < chars.length; in++) { 559 char c = chars[in]; 560 int inx = s2.indexOf(c); 561 if (inx != -1) { 562 if (inx < s3.length()) { 563 chars[out++] = s3.charAt(inx); 564 } 565 } 566 else { 567 chars[out++] = c; 568 } 569 } 570 return new String (chars, 0, out); 571 } 572 573 protected Object functionBoolean(EvalContext context) { 574 assertArgCount(1); 575 return InfoSetUtil.booleanValue(getArg1().computeValue(context)) 576 ? Boolean.TRUE 577 : Boolean.FALSE; 578 } 579 580 protected Object functionNot(EvalContext context) { 581 assertArgCount(1); 582 return InfoSetUtil.booleanValue(getArg1().computeValue(context)) 583 ? Boolean.FALSE 584 : Boolean.TRUE; 585 } 586 587 protected Object functionTrue(EvalContext context) { 588 assertArgCount(0); 589 return Boolean.TRUE; 590 } 591 592 protected Object functionFalse(EvalContext context) { 593 assertArgCount(0); 594 return Boolean.FALSE; 595 } 596 597 protected Object functionNull(EvalContext context) { 598 assertArgCount(0); 599 return null; 600 } 601 602 protected Object functionNumber(EvalContext context) { 603 if (getArgumentCount() == 0) { 604 return InfoSetUtil.number(context.getCurrentNodePointer()); 605 } 606 assertArgCount(1); 607 return InfoSetUtil.number(getArg1().computeValue(context)); 608 } 609 610 protected Object functionSum(EvalContext context) { 611 assertArgCount(1); 612 Object v = getArg1().compute(context); 613 if (v == null) { 614 return ZERO; 615 } 616 else if (v instanceof EvalContext) { 617 double sum = 0.0; 618 EvalContext ctx = (EvalContext) v; 619 while (ctx.hasNext()) { 620 NodePointer ptr = (NodePointer) ctx.next(); 621 sum += InfoSetUtil.doubleValue(ptr); 622 } 623 return new Double (sum); 624 } 625 throw new JXPathException( 626 "Invalid argument type for 'sum': " + v.getClass().getName()); 627 } 628 629 protected Object functionFloor(EvalContext context) { 630 assertArgCount(1); 631 double v = InfoSetUtil.doubleValue(getArg1().computeValue(context)); 632 return new Double (Math.floor(v)); 633 } 634 635 protected Object functionCeiling(EvalContext context) { 636 assertArgCount(1); 637 double v = InfoSetUtil.doubleValue(getArg1().computeValue(context)); 638 return new Double (Math.ceil(v)); 639 } 640 641 protected Object functionRound(EvalContext context) { 642 assertArgCount(1); 643 double v = InfoSetUtil.doubleValue(getArg1().computeValue(context)); 644 return new Double (Math.round(v)); 645 } 646 647 private Object functionFormatNumber(EvalContext context) { 648 int ac = getArgumentCount(); 649 if (ac != 2 && ac != 3) { 650 assertArgCount(2); 651 } 652 653 double number = 654 InfoSetUtil.doubleValue(getArg1().computeValue(context)); 655 String pattern = 656 InfoSetUtil.stringValue(getArg2().computeValue(context)); 657 658 DecimalFormatSymbols symbols = null; 659 if (ac == 3) { 660 String symbolsName = 661 InfoSetUtil.stringValue(getArg3().computeValue(context)); 662 symbols = 663 context.getJXPathContext().getDecimalFormatSymbols(symbolsName); 664 } 665 else { 666 NodePointer pointer = context.getCurrentNodePointer(); 667 Locale locale; 668 if (pointer != null) { 669 locale = pointer.getLocale(); 670 } 671 else { 672 locale = context.getJXPathContext().getLocale(); 673 } 674 symbols = new DecimalFormatSymbols (locale); 675 } 676 677 DecimalFormat format = (DecimalFormat ) NumberFormat.getInstance(); 678 format.setDecimalFormatSymbols(symbols); 679 format.applyLocalizedPattern(pattern); 680 return format.format(number); 681 } 682 683 private void assertArgCount(int count) { 684 if (getArgumentCount() != count) { 685 throw new JXPathException("Incorrect number of argument: " + this); 686 } 687 } 688 } | Popular Tags |