1 package com.icl.saxon.expr; 2 import com.icl.saxon.om.*; 3 import com.icl.saxon.*; 4 import com.icl.saxon.pattern.*; 5 import com.icl.saxon.functions.*; 6 import javax.xml.transform.TransformerException ; 7 8 9 import java.util.*; 10 11 18 19 20 public final class ExpressionParser { 21 22 private Tokenizer t; 23 private StaticContext env; 24 25 private final static int CHILD_AXIS = 0; 26 private final static int ATTRIBUTE_AXIS = 1; 27 28 31 32 private void expect(int token) throws XPathException { 33 if (t.currentToken != token) 34 grumble("expected \"" + Tokenizer.tokens[token] + "\"" + 35 ", found \"" + Tokenizer.tokens[t.currentToken] + "\""); 36 } 37 38 41 42 private void grumble(String message) throws XPathException { 43 throw new XPathException("Error in expression " + t.pattern + ": " + message); 44 } 45 46 51 52 public Expression parse(String expression, StaticContext env) throws XPathException { 53 this.env = env; 55 t = new Tokenizer(); 56 t.tokenize(expression); 57 Expression exp = parseExpression(); 58 if (t.currentToken != Tokenizer.EOF) 59 grumble("Unexpected token " + Tokenizer.tokens[t.currentToken] + " beyond end of expression"); 60 exp.setStaticContext(env); 61 return exp; 62 } 63 64 69 70 public Pattern parsePattern(String pattern, StaticContext env) throws XPathException { 71 this.env = env; 73 t = new Tokenizer(); 74 t.tokenize(pattern); 75 Pattern pat = parseUnionPattern(); 76 if (t.currentToken != Tokenizer.EOF) 77 grumble("Unexpected token " + Tokenizer.tokens[t.currentToken] + " beyond end of pattern"); 78 pat.setStaticContext(env); 79 return pat; 80 } 81 82 83 87 88 92 93 private Expression parseExpression() throws XPathException { 94 Expression exp = parseAndExpression(); 95 while (t.currentToken == Tokenizer.OR) { 96 t.next(); 97 exp = new BooleanExpression(exp, Tokenizer.OR, parseAndExpression()); 98 exp.setStaticContext(env); 99 } 100 return exp; 101 } 102 103 107 108 private Expression parseAndExpression() throws XPathException { 109 Expression exp = parseEqualityExpression(); 110 while (t.currentToken == Tokenizer.AND) { 111 t.next(); 112 exp = new BooleanExpression(exp, Tokenizer.AND, parseEqualityExpression()); 113 exp.setStaticContext(env); 114 } 115 return exp; 116 } 117 118 122 123 private Expression parseEqualityExpression() throws XPathException { 124 Expression exp = parseRelationalExpression(); 125 while (t.currentToken == Tokenizer.EQUALS || 126 t.currentToken == Tokenizer.NE) { 127 int op = t.currentToken; 128 t.next(); 129 exp = new RelationalExpression(exp, op, parseRelationalExpression()); 130 exp.setStaticContext(env); 131 } 132 return exp; 133 } 134 135 139 140 private Expression parseRelationalExpression() throws XPathException { 141 Expression exp = parseAdditiveExpression(); 142 while (t.currentToken == Tokenizer.LT || 143 t.currentToken == Tokenizer.GT || 144 t.currentToken == Tokenizer.LE || 145 t.currentToken == Tokenizer.GE ) { 146 int op = t.currentToken; 147 t.next(); 148 exp = new RelationalExpression(exp, op, parseAdditiveExpression()); 149 exp.setStaticContext(env); 150 } 151 return exp; 152 } 153 154 158 159 private Expression parseAdditiveExpression() throws XPathException { 160 Expression exp = parseMultiplicativeExpression(); 161 while (t.currentToken == Tokenizer.PLUS || 162 t.currentToken == Tokenizer.MINUS ) { 163 int op = t.currentToken; 164 t.next(); 165 exp = new ArithmeticExpression(exp, op, parseMultiplicativeExpression()); 166 exp.setStaticContext(env); 167 } 168 return exp; 169 } 170 171 175 176 private Expression parseMultiplicativeExpression() throws XPathException { 177 Expression exp = parseUnaryExpression(); 178 while (t.currentToken == Tokenizer.MULT || 179 t.currentToken == Tokenizer.DIV || 180 t.currentToken == Tokenizer.MOD ) { 181 int op = t.currentToken; 182 t.next(); 183 exp = new ArithmeticExpression(exp, op, parseUnaryExpression()); 184 exp.setStaticContext(env); 185 } 186 return exp; 187 } 188 189 193 194 private Expression parseUnaryExpression() throws XPathException { 195 Expression exp; 196 if (t.currentToken == Tokenizer.MINUS) { 197 t.next(); 198 exp = new ArithmeticExpression(new NumericValue(0), 199 Tokenizer.NEGATE, 200 parseUnaryExpression()); 201 exp.setStaticContext(env); 202 } 203 else { 204 exp = parseUnionExpression(); 205 } 206 return exp; 207 } 208 209 210 214 215 private Expression parseUnionExpression() throws XPathException { 216 Expression exp = parsePathExpression(); 217 while (t.currentToken == Tokenizer.VBAR ) { 218 t.next(); 219 exp = new UnionExpression(exp, parsePathExpression()); 220 exp.setStaticContext(env); 221 } 222 return exp; 223 } 224 225 231 232 private Expression parsePathExpression() throws XPathException { 233 Expression start; 234 switch (t.currentToken) { 235 case Tokenizer.SLASH: 236 t.next(); 237 switch(t.currentToken) { 238 case Tokenizer.NAME: 240 case Tokenizer.PREFIX: 241 case Tokenizer.STAR: 242 case Tokenizer.AT: 243 case Tokenizer.NODETYPE: 244 case Tokenizer.AXIS: 245 case Tokenizer.DOT: 246 case Tokenizer.DOTDOT: 247 return parseRelativePath(new RootExpression()); 248 default: 249 return new RootExpression(); 250 } 251 252 case Tokenizer.SLSL: 253 return parsePathContinuation(new RootExpression()); 255 256 case Tokenizer.DOT: 257 t.next(); 258 return parsePathContinuation(new ContextNodeExpression()); 259 260 case Tokenizer.DOTDOT: 261 t.next(); 262 return parsePathContinuation(new ParentNodeExpression()); 263 264 case Tokenizer.NAME: 265 case Tokenizer.PREFIX: 266 case Tokenizer.STAR: 267 case Tokenizer.NODETYPE: 268 case Tokenizer.AXIS: 269 case Tokenizer.AT: 270 return parseRelativePath(new ContextNodeExpression()); 271 272 default: 273 start = parseFilterExpression(); 274 Expression continuation = parsePathContinuation(start); 275 continuation.setStaticContext(env); 276 return continuation; 277 } 278 } 279 280 283 284 private Expression parseFilterExpression() throws XPathException { 285 Expression primary = parsePrimaryExpression(); 286 while (t.currentToken == Tokenizer.LSQB) { 287 t.next(); 288 Expression predicate = parseExpression(); 289 expect(Tokenizer.RSQB); 290 primary = new FilterExpression(primary, predicate); 291 primary.setStaticContext(env); 292 t.next(); 293 } 294 return primary; 295 } 296 297 305 306 private Expression parsePrimaryExpression() throws XPathException { 307 switch (t.currentToken) { 308 case Tokenizer.DOLLAR: 309 t.next(); 310 expect(Tokenizer.NAME); 311 String var = t.currentTokenValue; 312 t.next(); 313 314 int vtest = env.makeNameCode(var, false) & 0xfffff; 315 return new VariableReference(vtest, env); 316 317 case Tokenizer.LPAR: 318 t.next(); 319 Expression exp = parseExpression(); 320 expect(Tokenizer.RPAR); 321 t.next(); 322 return exp; 323 324 case Tokenizer.LITERAL: 325 Expression literal = new StringValue(t.currentTokenValue); 326 t.next(); 327 return literal; 328 329 case Tokenizer.NUMBER: 330 Expression number = new NumericValue(t.currentTokenValue); 331 t.next(); 332 return number; 333 334 case Tokenizer.FUNCTION: 335 return parseFunctionCall(); 336 337 default: 338 grumble("Unexpected token " + Tokenizer.tokens[t.currentToken] + " in expression"); 339 return null; 340 } 341 } 342 343 344 348 349 private Expression parsePathContinuation(Expression start) throws XPathException { 350 switch (t.currentToken) { 351 case Tokenizer.SLASH: 352 t.next(); 353 return parseRelativePath(start); 354 355 case Tokenizer.SLSL: 356 Expression exp = new PathExpression( 358 start, 359 new Step(Axis.DESCENDANT_OR_SELF, AnyNodeTest.getInstance())); 360 exp.setStaticContext(env); 361 t.next(); 362 return parseRelativePath(exp); 363 364 default: 365 return start; 366 } 367 } 368 369 373 374 private Expression parseRelativePath(Expression start) throws XPathException { 375 Step step = parseStep(); 376 Expression exp = new PathExpression(start, step); 377 exp.setStaticContext(env); 378 return parsePathContinuation(exp); 379 } 380 381 384 385 private Step parseStep() throws XPathException { 386 Step step=null; 387 388 switch(t.currentToken) { 389 390 case Tokenizer.DOT: 391 step = new Step(Axis.SELF, AnyNodeTest.getInstance()); 392 t.next(); 393 break; 394 395 case Tokenizer.DOTDOT: 396 step = new Step(Axis.PARENT, AnyNodeTest.getInstance()); 397 t.next(); 398 break; 399 400 case Tokenizer.NAME: 401 step = new Step(Axis.CHILD, 402 env.makeNameTest(NodeInfo.ELEMENT, 403 t.currentTokenValue, false)); 404 t.next(); 405 while (t.currentToken == Tokenizer.LSQB) { 406 step = parseStepPredicate(step); 407 } 408 break; 409 410 case Tokenizer.PREFIX: 411 NamespaceTest nstest1 = env.makeNamespaceTest( 412 NodeInfo.ELEMENT, 413 t.currentTokenValue); 414 step = new Step(Axis.CHILD, nstest1); 415 t.next(); 416 while (t.currentToken == Tokenizer.LSQB) { 417 step = parseStepPredicate(step); 418 } 419 break; 420 421 case Tokenizer.STAR: 422 step = new Step(Axis.CHILD, new NodeTypeTest(NodeInfo.ELEMENT)); 423 t.next(); 424 while (t.currentToken == Tokenizer.LSQB) { 425 step = parseStepPredicate(step); 426 } 427 break; 428 429 case Tokenizer.AT: 430 t.next(); 431 switch(t.currentToken) { 432 433 case Tokenizer.NAME: 434 step = new Step(Axis.ATTRIBUTE, 435 env.makeNameTest(NodeInfo.ATTRIBUTE, 436 t.currentTokenValue, false)); 437 t.next(); 438 break; 439 440 case Tokenizer.PREFIX: 441 NamespaceTest nstest2 = env.makeNamespaceTest( 442 NodeInfo.ATTRIBUTE, 443 t.currentTokenValue); 444 step = new Step(Axis.ATTRIBUTE, nstest2); 445 446 t.next(); 447 break; 448 449 case Tokenizer.STAR: 450 step = new Step(Axis.ATTRIBUTE, 451 AnyNodeTest.getInstance()); 452 t.next(); 453 break; 454 455 case Tokenizer.NODETYPE: 456 String nodetype = t.currentTokenValue; t.next(); 458 459 if (nodetype=="text") { 461 step = new Step(Axis.ATTRIBUTE, NoNodeTest.getInstance()); 462 } else if (nodetype=="node") { 463 step = new Step(Axis.ATTRIBUTE, AnyNodeTest.getInstance()); 464 } else if (nodetype=="comment") { 465 step = new Step(Axis.ATTRIBUTE, NoNodeTest.getInstance()); 466 } else if (nodetype=="processing-instruction") { 467 if (t.currentToken==Tokenizer.LITERAL) { 469 t.next(); } 471 step = new Step(Axis.ATTRIBUTE, NoNodeTest.getInstance()); 472 } 473 expect(Tokenizer.RPAR); 474 t.next(); 475 break; 476 477 default: 478 grumble("@ must be followed by a NameTest or NodeTest"); 479 } 480 while (t.currentToken == Tokenizer.LSQB) { 481 step = parseStepPredicate(step); 482 } 483 break; 484 485 case Tokenizer.NODETYPE: 486 String nodetype = t.currentTokenValue; t.next(); 488 489 if (nodetype=="text") { 490 step = new Step(Axis.CHILD, new NodeTypeTest(NodeInfo.TEXT)); 491 } else if (nodetype=="node") { 492 step = new Step(Axis.CHILD, AnyNodeTest.getInstance()); 493 } else if (nodetype=="comment") { 494 step = new Step(Axis.CHILD, new NodeTypeTest(NodeInfo.COMMENT)); 495 } else if (nodetype=="processing-instruction") { 496 if (t.currentToken==Tokenizer.LITERAL) { 498 if (Name.isNCName(t.currentTokenValue)) { 499 step = new Step(Axis.CHILD, 500 env.makeNameTest(NodeInfo.PI, 501 t.currentTokenValue, false)); 502 } else { 503 step = new Step(Axis.CHILD, NoNodeTest.getInstance()); 505 } 506 t.next(); 507 } else { 508 step = new Step(Axis.CHILD, new NodeTypeTest(NodeInfo.PI)); 509 } 510 } 511 expect(Tokenizer.RPAR); 512 t.next(); 513 514 while (t.currentToken == Tokenizer.LSQB) { 515 step = parseStepPredicate(step); 516 } 517 break; 518 519 case Tokenizer.AXIS: 520 byte axis = Axis.getAxisNumber(t.currentTokenValue); 521 short principalNodeType = Axis.principalNodeType[axis]; 522 t.next(); 523 switch (t.currentToken) { 524 525 case Tokenizer.NAME: 526 step = new Step(axis, 527 env.makeNameTest(principalNodeType, 528 t.currentTokenValue, false)); 529 t.next(); 530 break; 531 532 case Tokenizer.PREFIX: 533 NamespaceTest nstest3 = env.makeNamespaceTest( 534 principalNodeType, 535 t.currentTokenValue); 536 step = new Step(axis, nstest3); 537 t.next(); 538 break; 539 540 case Tokenizer.STAR: 541 step = new Step(axis, new NodeTypeTest(principalNodeType)); 542 t.next(); 543 break; 544 545 case Tokenizer.NODETYPE: 546 String nt = t.currentTokenValue; t.next(); 548 549 if (nt=="node") { 550 step = new Step(axis, AnyNodeTest.getInstance()); 551 } else if (nt=="text") { 552 step = new Step(axis, new NodeTypeTest(NodeInfo.TEXT)); 553 } else if (nt=="comment") { 554 step = new Step(axis, new NodeTypeTest(NodeInfo.COMMENT)); 555 } else if (nt=="processing-instruction") { 556 if (t.currentToken==Tokenizer.LITERAL) { 558 if (Name.isNCName(t.currentTokenValue)) { 559 step = new Step(axis, 560 env.makeNameTest(NodeInfo.PI, 561 t.currentTokenValue, false)); 562 } else { 563 step = new Step(axis, NoNodeTest.getInstance()); 565 } 566 t.next(); 567 } else { 568 step = new Step(axis, new NodeTypeTest(NodeInfo.PI)); 569 } 570 } else { 571 grumble("Unsupported node type"); 572 } 573 574 expect(Tokenizer.RPAR); 575 t.next(); 576 break; 577 default: 578 grumble("Unexpected token [" + Tokenizer.tokens[t.currentToken] + "] after axis name"); 579 } 580 while (t.currentToken == Tokenizer.LSQB) { 581 step = parseStepPredicate(step); 582 } 583 break; 584 585 default: 586 grumble("Unexpected token [" + Tokenizer.tokens[t.currentToken] + "] in path expression"); 587 } 589 return step; 590 } 591 592 595 596 private Step parseStepPredicate(Step start) throws XPathException { 597 t.next(); 598 Expression predicate = parseExpression(); 599 expect(Tokenizer.RSQB); 600 t.next(); 601 return start.addFilter(predicate); 602 } 603 604 608 609 private Expression parseFunctionCall() throws XPathException { 610 611 String fname = t.currentTokenValue; 612 Function f=null; 613 614 int colon = fname.indexOf(":"); 615 if (colon<0) { 616 Expression e = makeSystemFunction(fname); 617 if (e==null) grumble("Unknown system function: " + fname); 618 e.setStaticContext(env); 619 620 if (e instanceof Function) { 621 f = (Function)e; 622 } else { t.next(); 624 expect(Tokenizer.RPAR); 625 t.next(); 626 return e; 627 } 628 } else { f = env.getStyleSheetFunction(env.makeNameCode(fname, false) & 0xfffff); 630 } 631 if (f==null) { f = new FunctionProxy(); 633 } 634 f.setStaticContext(env); 635 636 638 t.next(); 639 if (t.currentToken!=Tokenizer.RPAR) { 640 Expression arg = parseExpression(); 642 f.addArgument(arg); 643 while(t.currentToken==Tokenizer.COMMA) { 644 t.next(); 645 arg = parseExpression(); 646 f.addArgument(arg); 647 } 648 expect(Tokenizer.RPAR); 649 } 650 t.next(); 651 if (f instanceof FunctionProxy) { 652 String uri = env.getURIForPrefix(fname.substring(0, colon)); 653 String lname = fname.substring(colon+1); 654 Class className = null; 655 try { 656 className = env.getExternalJavaClass(uri); 657 } catch (TransformerException err) { 658 XPathException xx = new XPathException( 659 "Failed to load external Java class for uri " + uri); 660 return new ErrorExpression(xx); 661 } 663 if (className==null) { 664 XPathException xx = new XPathException( 665 "The URI " + uri + " does not identify an external Java class"); 666 return new ErrorExpression(xx); 667 } 669 ((FunctionProxy)f).setFunctionName(className, lname); 670 } 671 return f; 672 } 673 674 678 679 public static Expression makeSystemFunction(String name) { 680 if (name=="last") return new Last(); 681 if (name=="position") return new Position(); 682 683 if (name=="count") return new Count(); 684 if (name=="current") return new Current(); 685 if (name=="id") return new Id(); 686 if (name=="key") return new Key(); 687 if (name=="document") return new Document(); 688 if (name=="local-name") return new LocalName(); 689 if (name=="namespace-uri") return new NamespaceURI(); 690 if (name=="name") return new NameFn(); 691 if (name=="generate-id") return new GenerateId(); 692 693 if (name=="not") return new Not(); 694 if (name=="true") return new BooleanValue(true); 695 if (name=="false") return new BooleanValue(false); 696 if (name=="boolean") return new BooleanFn(); 697 if (name=="lang") return new Lang(); 698 699 if (name=="number") return new NumberFn(); 700 if (name=="floor") return new Floor(); 701 if (name=="ceiling") return new Ceiling(); 702 if (name=="round") return new Round(); 703 if (name=="sum") return new Sum(); 704 705 if (name=="string") return new StringFn(); 706 707 if (name=="starts-with") return new StartsWith(); 708 if (name=="string-length") return new StringLength(); 709 if (name=="substring") return new Substring(); 710 if (name=="contains") return new Contains(); 711 if (name=="substring-before") return new SubstringBefore(); 712 if (name=="substring-after") return new SubstringAfter(); 713 if (name=="normalize-space") return new NormalizeSpace(); 714 if (name=="translate") return new Translate(); 715 if (name=="concat") return new Concat(); 716 if (name=="format-number") return new FormatNumber(); 717 718 if (name=="system-property") return new SystemProperty(); 719 if (name=="function-available") return new FunctionAvailable(); 720 if (name=="element-available") return new ElementAvailable(); 721 if (name=="unparsed-entity-uri") return new UnparsedEntityURI(); 722 return null; 723 } 724 725 729 730 734 735 private Pattern parseUnionPattern() throws XPathException { 736 Pattern exp1 = parsePathPattern(); 737 738 while (t.currentToken == Tokenizer.VBAR ) { 739 t.next(); 740 Pattern exp2 = parsePathPattern(); 741 exp1 = new UnionPattern(exp1, exp2); 742 exp1.setStaticContext(env); 743 exp2.setStaticContext(env); 744 } 745 746 return exp1; 747 } 748 749 752 753 private Pattern parsePathPattern() throws XPathException { 754 755 LocationPathPattern lppat = new LocationPathPattern(); 756 lppat.setStaticContext(env); 757 Pattern pat = lppat; 758 Pattern prev = null; 759 int connector = -1; 760 boolean rootonly = false; 761 762 764 switch(t.currentToken) { 765 case Tokenizer.SLASH: 766 connector = t.currentToken; 767 t.next(); 768 prev = new NodeTypeTest(NodeInfo.ROOT); 769 rootonly = true; 770 break; 771 case Tokenizer.SLSL: connector = t.currentToken; 774 t.next(); 775 prev = new NodeTypeTest(NodeInfo.ROOT); 776 rootonly = false; 777 break; 778 default: 779 break; 780 } 781 782 boolean more = true; 783 while(more) { 784 785 switch(t.currentToken) { 786 case Tokenizer.AXIS: 787 if (t.currentTokenValue.equals("child")) { 788 t.next(); 789 pat = patternStep(CHILD_AXIS, lppat, prev, connector); 790 } else if (t.currentTokenValue.equals("attribute")) { 791 t.next(); 792 pat = patternStep(ATTRIBUTE_AXIS, lppat, prev, connector); 793 } else { 794 grumble("Axis in pattern must be child or attribute"); 795 } 796 break; 797 798 case Tokenizer.STAR: 799 case Tokenizer.NAME: 800 case Tokenizer.PREFIX: 801 case Tokenizer.NODETYPE: 802 pat = patternStep(CHILD_AXIS, lppat, prev, connector); 803 break; 804 805 case Tokenizer.AT: 806 t.next(); 807 pat = patternStep(ATTRIBUTE_AXIS, lppat, prev, connector); 808 break; 809 810 case Tokenizer.FUNCTION: if (prev!=null) { 812 grumble("Function may appear only at the start of a pattern"); 813 } 814 if (t.currentTokenValue.equals("id")) { 815 t.next(); 816 expect(Tokenizer.LITERAL); 817 pat = new IDPattern(t.currentTokenValue); 818 pat.setStaticContext(env); 819 t.next(); 820 expect(Tokenizer.RPAR); 821 t.next(); 822 } else if (t.currentTokenValue.equals("key")) { 823 t.next(); 824 expect(Tokenizer.LITERAL); 825 String keyname = t.currentTokenValue; 826 t.next(); 827 expect(Tokenizer.COMMA); 828 t.next(); 829 expect(Tokenizer.LITERAL); 830 if (!env.allowsKeyFunction()) { 831 grumble("key() function cannot be used here"); 832 } 833 pat = new KeyPattern(env.makeNameCode(keyname, false), 834 t.currentTokenValue); 835 pat.setStaticContext(env); 836 t.next(); 837 expect(Tokenizer.RPAR); 838 t.next(); 839 } else { 840 grumble("The only functions allowed in a pattern are id() and key()"); 841 } 842 break; 843 844 default: 845 if (rootonly) return prev; 846 grumble("Unexpected token in pattern, found " + Tokenizer.tokens[t.currentToken]); 847 } 848 849 connector = t.currentToken; 850 rootonly = false; 851 more = (connector == Tokenizer.SLASH || connector == Tokenizer.SLSL); 852 if (more) { 853 prev = pat; 854 lppat = new LocationPathPattern(); 855 lppat.setStaticContext(env); 856 if (connector==Tokenizer.SLASH) { 857 lppat.parentPattern = prev; 858 } else { lppat.ancestorPattern = prev; 860 } 861 t.next(); 862 } 863 } 864 pat.setStaticContext(env); 865 return pat; 866 867 } 868 869 private Pattern patternStep(int axis, LocationPathPattern lppat, Pattern prev, int connector) 870 throws XPathException { 871 872 if (axis==CHILD_AXIS) { 873 if (t.currentToken==Tokenizer.STAR) { 874 lppat.nodeTest = new NodeTypeTest(NodeInfo.ELEMENT); 875 } else if (t.currentToken==Tokenizer.NAME) { 876 lppat.nodeTest = env.makeNameTest(NodeInfo.ELEMENT, 877 t.currentTokenValue, false); 878 } else if (t.currentToken==Tokenizer.PREFIX) { 879 lppat.nodeTest = env.makeNamespaceTest(NodeInfo.ELEMENT, 880 t.currentTokenValue); 881 } else if (t.currentToken==Tokenizer.NODETYPE) { 882 String nodetype = t.currentTokenValue; t.next(); 884 if (nodetype=="text") { 885 lppat.nodeTest = new NodeTypeTest(NodeInfo.TEXT); 886 } else if (nodetype=="node") { 887 lppat.nodeTest = new AnyChildNodePattern(); 888 } else if (nodetype=="comment") { 889 lppat.nodeTest = new NodeTypeTest(NodeInfo.COMMENT); 890 } else if (nodetype=="processing-instruction") { 891 if (t.currentToken == Tokenizer.LITERAL) { 893 if (Name.isNCName(t.currentTokenValue)) { 894 lppat.nodeTest = env.makeNameTest(NodeInfo.PI, 895 t.currentTokenValue, false); 896 } else { 897 lppat.nodeTest = NoNodeTest.getInstance(); 899 } 900 t.next(); 901 } else { 902 lppat.nodeTest = new NodeTypeTest(NodeInfo.PI); 903 } 904 } 905 expect(Tokenizer.RPAR); 906 } else { 907 grumble("Unexpected token in pattern, found " + Tokenizer.tokens[t.currentToken]); 908 } 909 910 if (prev!=null) { 911 if (connector==Tokenizer.SLASH) { 912 lppat.parentPattern = prev; 913 } else { lppat.ancestorPattern = prev; 915 } 916 } 917 t.next(); 918 parseFilters(lppat); 919 return lppat; 920 921 } else if (axis==ATTRIBUTE_AXIS) { 922 923 if (t.currentToken==Tokenizer.STAR) { 924 lppat.nodeTest = new NodeTypeTest(NodeInfo.ATTRIBUTE); 925 } else if (t.currentToken==Tokenizer.NAME) { 926 lppat.nodeTest = env.makeNameTest(NodeInfo.ATTRIBUTE, 927 t.currentTokenValue, false); 928 } else if (t.currentToken==Tokenizer.PREFIX) { 929 lppat.nodeTest = env.makeNamespaceTest(NodeInfo.ATTRIBUTE, 930 t.currentTokenValue); 931 } else if (t.currentToken==Tokenizer.NODETYPE) { 932 String nodetype = t.currentTokenValue; t.next(); 934 if (nodetype=="text") { 937 lppat.nodeTest = NoNodeTest.getInstance(); 938 } else if (nodetype=="node") { 939 lppat.nodeTest = new NodeTypeTest(NodeInfo.ATTRIBUTE); 940 } else if (nodetype=="comment") { 941 lppat.nodeTest = NoNodeTest.getInstance(); 942 } else if (nodetype=="processing-instruction") { 943 lppat.nodeTest = NoNodeTest.getInstance(); 945 if (t.currentToken == Tokenizer.LITERAL) { 946 t.next(); 948 } 949 } 950 expect(Tokenizer.RPAR); 951 952 } else { 953 grumble("@ in pattern not followed by NameTest or NodeTest"); 954 } 955 t.next(); 956 parseFilters(lppat); 957 return lppat; 958 959 } else { 960 grumble("Axis in pattern must be child or attribute"); 961 return null; 962 } 963 } 964 965 968 969 private void parseFilters(LocationPathPattern path) throws XPathException { 970 while (t.currentToken == Tokenizer.LSQB) { 971 t.next(); 972 Expression qual = parseExpression(); 973 expect(Tokenizer.RSQB); 974 t.next(); 975 path.addFilter(qual); 976 if (qual.usesCurrent()) { 977 grumble("The current() function may not be used in a pattern"); 978 } 979 } 980 } 981 982 } 983 984 | Popular Tags |