1 28 29 package com.caucho.xpath; 30 31 import com.caucho.log.Log; 32 import com.caucho.server.util.CauchoSystem; 33 import com.caucho.util.CharBuffer; 34 import com.caucho.util.IntMap; 35 import com.caucho.util.L10N; 36 import com.caucho.xml.XmlChar; 37 import com.caucho.xpath.expr.*; 38 import com.caucho.xpath.functions.BaseURI; 39 import com.caucho.xpath.functions.ResolveURI; 40 import com.caucho.xpath.functions.Trace; 41 import com.caucho.xpath.pattern.*; 42 43 import org.w3c.dom.Node ; 44 45 import java.lang.reflect.Constructor ; 46 import java.lang.reflect.Method ; 47 import java.lang.reflect.Modifier ; 48 import java.util.ArrayList ; 49 import java.util.HashMap ; 50 import java.util.logging.Logger ; 51 52 53 56 class XPathParser { 57 private static final Logger log = Log.open(XPathParser.class); 58 private static final L10N L = new L10N(XPathParser.class); 59 60 private final static int ANCESTOR_AXIS = 0; 61 private final static int ANCESTOR_OR_SELF_AXIS = ANCESTOR_AXIS + 1; 62 private final static int ATTRIBUTE_AXIS = ANCESTOR_OR_SELF_AXIS + 1; 63 private final static int CHILD_AXIS = ATTRIBUTE_AXIS + 1; 64 private final static int DESCENDANT_AXIS = CHILD_AXIS + 1; 65 private final static int DESCENDANT_OR_SELF_AXIS = DESCENDANT_AXIS + 1; 66 private final static int FOLLOWING_AXIS = DESCENDANT_OR_SELF_AXIS + 1; 67 private final static int FOLLOWING_SIBLING_AXIS = FOLLOWING_AXIS + 1; 68 private final static int NAMESPACE_AXIS = FOLLOWING_SIBLING_AXIS + 1; 69 private final static int PARENT_AXIS = NAMESPACE_AXIS + 1; 70 private final static int PRECEDING_AXIS = PARENT_AXIS + 1; 71 private final static int PRECEDING_SIBLING_AXIS = PRECEDING_AXIS + 1; 72 private final static int SELF_AXIS = PRECEDING_SIBLING_AXIS + 1; 73 74 private final static int TEXT = Expr.LAST_FUN + 1; 75 private final static int COMMENT = TEXT + 1; 76 private final static int ER = COMMENT + 1; 77 private final static int PI = ER + 1; 78 private final static int NODE = PI + 1; 79 private final static int CURRENT = NODE + 1; 80 private final static int NODE_TEXT = CURRENT + 1; 81 private final static int CONTEXT = NODE_TEXT + 1; 82 83 private static IntMap exprFunctions; 84 private static IntMap axisMap; 85 86 private static HashMap <String ,Constructor > _exprFunctions; 87 88 private CharBuffer tag = new CharBuffer(); 89 90 private String _string; 91 private int index; 92 private int peek; 93 94 private NamespaceContext _namespace; 95 96 XPathParser(String string, NamespaceContext namespace) 97 { 98 _string = string; 99 _namespace = namespace; 100 } 101 102 105 AbstractPattern parseSelect() 106 throws XPathParseException 107 { 108 AbstractPattern top = new FromContext(); 109 110 AbstractPattern pattern = parseUnion(parseTop(top), top); 111 112 if (index < _string.length()) 113 throw error(L.l("unexpected character at `{0}'", badChar(read()))); 114 115 return pattern; 116 } 117 118 121 AbstractPattern parseMatch() 122 throws XPathParseException 123 { 124 AbstractPattern root = new FromAny(); 125 AbstractPattern pattern = parseUnion(parseTop(root), root); 126 127 if (index < _string.length()) 128 throw error(L.l("unexpected character at `{0}'", badChar(read()))); 129 130 return pattern; 131 } 132 133 134 137 Expr parseExpr() 138 throws XPathParseException 139 { 140 Expr expr = parseExpr(null, null); 141 142 if (index < _string.length()) 143 throw error(L.l("unexpected character at `{0}'", badChar(read()))); 144 145 return expr; 146 } 147 148 private AbstractPattern parseStep(AbstractPattern root) 149 throws XPathParseException 150 { 151 return parseUnion(parseTop(root), root); 152 } 153 154 private AbstractPattern parseUnion(AbstractPattern left, AbstractPattern root) 155 throws XPathParseException 156 { 157 int ch = skipWhitespace(read()); 158 159 while (ch >= 0) { 160 if (ch == '|') { 161 AbstractPattern tail = parseUnion(parseTop(root), root); 162 left = new UnionPattern(left, tail); 163 } else 164 break; 165 166 for (ch = read(); XmlChar.isWhitespace(ch); ch = read()) { 167 } 168 } 169 170 unread(); 171 172 return left; 173 } 174 175 183 private AbstractPattern parseTop(AbstractPattern pattern) 184 throws XPathParseException 185 { 186 int ch = skipWhitespace(read()); 187 unread(); 188 189 if (ch == '(') { 190 Expr expr = parseTerm(pattern, pattern); 191 192 if (expr instanceof NodeSetExpr) { 195 AbstractPattern nodeSet = ((NodeSetExpr) expr).getPattern(); 196 197 if (nodeSet.isAscending()) 198 return nodeSet; 199 } 200 201 return new FromExpr(null, expr); 202 } 203 else 204 return parseTerm(pattern, pattern).toNodeList(); 205 } 206 207 private AbstractPattern parseBasisTop(AbstractPattern pattern) 208 throws XPathParseException 209 { 210 int ch; 211 212 ch = skipWhitespace(read()); 213 if (ch == '/') { 214 ch = read(); 215 if (ch == '/') { 216 pattern = new FromRoot(); 217 pattern = new FromDescendants(pattern, false); 218 pattern = parseBasis(pattern); 219 pattern = parseFilter(pattern); 220 pattern = parsePath(pattern); 221 222 return pattern; 223 } 224 pattern = new FromRoot(); 225 ch = skipWhitespace(ch); 226 227 if (ch == -1) 228 return pattern; 229 } 230 231 unread(); 232 233 if (pattern == null) 234 pattern = new FromContext(); 235 236 pattern = parseBasis(pattern); 237 pattern = parseFilter(pattern); 238 239 return parsePath(pattern); 240 } 241 242 245 private AbstractPattern parsePath(AbstractPattern pattern) 246 throws XPathParseException 247 { 248 int ch = skipWhitespace(read()); 249 250 while (ch == '/') { 251 ch = read(); 252 253 if (ch == '/') { 254 pattern = new FromDescendants(pattern, false); 255 pattern = parseBasis(pattern); 256 pattern = parseFilter(pattern); 257 } 258 else { 259 unread(); 260 pattern = parseBasis(pattern); 261 pattern = parseFilter(pattern); 262 } 263 264 ch = skipWhitespace(read()); 265 } 266 267 unread(); 268 269 return pattern; 270 } 271 272 275 private AbstractPattern parseFilter(AbstractPattern pattern) 276 throws XPathParseException 277 { 278 int ch = skipWhitespace(read()); 279 while (ch == '[') { 280 AbstractPattern context = new FromContext(); 281 Expr expr = parseExpr(context, pattern); 282 pattern = new FilterPattern(pattern, expr); 283 284 ch = skipWhitespace(read()); 285 if (ch != ']') 286 throw error(L.l("expected `{0}' at {1}", "]", badChar(ch))); 287 288 ch = skipWhitespace(read()); 289 } 290 unread(); 291 292 return pattern; 293 } 294 295 303 private AbstractPattern parseBasis(AbstractPattern pattern) 304 throws XPathParseException 305 { 306 boolean fromChildren = true; 307 int ch = skipWhitespace(read()); 308 309 int nodeType = Node.ELEMENT_NODE; 310 String namespace = null; 311 tag.clear(); 312 313 if (ch == '@') { 314 if (pattern instanceof FromDescendants) 315 pattern = NodeTypePattern.create(pattern, NodeTypePattern.NODE); 316 317 pattern = new FromAttributes(pattern); 318 nodeType = Node.ATTRIBUTE_NODE; 319 fromChildren = false; 320 ch = read(); 321 } 322 else if (ch == '.') { 323 ch = read(); 324 if (ch == '.') 325 return NodeTypePattern.create(new FromParent(pattern), 326 NodeTypePattern.NODE); 327 else { 328 unread(); 329 if (pattern != null) 330 return pattern; 331 else 332 return NodeTypePattern.create(new FromSelf(pattern), NodeTypePattern.ANY); 333 } 334 } 335 else if (ch == '(') { 336 Expr expr = parseExpr(null, null); 338 339 if ((ch = read()) != ')') 340 throw error(L.l("expected `{0}' at {1}", ")", badChar(ch))); 341 342 return new FromExpr(pattern, expr); 343 } 344 345 if (ch == '*') { 346 tag.append('*'); 347 } 348 349 else if (XmlChar.isNameStart(ch)) { 350 for (; XmlChar.isNameChar(ch); ch = read()) 351 tag.append((char) ch); 352 353 if (ch == '*' && tag.endsWith(":")) 354 tag.append('*'); 355 else 356 unread(); 357 } 358 else 359 unread(); 360 361 String name = tag.toString(); 362 363 if (name.equals("")) 364 throw error(L.l("expected name at {0}", badChar(ch))); 365 366 return parseAxis(pattern, name, fromChildren, nodeType); 367 } 368 369 private AbstractPattern parseAxis(AbstractPattern pattern, String name, 370 boolean fromChildren, int nodeType) 371 throws XPathParseException 372 { 373 String axis = ""; 374 int axisIndex = name.indexOf("::"); 375 376 if (axisIndex >= 0 && nodeType != Node.ATTRIBUTE_NODE) { 377 axis = name.substring(0, axisIndex); 378 name = name.substring(axisIndex + 2); 379 } 380 381 if (pattern instanceof FromDescendants) 382 return parseNodeTest(pattern, name, false, Node.ELEMENT_NODE); 383 384 switch (axisMap.get(axis)) { 385 case ANCESTOR_AXIS: 386 return parseNodeTest(new FromAncestors(pattern, false), 387 name, false, Node.ELEMENT_NODE); 388 389 case ANCESTOR_OR_SELF_AXIS: 390 return parseNodeTest(new FromAncestors(pattern, true), 391 name, false, Node.ELEMENT_NODE); 392 393 case ATTRIBUTE_AXIS: 394 return parseNodeTest(new FromAttributes(pattern), 395 name, false, Node.ATTRIBUTE_NODE); 396 397 case CHILD_AXIS: 398 return parseNodeTest(new FromChildren(pattern), 399 name, false, Node.ELEMENT_NODE); 400 401 case DESCENDANT_AXIS: 402 return parseNodeTest(new FromDescendants(pattern, false), 403 name, false, Node.ELEMENT_NODE); 404 405 case DESCENDANT_OR_SELF_AXIS: 406 return parseNodeTest(new FromDescendants(pattern, true), 407 name, false, Node.ELEMENT_NODE); 408 409 case FOLLOWING_AXIS: 410 return parseNodeTest(new FromNext(pattern), 411 name, false, Node.ELEMENT_NODE); 412 413 case FOLLOWING_SIBLING_AXIS: 414 return parseNodeTest(new FromNextSibling(pattern), 415 name, false, Node.ELEMENT_NODE); 416 417 case NAMESPACE_AXIS: 418 return parseNodeTest(new FromNamespace(pattern), 419 name, false, Node.ATTRIBUTE_NODE); 420 421 case PARENT_AXIS: 422 return parseNodeTest(new FromParent(pattern), 423 name, false, Node.ELEMENT_NODE); 424 425 case PRECEDING_AXIS: 426 return parseNodeTest(new FromPrevious(pattern), 427 name, false, Node.ELEMENT_NODE); 428 429 case PRECEDING_SIBLING_AXIS: 430 return parseNodeTest(new FromPreviousSibling(pattern), 431 name, false, Node.ELEMENT_NODE); 432 433 case SELF_AXIS: 434 return parseNodeTest(new FromSelf(pattern), 435 name, false, Node.ELEMENT_NODE); 436 437 default: 438 return parseNodeTest(pattern, name, fromChildren, nodeType); 439 } 440 } 441 442 449 private AbstractPattern parseNodeTest(AbstractPattern pattern, String name, 450 boolean fromChildren, int nodeType) 451 throws XPathParseException 452 { 453 int ch = skipWhitespace(read()); 454 455 AbstractPattern tagPattern; 456 457 if (ch == '(') { 458 Expr expr = parseFunction(pattern, pattern, name, fromChildren); 459 return expr.toNodeList(); 460 } 461 else if (ch == '{') { 462 tag.clear(); 463 while ((ch = read()) >= 0 && ch != '}') 464 tag.append((char) ch); 465 String url = tag.toString(); 466 tag.clear(); 467 for (ch = read(); XmlChar.isNameChar(ch); ch = read()) 468 tag.append((char) ch); 469 470 pattern = new NSNamePattern(pattern, url, tag.toString(), nodeType); 471 } 472 else { 473 if (fromChildren) 474 pattern = new FromChildren(pattern); 475 476 if (name.equals("*")) 477 pattern = NodeTypePattern.create(pattern, nodeType); 478 else if (name.endsWith(":*")) { 479 pattern = new NamespacePattern(pattern, 480 name.substring(0, name.length() - 2), 481 nodeType); 482 } 483 else { 484 int p = name.indexOf(':'); 485 String ns = null; 486 String local = name; 487 488 if (p > 0) { 489 String prefix = name.substring(0, p); 490 ns = NamespaceContext.find(_namespace, prefix); 491 local = name.substring(p + 1); 492 } 493 else if (nodeType != Node.ATTRIBUTE_NODE) 494 ns = _namespace.find(_namespace, ""); 495 else 496 ns = null; 498 if (ns == null) 499 pattern = new NodePattern(pattern, name, nodeType); 500 else 501 pattern = new NSNamePattern(pattern, ns, local, nodeType); 502 } 503 } 504 unread(); 505 506 return pattern; 507 } 508 509 512 Expr parseExpr(AbstractPattern parent, AbstractPattern listParent) 513 throws XPathParseException 514 { 515 peek = -1; 516 Expr left = parseTerm(parent, listParent); 517 518 while (true) { 519 int token = scanToken(); 520 switch (token) { 521 case Expr.OR: 522 left = parseOrExpr(token, left, parseTerm(parent, listParent), 523 parent, listParent); 524 break; 525 526 case Expr.AND: 527 left = parseAndExpr(token, left, parseTerm(parent, listParent), 528 parent, listParent); 529 break; 530 531 case Expr.EQ: case Expr.NEQ: case Expr.LT: 532 case Expr.LE: case Expr.GT: case Expr.GE: 533 left = parseCmpExpr(token, left, parseTerm(parent, listParent), 534 parent, listParent); 535 break; 536 537 case Expr.ADD: case Expr.SUB: 538 left = parseAddExpr(token, left, parseTerm(parent, listParent), 539 parent, listParent); 540 break; 541 542 case Expr.MUL: case Expr.DIV: case Expr.QUO: case Expr.MOD: 543 left = parseMulExpr(token, left, parseTerm(parent, listParent), 544 parent, listParent); 545 break; 546 547 default: 548 return left; 549 } 550 } 551 } 552 553 557 private Expr parseOrExpr(int code, Expr left, Expr right, 558 AbstractPattern parent, AbstractPattern listParent) 559 throws XPathParseException 560 { 561 while (true) { 562 int token = scanToken(); 563 switch (token) { 564 case Expr.OR: 565 left = new BooleanExpr(code, left, right); 566 code = token; 567 right = parseTerm(parent, listParent); 568 break; 569 570 case Expr.AND: 571 right = parseAndExpr(token, right, parseTerm(parent, listParent), 572 parent, listParent); 573 break; 574 575 case Expr.EQ: case Expr.NEQ: case Expr.LT: 576 case Expr.LE: case Expr.GT: case Expr.GE: 577 right = parseCmpExpr(token, right, parseTerm(parent, listParent), 578 parent, listParent); 579 break; 580 581 case Expr.ADD: case Expr.SUB: 582 right = parseAddExpr(token, right, parseTerm(parent, listParent), 583 parent, listParent); 584 break; 585 586 case Expr.MUL: case Expr.DIV: case Expr.QUO: case Expr.MOD: 587 right = parseMulExpr(token, right, parseTerm(parent, listParent), 588 parent, listParent); 589 break; 590 591 default: 592 undoToken(token); 593 return new BooleanExpr(code, left, right); 594 } 595 } 596 } 597 598 602 private Expr parseAndExpr(int code, Expr left, Expr right, 603 AbstractPattern parent, AbstractPattern listParent) 604 throws XPathParseException 605 { 606 while (true) { 607 int token = scanToken(); 608 switch (token) { 609 case Expr.AND: 610 left = new BooleanExpr(code, left, right); 611 code = token; 612 right = parseTerm(parent, listParent); 613 break; 614 615 case Expr.EQ: case Expr.NEQ: case Expr.LT: 616 case Expr.LE: case Expr.GT: case Expr.GE: 617 right = parseCmpExpr(token, right, parseTerm(parent, listParent), 618 parent, listParent); 619 break; 620 621 case Expr.ADD: case Expr.SUB: 622 right = parseAddExpr(token, right, parseTerm(parent, listParent), 623 parent, listParent); 624 break; 625 626 case Expr.MUL: case Expr.DIV: case Expr.QUO: case Expr.MOD: 627 right = parseMulExpr(token, right, parseTerm(parent, listParent), 628 parent, listParent); 629 break; 630 631 default: 632 undoToken(token); 633 return new BooleanExpr(code, left, right); 634 } 635 } 636 } 637 638 642 private Expr parseCmpExpr(int code, Expr left, Expr right, 643 AbstractPattern parent, AbstractPattern listParent) 644 throws XPathParseException 645 { 646 while (true) { 647 int token = scanToken(); 648 switch (token) { 649 case Expr.EQ: case Expr.NEQ: case Expr.LT: 650 case Expr.LE: case Expr.GT: case Expr.GE: 651 left = new BooleanExpr(code, left, right); 652 code = token; 653 right = parseTerm(parent, listParent); 654 break; 655 656 case Expr.ADD: case Expr.SUB: 657 right = parseAddExpr(token, right, parseTerm(parent, listParent), 658 parent, listParent); 659 break; 660 661 case Expr.MUL: case Expr.DIV: case Expr.QUO: case Expr.MOD: 662 right = parseMulExpr(token, right, parseTerm(parent, listParent), 663 parent, listParent); 664 break; 665 666 default: 667 undoToken(token); 668 return new BooleanExpr(code, left, right); 669 } 670 } 671 } 672 673 677 private Expr parseAddExpr(int code, Expr left, Expr right, 678 AbstractPattern parent, AbstractPattern listParent) 679 throws XPathParseException 680 { 681 while (true) { 682 int token = scanToken(); 683 switch (token) { 684 case Expr.ADD: case Expr.SUB: 685 left = new NumericExpr(code, left, right); 686 code = token; 687 right = parseTerm(parent, listParent); 688 break; 689 690 case Expr.MUL: case Expr.DIV: case Expr.QUO: case Expr.MOD: 691 right = parseMulExpr(token, right, parseTerm(parent, listParent), 692 parent, listParent); 693 break; 694 695 default: 696 undoToken(token); 697 return new NumericExpr(code, left, right); 698 } 699 } 700 } 701 702 706 private Expr parseMulExpr(int code, Expr left, Expr right, 707 AbstractPattern parent, AbstractPattern listParent) 708 throws XPathParseException 709 { 710 while (true) { 711 int token = scanToken(); 712 switch (token) { 713 case Expr.MUL: case Expr.DIV: case Expr.QUO: case Expr.MOD: 714 left = new NumericExpr(code, left, right); 715 code = token; 716 right = parseTerm(parent, listParent); 717 break; 718 719 default: 720 undoToken(token); 721 return new NumericExpr(code, left, right); 722 } 723 } 724 } 725 726 729 private Expr parseTerm(AbstractPattern parent, AbstractPattern listParent) 730 throws XPathParseException 731 { 732 int ch = skipWhitespace(read()); 733 unread(); 734 Expr expr = parseSimpleTerm(parent, listParent); 735 736 int nextCh = skipWhitespace(read()); 737 unread(); 738 if (nextCh == '/' || nextCh == '[') { 739 AbstractPattern pattern = expr.toNodeList(); 740 741 if (ch == '(' && ! pattern.isStrictlyAscending()) 742 pattern = new FromExpr(null, expr); 743 744 return NodeSetExpr.create(parseUnion(parsePath(parseFilter(pattern)), 745 pattern)); 746 } 747 else if (nextCh == '|') { 748 AbstractPattern pattern = expr.toNodeList(); 749 750 return NodeSetExpr.create(parseUnion(parsePath(parseFilter(pattern)), 751 listParent)); 752 } 753 else 754 return expr; 755 } 756 757 764 private Expr parseSimpleTerm(AbstractPattern parent, AbstractPattern listParent) 765 throws XPathParseException 766 { 767 int ch = read(); 768 769 ch = skipWhitespace(ch); 770 771 switch (ch) { 772 case '.': 773 ch = read(); 774 unread(); 775 unread(); 776 if (! ('0' <= ch && ch <= '9')) { 777 return NodeSetExpr.create(parseUnion(parseBasisTop(parent), parent)); 778 } 779 ch = read(); 780 782 case '0': case '1': case '2': case '3': case '4': 783 case '5': case '6': case '7': case '8': case '9': 784 { 785 long value = 0; 786 double exp = 1; 787 int digits = 0; 788 for (; ch >= '0' && ch <= '9'; ch = read()) 789 value = 10 * value + ch - '0'; 790 if (ch == '.') { 791 for (ch = read(); ch >= '0' && ch <= '9'; ch = read()) { 792 value = 10 * value + ch - '0'; 793 exp *= 10; 794 digits--; 795 } 796 } 797 798 if (ch == 'e' || ch == 'E') { 799 int sign = 1; 800 int expValue = 0; 801 802 ch = read(); 803 if (ch == '-') { 804 sign = -1; 805 ch = read(); 806 } 807 else if (ch == '+') 808 ch = read(); 809 810 for (; ch >= '0' && ch <= '9'; ch = read()) 811 expValue = 10 * expValue + ch - '0'; 812 813 exp = Math.pow(10, digits + sign * expValue); 814 815 unread(); 816 817 return new NumericExpr((double) value * (double) exp); 818 } 819 820 unread(); 821 return new NumericExpr((double) value / (double) exp); 822 } 823 824 case '-': 825 return new NumericExpr(Expr.NEG, parseTerm(parent, listParent)); 826 827 case '+': 828 return parseTerm(parent, listParent); 829 830 case '(': 831 { 832 Expr expr = parseExpr(parent, listParent); 833 if ((ch = skipWhitespace(read())) != ')') 834 throw error(L.l("expected `{0}' at {1}", ")", badChar(ch))); 835 836 return expr; 837 } 838 839 case '/': case '@': case '*': 840 unread(); 841 return NodeSetExpr.create(parseUnion(parseBasisTop(parent), parent)); 842 843 case '\'': case '"': 844 { 845 int end = ch; 846 CharBuffer cb = new CharBuffer(); 847 for (ch = read(); ch >= 0; ch = read()) { 848 if (ch != end) 849 cb.append((char) ch); 850 else if ((ch = read()) == end) 851 cb.append((char) ch); 852 else { 853 unread(); 854 break; 855 } 856 } 857 858 return new StringExpr(cb.toString()); 859 } 860 861 case '$': 862 { 863 String name = readName(read()); 864 return new VarExpr(name); 865 } 866 867 default: 868 if (! XmlChar.isNameStart(ch)) 869 throw error(L.l("unknown character at {0}", badChar(ch))); 870 871 String name = readName(ch); 872 873 ch = skipWhitespace(read()); 874 int axisIndex = name.indexOf("::"); 875 876 if (ch == '(' && axisIndex < 0) { 878 return parseFunction(parent, listParent, name, true); 879 } 880 else if (ch == '(') { 881 String axis = name.substring(0, axisIndex); 882 if (axisMap.get(axis) <= 0) 883 return parseFunction(parent, listParent, name, true); 884 } 885 886 unread(); 887 888 if (parent == null) 889 parent = new FromContext(); 890 return parseNodeSetExpr(parent, name, Node.ELEMENT_NODE); 891 } 892 } 893 894 900 Expr parseFunction(AbstractPattern parent, 901 AbstractPattern listParent, 902 String name, 903 boolean fromChildren) 904 throws XPathParseException 905 { 906 int ch = skipWhitespace(read()); 907 908 ArrayList <Expr> args = new ArrayList <Expr>(); 909 910 for (; ch >= 0 && ch != ')'; ch = skipWhitespace(read())) { 911 if (ch != ',') 912 unread(); 913 Expr expr = parseExpr(parent, listParent); 914 915 if (expr == null) 916 throw error(L.l("null expression")); 917 918 args.add(expr); 919 } 920 921 int code = exprFunctions.get(name); 922 switch (code) { 923 case Expr.TRUE: case Expr.FALSE: case Expr.NOT: case Expr.BOOLEAN: 924 case Expr.STARTS_WITH: case Expr.CONTAINS: case Expr.LANG: 925 case Expr.FUNCTION_AVAILABLE: 926 return new BooleanExpr(code, args); 927 928 case Expr.NUMBER: case Expr.FLOOR: case Expr.CEILING: case Expr.ROUND: 929 case Expr.STRING_LENGTH: 930 return new NumericExpr(code, args); 931 932 case Expr.POSITION: 933 case Expr.LAST: 934 return new NumericExpr(code, listParent); 935 936 case Expr.COUNT: case Expr.SUM: 937 if (args.size() == 0) 938 args.add(NodeSetExpr.create(new FromContext())); 939 return new NumericExpr(code, ((Expr) args.get(0)).toNodeList()); 940 941 942 case Expr.CONCAT: 943 case Expr.SUBSTRING_BEFORE: 944 case Expr.SUBSTRING: case Expr.SUBSTRING_AFTER: 945 case Expr.TRANSLATE: 946 case Expr.SYSTEM_PROPERTY: 947 return new StringExpr(code, args); 948 949 case Expr.STRING: case Expr.NORMALIZE: 950 return new StringExpr(code, args); 951 952 case Expr.LOCAL_PART: case Expr.NAMESPACE: 953 case Expr.QNAME: case Expr.GENERATE_ID: 954 if (args.size() == 0) 955 args.add(NodeSetExpr.create(new FromContext())); 956 return new StringExpr(code, args); 957 958 case Expr.ID: 959 if (args.size() == 0) { 960 args.add(NodeSetExpr.create(parent)); 961 return new IdExpr(args); 962 } 963 else 964 return new IdExpr(args); 965 966 case Expr.IF: 967 if (args.size() != 3) 968 throw error(L.l("`if' needs three args.")); 969 970 return new ObjectExpr(code, args); 971 972 case Expr.BASE_URI: 973 if (args.size() != 1) 974 throw error(L.l("`base-uri' needs one args.")); 975 976 return new StringExpr(code, args.get(0)); 977 978 case TEXT: 979 if (fromChildren) 980 parent = new FromChildren(parent); 981 AbstractPattern pattern = NodeTypePattern.create(parent, Node.TEXT_NODE); 982 return NodeSetExpr.create(pattern); 983 984 case COMMENT: 985 if (fromChildren) 986 parent = new FromChildren(parent); 987 pattern = NodeTypePattern.create(parent, Node.COMMENT_NODE); 988 return NodeSetExpr.create(pattern); 989 990 case ER: 991 if (fromChildren) 992 parent = new FromChildren(parent); 993 pattern = NodeTypePattern.create(parent, Node.ENTITY_REFERENCE_NODE); 994 return NodeSetExpr.create(pattern); 995 996 case PI: 997 if (fromChildren) 998 parent = new FromChildren(parent); 999 if (args.size() == 1) { 1000 Expr expr = (Expr) args.get(0); 1001 String value = null; 1002 if (expr instanceof StringExpr) 1003 value = ((StringExpr) expr).getValue(); 1004 if (value == null) 1005 throw error(L.l("processing-instruction expects string literal")); 1006 pattern = new NodePattern(parent, value, 1007 Node.PROCESSING_INSTRUCTION_NODE); 1008 } 1009 else 1010 pattern = NodeTypePattern.create(parent, Node.PROCESSING_INSTRUCTION_NODE); 1011 return NodeSetExpr.create(pattern); 1012 1013 case NODE: 1014 if (fromChildren) 1015 parent = new FromChildren(parent); 1016 pattern = NodeTypePattern.create(parent, NodeTypePattern.NODE); 1017 return NodeSetExpr.create(pattern); 1018 1019 case CURRENT: 1020 return NodeSetExpr.create(new CurrentPattern()); 1021 1022 case CONTEXT: 1023 return NodeSetExpr.create(new FromContext()); 1024 1025 default: 1026 Expr function = constructorFunction(name, args); 1027 1028 if (function != null) 1029 return function; 1030 1031 int p = name.lastIndexOf(':'); 1032 String prefix; 1033 1034 if (p > 0) 1035 prefix = name.substring(0, p); 1036 else 1037 prefix = ""; 1038 1039 String context = NamespaceContext.find(_namespace, prefix); 1040 1041 if (context == null) { 1042 } 1043 else if (context.startsWith("java:")) 1044 name = context + "." + name.substring(p + 1); 1045 else if (context.indexOf(':') < 0) 1046 name = "java:" + context + "." + name.substring(p + 1); 1047 1048 if (name.startsWith("java:")) { 1049 p = name.lastIndexOf('.'); 1050 if (p < 0) 1051 throw error(L.l("`{0}' is an illegal extension function. Java extension functions must look like java:mypkg.MyClass.mymethod.", name)); 1052 1053 String className = name.substring(5, p); 1054 String methodName = name.substring(p + 1); 1055 1056 Class cl; 1057 try { 1058 cl = CauchoSystem.loadClass(className); 1059 } catch (ClassNotFoundException e) { 1060 throw error(L.l("`{0}' is an unknown Java class. Java extension functions must use public classes.", className)); 1061 } 1062 1063 if (methodName.equals("new")) { 1064 Constructor []constructors = cl.getConstructors(); 1065 1066 for (int i = 0; i < constructors.length; i++) { 1067 if (constructors[i].getParameterTypes().length == args.size()) 1068 return new NewJavaExpr(constructors[i], args); 1069 } 1070 1071 throw error(L.l("No matching public constructor in `{0}'", 1072 className)); 1073 } 1074 1075 Method method = null; 1076 Method []methods = cl.getMethods(); 1077 1078 if (args.size() > 0) { 1079 for (int i = 0; i < methods.length; i++) { 1080 if (methods[i].getName().equals(methodName) && 1081 methods[i].getParameterTypes().length == args.size() - 1 && 1082 ! Modifier.isStatic(methods[i].getModifiers())) { 1083 Expr objArg = (Expr) args.remove(0); 1084 1085 return new ObjectJavaExpr(methods[i], objArg, args); 1086 } 1087 } 1088 } 1089 1090 for (int i = 0; i < methods.length; i++) { 1091 if (methods[i].getName().equals(methodName) && 1092 methods[i].getParameterTypes().length == args.size()) { 1093 method = methods[i]; 1094 break; 1095 } 1096 } 1097 1098 if (method == null) 1099 throw error(L.l("`{0}' does not match a public method in `{1}'", 1100 methodName, className)); 1101 1102 if (! Modifier.isStatic(method.getModifiers())) 1103 throw error(L.l("`{0}' is not a static method in `{1}'", 1104 methodName, className)); 1105 1106 return new StaticJavaExpr(method, args); 1107 } 1108 else if (name.equals("")) 1109 throw error(L.l("expected node-test at `{0}'", "(")); 1110 1111 return new FunExpr(name, parent, args); 1112 } 1113 } 1114 1115 private Expr constructorFunction(String name, ArrayList <Expr> args) 1116 throws XPathParseException 1117 { 1118 Constructor constructor = _exprFunctions.get(name); 1119 1120 if (constructor == null) 1121 return null; 1122 1123 Class []params = constructor.getParameterTypes(); 1124 1125 if (params.length < args.size()) 1126 throw error(L.l("`{0}' needs {1} arguments", 1127 name, "" + params.length)); 1128 1129 Object []values = new Object [params.length]; 1130 1131 for (int i = 0; i < args.size(); i++) 1132 values[i] = args.get(i); 1133 1134 try { 1135 return (Expr) constructor.newInstance(values); 1136 } catch (Throwable e) { 1137 throw new XPathParseException(e); 1138 } 1139 } 1140 1141 private Expr parseNodeSetExpr(AbstractPattern parent, String name, int nodeType) 1142 throws XPathParseException 1143 { 1144 AbstractPattern top = parseAxis(parent, name, true, nodeType); 1145 top = parseFilter(top); 1146 1147 return NodeSetExpr.create(parseUnion(parsePath(top), parent)); 1148 } 1149 1150 1155 private int scanToken() 1156 throws XPathParseException 1157 { 1158 if (peek >= 0) { 1159 int value = peek; 1160 peek = -1; 1161 return value; 1162 } 1163 1164 int ch = skipWhitespace(read()); 1165 1166 switch (ch) { 1167 case '+': return Expr.ADD; 1168 case '-': return Expr.SUB; 1169 case '*': return Expr.MUL; 1170 case '=': return Expr.EQ; 1171 1172 case '!': 1173 ch = read(); 1174 if (ch == '=') 1175 return Expr.NEQ; 1176 else 1177 throw error(L.l("expected `{0}' at {1}", "=", badChar(ch))); 1178 1179 case '<': 1180 ch = read(); 1181 if (ch == '=') 1182 return Expr.LE; 1183 else { 1184 unread(); 1185 return Expr.LT; 1186 } 1187 1188 case '>': 1189 ch = read(); 1190 if (ch == '=') 1191 return Expr.GE; 1192 else { 1193 unread(); 1194 return Expr.GT; 1195 } 1196 1197 default: 1198 if (XmlChar.isNameStart(ch)) { 1199 String name = readName(ch); 1200 1201 if (name.equals("div")) 1202 return Expr.DIV; 1203 else if (name.equals("quo")) 1204 return Expr.QUO; 1205 else if (name.equals("mod")) 1206 return Expr.MOD; 1207 else if (name.equals("and")) 1208 return Expr.AND; 1209 else if (name.equals("or")) 1210 return Expr.OR; 1211 else 1212 throw error(L.l("expected binary operation at `{0}'", name)); 1213 } 1214 1215 unread(); 1216 return -1; 1217 } 1218 } 1219 1220 private String readName(int ch) 1221 { 1222 tag.clear(); 1223 for (; XmlChar.isNameChar(ch); ch = read()) 1224 tag.append((char) ch); 1225 1226 if (ch == '*' && tag.endsWith(":")) 1227 tag.append((char) ch); 1228 else 1229 unread(); 1230 1231 return tag.toString(); 1232 } 1233 1234 private void undoToken(int token) 1235 { 1236 peek = token; 1237 } 1238 1239 private int read() 1240 { 1241 if (index < _string.length()) { 1242 return _string.charAt(index++); 1243 } 1244 else { 1245 index++; 1246 return -1; 1247 } 1248 } 1249 1250 private void unread() 1251 { 1252 index--; 1253 } 1254 1255 private XPathParseException error(String message) 1256 { 1257 return new XPathParseException(message + " in " + _string); 1258 } 1259 1260 private String badChar(int ch) 1261 { 1262 if (ch < 0) 1263 return L.l("end of file"); 1264 else if (ch == '\n') 1265 return L.l("end of line"); 1266 else 1267 return "`" + (char) ch + "'"; 1268 } 1269 1270 private int skipWhitespace(int ch) 1271 throws XPathParseException 1272 { 1273 for (; ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'; ch = read()) { 1274 } 1275 1276 return ch; 1277 } 1278 1279 private static void addFunction(String name, Class cl) 1280 { 1281 Constructor []constructors = cl.getConstructors(); 1282 1283 _exprFunctions.put(name, constructors[0]); 1284 } 1285 1286 static { 1287 exprFunctions = new IntMap(); 1288 exprFunctions.put("id", Expr.ID); 1289 1290 exprFunctions.put("true", Expr.TRUE); 1291 exprFunctions.put("false", Expr.FALSE); 1292 exprFunctions.put("not", Expr.NOT); 1293 exprFunctions.put("boolean", Expr.BOOLEAN); 1294 exprFunctions.put("starts-with", Expr.STARTS_WITH); 1295 exprFunctions.put("contains", Expr.CONTAINS); 1296 exprFunctions.put("lang", Expr.LANG); 1297 1298 exprFunctions.put("number", Expr.NUMBER); 1299 exprFunctions.put("sum", Expr.SUM); 1300 exprFunctions.put("floor", Expr.FLOOR); 1301 exprFunctions.put("ceiling", Expr.CEILING); 1302 exprFunctions.put("round", Expr.ROUND); 1303 exprFunctions.put("position", Expr.POSITION); 1304 exprFunctions.put("count", Expr.COUNT); 1305 exprFunctions.put("last", Expr.LAST); 1306 exprFunctions.put("string-length", Expr.STRING_LENGTH); 1307 1308 exprFunctions.put("string", Expr.STRING); 1309 exprFunctions.put("concat", Expr.CONCAT); 1310 exprFunctions.put("substring", Expr.SUBSTRING); 1311 exprFunctions.put("substring-before", Expr.SUBSTRING_BEFORE); 1312 exprFunctions.put("substring-after", Expr.SUBSTRING_AFTER); 1313 exprFunctions.put("normalize-space", Expr.NORMALIZE); 1314 exprFunctions.put("translate", Expr.TRANSLATE); 1315 1316 exprFunctions.put("local-name", Expr.LOCAL_PART); 1317 exprFunctions.put("local-part", Expr.LOCAL_PART); 1318 exprFunctions.put("namespace-uri", Expr.NAMESPACE); 1319 exprFunctions.put("name", Expr.QNAME); 1320 exprFunctions.put("generate-id", Expr.GENERATE_ID); 1321 1322 exprFunctions.put("if", Expr.IF); 1323 1324 exprFunctions.put("text", TEXT); 1325 exprFunctions.put("comment", COMMENT); 1326 exprFunctions.put("er", ER); 1327 exprFunctions.put("entity-reference", ER); 1328 exprFunctions.put("pi", PI); 1329 exprFunctions.put("processing-instruction", PI); 1330 exprFunctions.put("node", NODE); 1331 exprFunctions.put("current", CURRENT); 1332 exprFunctions.put("context", CONTEXT); 1333 1334 axisMap = new IntMap(); 1335 axisMap.put("ancestor", ANCESTOR_AXIS); 1336 axisMap.put("ancestor-or-self", ANCESTOR_OR_SELF_AXIS); 1337 axisMap.put("attribute", ATTRIBUTE_AXIS); 1338 axisMap.put("child", CHILD_AXIS); 1339 axisMap.put("descendant", DESCENDANT_AXIS); 1340 axisMap.put("descendant-or-self", DESCENDANT_OR_SELF_AXIS); 1341 axisMap.put("following", FOLLOWING_AXIS); 1342 axisMap.put("following-sibling", FOLLOWING_SIBLING_AXIS); 1343 axisMap.put("namespace", NAMESPACE_AXIS); 1344 axisMap.put("parent", PARENT_AXIS); 1345 axisMap.put("preceding", PRECEDING_AXIS); 1346 axisMap.put("preceding-sibling", PRECEDING_SIBLING_AXIS); 1347 axisMap.put("self", SELF_AXIS); 1348 1349 _exprFunctions = new HashMap <String ,Constructor >(); 1350 addFunction("fn:base-uri", BaseURI.class); 1351 addFunction("fn:resolve-uri", ResolveURI.class); 1352 addFunction("fn:trace", Trace.class); 1353 } 1354} 1355 | Popular Tags |