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: Compiler.java 468655 2006-10-28 07:12:06Z minchau $ 020 */ 021 package org.apache.xpath.compiler; 022 023 import javax.xml.transform.ErrorListener; 024 import javax.xml.transform.SourceLocator; 025 import javax.xml.transform.TransformerException; 026 027 import org.apache.xalan.res.XSLMessages; 028 import org.apache.xml.dtm.Axis; 029 import org.apache.xml.dtm.DTMFilter; 030 import org.apache.xml.dtm.DTMIterator; 031 import org.apache.xml.utils.PrefixResolver; 032 import org.apache.xml.utils.QName; 033 import org.apache.xml.utils.SAXSourceLocator; 034 import org.apache.xpath.Expression; 035 import org.apache.xpath.axes.UnionPathIterator; 036 import org.apache.xpath.axes.WalkerFactory; 037 import org.apache.xpath.functions.FuncExtFunction; 038 import org.apache.xpath.functions.FuncExtFunctionAvailable; 039 import org.apache.xpath.functions.Function; 040 import org.apache.xpath.functions.WrongNumberArgsException; 041 import org.apache.xpath.objects.XNumber; 042 import org.apache.xpath.objects.XString; 043 import org.apache.xpath.operations.And; 044 import org.apache.xpath.operations.Div; 045 import org.apache.xpath.operations.Equals; 046 import org.apache.xpath.operations.Gt; 047 import org.apache.xpath.operations.Gte; 048 import org.apache.xpath.operations.Lt; 049 import org.apache.xpath.operations.Lte; 050 import org.apache.xpath.operations.Minus; 051 import org.apache.xpath.operations.Mod; 052 import org.apache.xpath.operations.Mult; 053 import org.apache.xpath.operations.Neg; 054 import org.apache.xpath.operations.NotEquals; 055 import org.apache.xpath.operations.Operation; 056 import org.apache.xpath.operations.Or; 057 import org.apache.xpath.operations.Plus; 058 import org.apache.xpath.operations.UnaryOperation; 059 import org.apache.xpath.operations.Variable; 060 import org.apache.xpath.patterns.FunctionPattern; 061 import org.apache.xpath.patterns.NodeTest; 062 import org.apache.xpath.patterns.StepPattern; 063 import org.apache.xpath.patterns.UnionPattern; 064 import org.apache.xpath.res.XPATHErrorResources; 065 066 /** 067 * An instance of this class compiles an XPath string expression into 068 * a Expression object. This class compiles the string into a sequence 069 * of operation codes (op map) and then builds from that into an Expression 070 * tree. 071 * @xsl.usage advanced 072 */ 073 public class Compiler extends OpMap 074 { 075 076 /** 077 * Construct a Compiler object with a specific ErrorListener and 078 * SourceLocator where the expression is located. 079 * 080 * @param errorHandler Error listener where messages will be sent, or null 081 * if messages should be sent to System err. 082 * @param locator The location object where the expression lives, which 083 * may be null, but which, if not null, must be valid over 084 * the long haul, in other words, it will not be cloned. 085 * @param fTable The FunctionTable object where the xpath build-in 086 * functions are stored. 087 */ 088 public Compiler(ErrorListener errorHandler, SourceLocator locator, 089 FunctionTable fTable) 090 { 091 m_errorHandler = errorHandler; 092 m_locator = locator; 093 m_functionTable = fTable; 094 } 095 096 /** 097 * Construct a Compiler instance that has a null error listener and a 098 * null source locator. 099 */ 100 public Compiler() 101 { 102 m_errorHandler = null; 103 m_locator = null; 104 } 105 106 /** 107 * Execute the XPath object from a given opcode position. 108 * @param opPos The current position in the xpath.m_opMap array. 109 * @return The result of the XPath. 110 * 111 * @throws TransformerException if there is a syntax or other error. 112 * @xsl.usage advanced 113 */ 114 public Expression compile(int opPos) throws TransformerException 115 { 116 117 int op = getOp(opPos); 118 119 Expression expr = null; 120 // System.out.println(getPatternString()+"op: "+op); 121 switch (op) 122 { 123 case OpCodes.OP_XPATH : 124 expr = compile(opPos + 2); break; 125 case OpCodes.OP_OR : 126 expr = or(opPos); break; 127 case OpCodes.OP_AND : 128 expr = and(opPos); break; 129 case OpCodes.OP_NOTEQUALS : 130 expr = notequals(opPos); break; 131 case OpCodes.OP_EQUALS : 132 expr = equals(opPos); break; 133 case OpCodes.OP_LTE : 134 expr = lte(opPos); break; 135 case OpCodes.OP_LT : 136 expr = lt(opPos); break; 137 case OpCodes.OP_GTE : 138 expr = gte(opPos); break; 139 case OpCodes.OP_GT : 140 expr = gt(opPos); break; 141 case OpCodes.OP_PLUS : 142 expr = plus(opPos); break; 143 case OpCodes.OP_MINUS : 144 expr = minus(opPos); break; 145 case OpCodes.OP_MULT : 146 expr = mult(opPos); break; 147 case OpCodes.OP_DIV : 148 expr = div(opPos); break; 149 case OpCodes.OP_MOD : 150 expr = mod(opPos); break; 151 // case OpCodes.OP_QUO : 152 // expr = quo(opPos); break; 153 case OpCodes.OP_NEG : 154 expr = neg(opPos); break; 155 case OpCodes.OP_STRING : 156 expr = string(opPos); break; 157 case OpCodes.OP_BOOL : 158 expr = bool(opPos); break; 159 case OpCodes.OP_NUMBER : 160 expr = number(opPos); break; 161 case OpCodes.OP_UNION : 162 expr = union(opPos); break; 163 case OpCodes.OP_LITERAL : 164 expr = literal(opPos); break; 165 case OpCodes.OP_VARIABLE : 166 expr = variable(opPos); break; 167 case OpCodes.OP_GROUP : 168 expr = group(opPos); break; 169 case OpCodes.OP_NUMBERLIT : 170 expr = numberlit(opPos); break; 171 case OpCodes.OP_ARGUMENT : 172 expr = arg(opPos); break; 173 case OpCodes.OP_EXTFUNCTION : 174 expr = compileExtension(opPos); break; 175 case OpCodes.OP_FUNCTION : 176 expr = compileFunction(opPos); break; 177 case OpCodes.OP_LOCATIONPATH : 178 expr = locationPath(opPos); break; 179 case OpCodes.OP_PREDICATE : 180 expr = null; break; // should never hit this here. 181 case OpCodes.OP_MATCHPATTERN : 182 expr = matchPattern(opPos + 2); break; 183 case OpCodes.OP_LOCATIONPATHPATTERN : 184 expr = locationPathPattern(opPos); break; 185 case OpCodes.OP_QUO: 186 error(XPATHErrorResources.ER_UNKNOWN_OPCODE, 187 new Object[]{ "quo" }); //"ERROR! Unknown op code: "+m_opMap[opPos]); 188 break; 189 default : 190 error(XPATHErrorResources.ER_UNKNOWN_OPCODE, 191 new Object[]{ Integer.toString(getOp(opPos)) }); //"ERROR! Unknown op code: "+m_opMap[opPos]); 192 } 193 // if(null != expr) 194 // expr.setSourceLocator(m_locator); 195 196 return expr; 197 } 198 199 /** 200 * Bottle-neck compilation of an operation with left and right operands. 201 * 202 * @param operation non-null reference to parent operation. 203 * @param opPos The op map position of the parent operation. 204 * 205 * @return reference to {@link org.apache.xpath.operations.Operation} instance. 206 * 207 * @throws TransformerException if there is a syntax or other error. 208 */ 209 private Expression compileOperation(Operation operation, int opPos) 210 throws TransformerException 211 { 212 213 int leftPos = getFirstChildPos(opPos); 214 int rightPos = getNextOpPos(leftPos); 215 216 operation.setLeftRight(compile(leftPos), compile(rightPos)); 217 218 return operation; 219 } 220 221 /** 222 * Bottle-neck compilation of a unary operation. 223 * 224 * @param unary The parent unary operation. 225 * @param opPos The position in the op map of the parent operation. 226 * 227 * @return The unary argument. 228 * 229 * @throws TransformerException if syntax or other error occurs. 230 */ 231 private Expression compileUnary(UnaryOperation unary, int opPos) 232 throws TransformerException 233 { 234 235 int rightPos = getFirstChildPos(opPos); 236 237 unary.setRight(compile(rightPos)); 238 239 return unary; 240 } 241 242 /** 243 * Compile an 'or' operation. 244 * 245 * @param opPos The current position in the m_opMap array. 246 * 247 * @return reference to {@link org.apache.xpath.operations.Or} instance. 248 * 249 * @throws TransformerException if a error occurs creating the Expression. 250 */ 251 protected Expression or(int opPos) throws TransformerException 252 { 253 return compileOperation(new Or(), opPos); 254 } 255 256 /** 257 * Compile an 'and' operation. 258 * 259 * @param opPos The current position in the m_opMap array. 260 * 261 * @return reference to {@link org.apache.xpath.operations.And} instance. 262 * 263 * @throws TransformerException if a error occurs creating the Expression. 264 */ 265 protected Expression and(int opPos) throws TransformerException 266 { 267 return compileOperation(new And(), opPos); 268 } 269 270 /** 271 * Compile a '!=' operation. 272 * 273 * @param opPos The current position in the m_opMap array. 274 * 275 * @return reference to {@link org.apache.xpath.operations.NotEquals} instance. 276 * 277 * @throws TransformerException if a error occurs creating the Expression. 278 */ 279 protected Expression notequals(int opPos) throws TransformerException 280 { 281 return compileOperation(new NotEquals(), opPos); 282 } 283 284 /** 285 * Compile a '=' operation. 286 * 287 * @param opPos The current position in the m_opMap array. 288 * 289 * @return reference to {@link org.apache.xpath.operations.Equals} instance. 290 * 291 * @throws TransformerException if a error occurs creating the Expression. 292 */ 293 protected Expression equals(int opPos) throws TransformerException 294 { 295 return compileOperation(new Equals(), opPos); 296 } 297 298 /** 299 * Compile a '<=' operation. 300 * 301 * @param opPos The current position in the m_opMap array. 302 * 303 * @return reference to {@link org.apache.xpath.operations.Lte} instance. 304 * 305 * @throws TransformerException if a error occurs creating the Expression. 306 */ 307 protected Expression lte(int opPos) throws TransformerException 308 { 309 return compileOperation(new Lte(), opPos); 310 } 311 312 /** 313 * Compile a '<' operation. 314 * 315 * @param opPos The current position in the m_opMap array. 316 * 317 * @return reference to {@link org.apache.xpath.operations.Lt} instance. 318 * 319 * @throws TransformerException if a error occurs creating the Expression. 320 */ 321 protected Expression lt(int opPos) throws TransformerException 322 { 323 return compileOperation(new Lt(), opPos); 324 } 325 326 /** 327 * Compile a '>=' operation. 328 * 329 * @param opPos The current position in the m_opMap array. 330 * 331 * @return reference to {@link org.apache.xpath.operations.Gte} instance. 332 * 333 * @throws TransformerException if a error occurs creating the Expression. 334 */ 335 protected Expression gte(int opPos) throws TransformerException 336 { 337 return compileOperation(new Gte(), opPos); 338 } 339 340 /** 341 * Compile a '>' operation. 342 * 343 * @param opPos The current position in the m_opMap array. 344 * 345 * @return reference to {@link org.apache.xpath.operations.Gt} instance. 346 * 347 * @throws TransformerException if a error occurs creating the Expression. 348 */ 349 protected Expression gt(int opPos) throws TransformerException 350 { 351 return compileOperation(new Gt(), opPos); 352 } 353 354 /** 355 * Compile a '+' operation. 356 * 357 * @param opPos The current position in the m_opMap array. 358 * 359 * @return reference to {@link org.apache.xpath.operations.Plus} instance. 360 * 361 * @throws TransformerException if a error occurs creating the Expression. 362 */ 363 protected Expression plus(int opPos) throws TransformerException 364 { 365 return compileOperation(new Plus(), opPos); 366 } 367 368 /** 369 * Compile a '-' operation. 370 * 371 * @param opPos The current position in the m_opMap array. 372 * 373 * @return reference to {@link org.apache.xpath.operations.Minus} instance. 374 * 375 * @throws TransformerException if a error occurs creating the Expression. 376 */ 377 protected Expression minus(int opPos) throws TransformerException 378 { 379 return compileOperation(new Minus(), opPos); 380 } 381 382 /** 383 * Compile a '*' operation. 384 * 385 * @param opPos The current position in the m_opMap array. 386 * 387 * @return reference to {@link org.apache.xpath.operations.Mult} instance. 388 * 389 * @throws TransformerException if a error occurs creating the Expression. 390 */ 391 protected Expression mult(int opPos) throws TransformerException 392 { 393 return compileOperation(new Mult(), opPos); 394 } 395 396 /** 397 * Compile a 'div' operation. 398 * 399 * @param opPos The current position in the m_opMap array. 400 * 401 * @return reference to {@link org.apache.xpath.operations.Div} instance. 402 * 403 * @throws TransformerException if a error occurs creating the Expression. 404 */ 405 protected Expression div(int opPos) throws TransformerException 406 { 407 return compileOperation(new Div(), opPos); 408 } 409 410 /** 411 * Compile a 'mod' operation. 412 * 413 * @param opPos The current position in the m_opMap array. 414 * 415 * @return reference to {@link org.apache.xpath.operations.Mod} instance. 416 * 417 * @throws TransformerException if a error occurs creating the Expression. 418 */ 419 protected Expression mod(int opPos) throws TransformerException 420 { 421 return compileOperation(new Mod(), opPos); 422 } 423 424 /* 425 * Compile a 'quo' operation. 426 * 427 * @param opPos The current position in the m_opMap array. 428 * 429 * @return reference to {@link org.apache.xpath.operations.Quo} instance. 430 * 431 * @throws TransformerException if a error occurs creating the Expression. 432 */ 433 // protected Expression quo(int opPos) throws TransformerException 434 // { 435 // return compileOperation(new Quo(), opPos); 436 // } 437 438 /** 439 * Compile a unary '-' operation. 440 * 441 * @param opPos The current position in the m_opMap array. 442 * 443 * @return reference to {@link org.apache.xpath.operations.Neg} instance. 444 * 445 * @throws TransformerException if a error occurs creating the Expression. 446 */ 447 protected Expression neg(int opPos) throws TransformerException 448 { 449 return compileUnary(new Neg(), opPos); 450 } 451 452 /** 453 * Compile a 'string(...)' operation. 454 * 455 * @param opPos The current position in the m_opMap array. 456 * 457 * @return reference to {@link org.apache.xpath.operations.String} instance. 458 * 459 * @throws TransformerException if a error occurs creating the Expression. 460 */ 461 protected Expression string(int opPos) throws TransformerException 462 { 463 return compileUnary(new org.apache.xpath.operations.String(), opPos); 464 } 465 466 /** 467 * Compile a 'boolean(...)' operation. 468 * 469 * @param opPos The current position in the m_opMap array. 470 * 471 * @return reference to {@link org.apache.xpath.operations.Bool} instance. 472 * 473 * @throws TransformerException if a error occurs creating the Expression. 474 */ 475 protected Expression bool(int opPos) throws TransformerException 476 { 477 return compileUnary(new org.apache.xpath.operations.Bool(), opPos); 478 } 479 480 /** 481 * Compile a 'number(...)' operation. 482 * 483 * @param opPos The current position in the m_opMap array. 484 * 485 * @return reference to {@link org.apache.xpath.operations.Number} instance. 486 * 487 * @throws TransformerException if a error occurs creating the Expression. 488 */ 489 protected Expression number(int opPos) throws TransformerException 490 { 491 return compileUnary(new org.apache.xpath.operations.Number(), opPos); 492 } 493 494 /** 495 * Compile a literal string value. 496 * 497 * @param opPos The current position in the m_opMap array. 498 * 499 * @return reference to {@link org.apache.xpath.objects.XString} instance. 500 * 501 * @throws TransformerException if a error occurs creating the Expression. 502 */ 503 protected Expression literal(int opPos) 504 { 505 506 opPos = getFirstChildPos(opPos); 507 508 return (XString) getTokenQueue().elementAt(getOp(opPos)); 509 } 510 511 /** 512 * Compile a literal number value. 513 * 514 * @param opPos The current position in the m_opMap array. 515 * 516 * @return reference to {@link org.apache.xpath.objects.XNumber} instance. 517 * 518 * @throws TransformerException if a error occurs creating the Expression. 519 */ 520 protected Expression numberlit(int opPos) 521 { 522 523 opPos = getFirstChildPos(opPos); 524 525 return (XNumber) getTokenQueue().elementAt(getOp(opPos)); 526 } 527 528 /** 529 * Compile a variable reference. 530 * 531 * @param opPos The current position in the m_opMap array. 532 * 533 * @return reference to {@link org.apache.xpath.operations.Variable} instance. 534 * 535 * @throws TransformerException if a error occurs creating the Expression. 536 */ 537 protected Expression variable(int opPos) throws TransformerException 538 { 539 540 Variable var = new Variable(); 541 542 opPos = getFirstChildPos(opPos); 543 544 int nsPos = getOp(opPos); 545 java.lang.String namespace 546 = (OpCodes.EMPTY == nsPos) ? null 547 : (java.lang.String) getTokenQueue().elementAt(nsPos); 548 java.lang.String localname 549 = (java.lang.String) getTokenQueue().elementAt(getOp(opPos+1)); 550 QName qname = new QName(namespace, localname); 551 552 var.setQName(qname); 553 554 return var; 555 } 556 557 /** 558 * Compile an expression group. 559 * 560 * @param opPos The current position in the m_opMap array. 561 * 562 * @return reference to the contained expression. 563 * 564 * @throws TransformerException if a error occurs creating the Expression. 565 */ 566 protected Expression group(int opPos) throws TransformerException 567 { 568 569 // no-op 570 return compile(opPos + 2); 571 } 572 573 /** 574 * Compile a function argument. 575 * 576 * @param opPos The current position in the m_opMap array. 577 * 578 * @return reference to the argument expression. 579 * 580 * @throws TransformerException if a error occurs creating the Expression. 581 */ 582 protected Expression arg(int opPos) throws TransformerException 583 { 584 585 // no-op 586 return compile(opPos + 2); 587 } 588 589 /** 590 * Compile a location path union. The UnionPathIterator itself may create 591 * {@link org.apache.xpath.axes.LocPathIterator} children. 592 * 593 * @param opPos The current position in the m_opMap array. 594 * 595 * @return reference to {@link org.apache.xpath.axes.LocPathIterator} instance. 596 * 597 * @throws TransformerException if a error occurs creating the Expression. 598 */ 599 protected Expression union(int opPos) throws TransformerException 600 { 601 locPathDepth++; 602 try 603 { 604 return UnionPathIterator.createUnionIterator(this, opPos); 605 } 606 finally 607 { 608 locPathDepth--; 609 } 610 } 611 612 private int locPathDepth = -1; 613 614 /** 615 * Get the level of the location path or union being constructed. 616 * @return 0 if it is a top-level path. 617 */ 618 public int getLocationPathDepth() 619 { 620 return locPathDepth; 621 } 622 623 /** 624 * Get the function table 625 */ 626 FunctionTable getFunctionTable() 627 { 628 return m_functionTable; 629 } 630 631 /** 632 * Compile a location path. The LocPathIterator itself may create 633 * {@link org.apache.xpath.axes.AxesWalker} children. 634 * 635 * @param opPos The current position in the m_opMap array. 636 * 637 * @return reference to {@link org.apache.xpath.axes.LocPathIterator} instance. 638 * 639 * @throws TransformerException if a error occurs creating the Expression. 640 */ 641 public Expression locationPath(int opPos) throws TransformerException 642 { 643 locPathDepth++; 644 try 645 { 646 DTMIterator iter = WalkerFactory.newDTMIterator(this, opPos, (locPathDepth == 0)); 647 return (Expression)iter; // cast OK, I guess. 648 } 649 finally 650 { 651 locPathDepth--; 652 } 653 } 654 655 /** 656 * Compile a location step predicate expression. 657 * 658 * @param opPos The current position in the m_opMap array. 659 * 660 * @return the contained predicate expression. 661 * 662 * @throws TransformerException if a error occurs creating the Expression. 663 */ 664 public Expression predicate(int opPos) throws TransformerException 665 { 666 return compile(opPos + 2); 667 } 668 669 /** 670 * Compile an entire match pattern expression. 671 * 672 * @param opPos The current position in the m_opMap array. 673 * 674 * @return reference to {@link org.apache.xpath.patterns.UnionPattern} instance. 675 * 676 * @throws TransformerException if a error occurs creating the Expression. 677 */ 678 protected Expression matchPattern(int opPos) throws TransformerException 679 { 680 locPathDepth++; 681 try 682 { 683 // First, count... 684 int nextOpPos = opPos; 685 int i; 686 687 for (i = 0; getOp(nextOpPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++) 688 { 689 nextOpPos = getNextOpPos(nextOpPos); 690 } 691 692 if (i == 1) 693 return compile(opPos); 694 695 UnionPattern up = new UnionPattern(); 696 StepPattern[] patterns = new StepPattern[i]; 697 698 for (i = 0; getOp(opPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++) 699 { 700 nextOpPos = getNextOpPos(opPos); 701 patterns[i] = (StepPattern) compile(opPos); 702 opPos = nextOpPos; 703 } 704 705 up.setPatterns(patterns); 706 707 return up; 708 } 709 finally 710 { 711 locPathDepth--; 712 } 713 } 714 715 /** 716 * Compile a location match pattern unit expression. 717 * 718 * @param opPos The current position in the m_opMap array. 719 * 720 * @return reference to {@link org.apache.xpath.patterns.StepPattern} instance. 721 * 722 * @throws TransformerException if a error occurs creating the Expression. 723 */ 724 public Expression locationPathPattern(int opPos) 725 throws TransformerException 726 { 727 728 opPos = getFirstChildPos(opPos); 729 730 return stepPattern(opPos, 0, null); 731 } 732 733 /** 734 * Get a {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what 735 * to show for a given node test. 736 * 737 * @param opPos the op map position for the location step. 738 * 739 * @return {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what 740 * to show for a given node test. 741 */ 742 public int getWhatToShow(int opPos) 743 { 744 745 int axesType = getOp(opPos); 746 int testType = getOp(opPos + 3); 747 748 // System.out.println("testType: "+testType); 749 switch (testType) 750 { 751 case OpCodes.NODETYPE_COMMENT : 752 return DTMFilter.SHOW_COMMENT; 753 case OpCodes.NODETYPE_TEXT : 754 // return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_COMMENT; 755 return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_CDATA_SECTION ; 756 case OpCodes.NODETYPE_PI : 757 return DTMFilter.SHOW_PROCESSING_INSTRUCTION; 758 case OpCodes.NODETYPE_NODE : 759 // return DTMFilter.SHOW_ALL; 760 switch (axesType) 761 { 762 case OpCodes.FROM_NAMESPACE: 763 return DTMFilter.SHOW_NAMESPACE; 764 case OpCodes.FROM_ATTRIBUTES : 765 case OpCodes.MATCH_ATTRIBUTE : 766 return DTMFilter.SHOW_ATTRIBUTE; 767 case OpCodes.FROM_SELF: 768 case OpCodes.FROM_ANCESTORS_OR_SELF: 769 case OpCodes.FROM_DESCENDANTS_OR_SELF: 770 return DTMFilter.SHOW_ALL; 771 default: 772 if (getOp(0) == OpCodes.OP_MATCHPATTERN) 773 return ~DTMFilter.SHOW_ATTRIBUTE 774 & ~DTMFilter.SHOW_DOCUMENT 775 & ~DTMFilter.SHOW_DOCUMENT_FRAGMENT; 776 else 777 return ~DTMFilter.SHOW_ATTRIBUTE; 778 } 779 case OpCodes.NODETYPE_ROOT : 780 return DTMFilter.SHOW_DOCUMENT | DTMFilter.SHOW_DOCUMENT_FRAGMENT; 781 case OpCodes.NODETYPE_FUNCTEST : 782 return NodeTest.SHOW_BYFUNCTION; 783 case OpCodes.NODENAME : 784 switch (axesType) 785 { 786 case OpCodes.FROM_NAMESPACE : 787 return DTMFilter.SHOW_NAMESPACE; 788 case OpCodes.FROM_ATTRIBUTES : 789 case OpCodes.MATCH_ATTRIBUTE : 790 return DTMFilter.SHOW_ATTRIBUTE; 791 792 // break; 793 case OpCodes.MATCH_ANY_ANCESTOR : 794 case OpCodes.MATCH_IMMEDIATE_ANCESTOR : 795 return DTMFilter.SHOW_ELEMENT; 796 797 // break; 798 default : 799 return DTMFilter.SHOW_ELEMENT; 800 } 801 default : 802 // System.err.println("We should never reach here."); 803 return DTMFilter.SHOW_ALL; 804 } 805 } 806 807 private static final boolean DEBUG = false; 808 809 /** 810 * Compile a step pattern unit expression, used for both location paths 811 * and match patterns. 812 * 813 * @param opPos The current position in the m_opMap array. 814 * @param stepCount The number of steps to expect. 815 * @param ancestorPattern The owning StepPattern, which may be null. 816 * 817 * @return reference to {@link org.apache.xpath.patterns.StepPattern} instance. 818 * 819 * @throws TransformerException if a error occurs creating the Expression. 820 */ 821 protected StepPattern stepPattern( 822 int opPos, int stepCount, StepPattern ancestorPattern) 823 throws TransformerException 824 { 825 826 int startOpPos = opPos; 827 int stepType = getOp(opPos); 828 829 if (OpCodes.ENDOP == stepType) 830 { 831 return null; 832 } 833 834 boolean addMagicSelf = true; 835 836 int endStep = getNextOpPos(opPos); 837 838 // int nextStepType = getOpMap()[endStep]; 839 StepPattern pattern; 840 841 // boolean isSimple = ((OpCodes.ENDOP == nextStepType) && (stepCount == 0)); 842 int argLen; 843 844 switch (stepType) 845 { 846 case OpCodes.OP_FUNCTION : 847 if(DEBUG) 848 System.out.println("MATCH_FUNCTION: "+m_currentPattern); 849 addMagicSelf = false; 850 argLen = getOp(opPos + OpMap.MAPINDEX_LENGTH); 851 pattern = new FunctionPattern(compileFunction(opPos), Axis.PARENT, Axis.CHILD); 852 break; 853 case OpCodes.FROM_ROOT : 854 if(DEBUG) 855 System.out.println("FROM_ROOT, "+m_currentPattern); 856 addMagicSelf = false; 857 argLen = getArgLengthOfStep(opPos); 858 opPos = getFirstChildPosOfStep(opPos); 859 pattern = new StepPattern(DTMFilter.SHOW_DOCUMENT | 860 DTMFilter.SHOW_DOCUMENT_FRAGMENT, 861 Axis.PARENT, Axis.CHILD); 862 break; 863 case OpCodes.MATCH_ATTRIBUTE : 864 if(DEBUG) 865 System.out.println("MATCH_ATTRIBUTE: "+getStepLocalName(startOpPos)+", "+m_currentPattern); 866 argLen = getArgLengthOfStep(opPos); 867 opPos = getFirstChildPosOfStep(opPos); 868 pattern = new StepPattern(DTMFilter.SHOW_ATTRIBUTE, 869 getStepNS(startOpPos), 870 getStepLocalName(startOpPos), 871 Axis.PARENT, Axis.ATTRIBUTE); 872 break; 873 case OpCodes.MATCH_ANY_ANCESTOR : 874 if(DEBUG) 875 System.out.println("MATCH_ANY_ANCESTOR: "+getStepLocalName(startOpPos)+", "+m_currentPattern); 876 argLen = getArgLengthOfStep(opPos); 877 opPos = getFirstChildPosOfStep(opPos); 878 int what = getWhatToShow(startOpPos); 879 // bit-o-hackery, but this code is due for the morgue anyway... 880 if(0x00000500 == what) 881 addMagicSelf = false; 882 pattern = new StepPattern(getWhatToShow(startOpPos), 883 getStepNS(startOpPos), 884 getStepLocalName(startOpPos), 885 Axis.ANCESTOR, Axis.CHILD); 886 break; 887 case OpCodes.MATCH_IMMEDIATE_ANCESTOR : 888 if(DEBUG) 889 System.out.println("MATCH_IMMEDIATE_ANCESTOR: "+getStepLocalName(startOpPos)+", "+m_currentPattern); 890 argLen = getArgLengthOfStep(opPos); 891 opPos = getFirstChildPosOfStep(opPos); 892 pattern = new StepPattern(getWhatToShow(startOpPos), 893 getStepNS(startOpPos), 894 getStepLocalName(startOpPos), 895 Axis.PARENT, Axis.CHILD); 896 break; 897 default : 898 error(XPATHErrorResources.ER_UNKNOWN_MATCH_OPERATION, null); //"unknown match operation!"); 899 900 return null; 901 } 902 903 pattern.setPredicates(getCompiledPredicates(opPos + argLen)); 904 if(null == ancestorPattern) 905 { 906 // This is the magic and invisible "." at the head of every 907 // match pattern, and corresponds to the current node in the context 908 // list, from where predicates are counted. 909 // So, in order to calculate "foo[3]", it has to count from the 910 // current node in the context list, so, from that current node, 911 // the full pattern is really "self::node()/child::foo[3]". If you 912 // translate this to a select pattern from the node being tested, 913 // which is really how we're treating match patterns, it works out to 914 // self::foo/parent::node[child::foo[3]]", or close enough. 915 /* if(addMagicSelf && pattern.getPredicateCount() > 0) 916 { 917 StepPattern selfPattern = new StepPattern(DTMFilter.SHOW_ALL, 918 Axis.PARENT, Axis.CHILD); 919 // We need to keep the new nodetest from affecting the score... 920 XNumber score = pattern.getStaticScore(); 921 pattern.setRelativePathPattern(selfPattern); 922 pattern.setStaticScore(score); 923 selfPattern.setStaticScore(score); 924 }*/ 925 } 926 else 927 { 928 // System.out.println("Setting "+ancestorPattern+" as relative to "+pattern); 929 pattern.setRelativePathPattern(ancestorPattern); 930 } 931 932 StepPattern relativePathPattern = stepPattern(endStep, stepCount + 1, 933 pattern); 934 935 return (null != relativePathPattern) ? relativePathPattern : pattern; 936 } 937 938 /** 939 * Compile a zero or more predicates for a given match pattern. 940 * 941 * @param opPos The position of the first predicate the m_opMap array. 942 * 943 * @return reference to array of {@link org.apache.xpath.Expression} instances. 944 * 945 * @throws TransformerException if a error occurs creating the Expression. 946 */ 947 public Expression[] getCompiledPredicates(int opPos) 948 throws TransformerException 949 { 950 951 int count = countPredicates(opPos); 952 953 if (count > 0) 954 { 955 Expression[] predicates = new Expression[count]; 956 957 compilePredicates(opPos, predicates); 958 959 return predicates; 960 } 961 962 return null; 963 } 964 965 /** 966 * Count the number of predicates in the step. 967 * 968 * @param opPos The position of the first predicate the m_opMap array. 969 * 970 * @return The number of predicates for this step. 971 * 972 * @throws TransformerException if a error occurs creating the Expression. 973 */ 974 public int countPredicates(int opPos) throws TransformerException 975 { 976 977 int count = 0; 978 979 while (OpCodes.OP_PREDICATE == getOp(opPos)) 980 { 981 count++; 982 983 opPos = getNextOpPos(opPos); 984 } 985 986 return count; 987 } 988 989 /** 990 * Compiles predicates in the step. 991 * 992 * @param opPos The position of the first predicate the m_opMap array. 993 * @param predicates An empty pre-determined array of 994 * {@link org.apache.xpath.Expression}s, that will be filled in. 995 * 996 * @throws TransformerException 997 */ 998 private void compilePredicates(int opPos, Expression[] predicates) 999 throws TransformerException 1000 { 1001 1002 for (int i = 0; OpCodes.OP_PREDICATE == getOp(opPos); i++) 1003 { 1004 predicates[i] = predicate(opPos); 1005 opPos = getNextOpPos(opPos); 1006 } 1007 } 1008 1009 /** 1010 * Compile a built-in XPath function. 1011 * 1012 * @param opPos The current position in the m_opMap array. 1013 * 1014 * @return reference to {@link org.apache.xpath.functions.Function} instance. 1015 * 1016 * @throws TransformerException if a error occurs creating the Expression. 1017 */ 1018 Expression compileFunction(int opPos) throws TransformerException 1019 { 1020 1021 int endFunc = opPos + getOp(opPos + 1) - 1; 1022 1023 opPos = getFirstChildPos(opPos); 1024 1025 int funcID = getOp(opPos); 1026 1027 opPos++; 1028 1029 if (-1 != funcID) 1030 { 1031 Function func = m_functionTable.getFunction(funcID); 1032 1033 /** 1034 * It is a trick for function-available. Since the function table is an 1035 * instance field, insert this table at compilation time for later usage 1036 */ 1037 1038 if (func instanceof FuncExtFunctionAvailable) 1039 ((FuncExtFunctionAvailable) func).setFunctionTable(m_functionTable); 1040 1041 func.postCompileStep(this); 1042 1043 try 1044 { 1045 int i = 0; 1046 1047 for (int p = opPos; p < endFunc; p = getNextOpPos(p), i++) 1048 { 1049 1050 // System.out.println("argPos: "+ p); 1051 // System.out.println("argCode: "+ m_opMap[p]); 1052 func.setArg(compile(p), i); 1053 } 1054 1055 func.checkNumberArgs(i); 1056 } 1057 catch (WrongNumberArgsException wnae) 1058 { 1059 java.lang.String name = m_functionTable.getFunctionName(funcID); 1060 1061 m_errorHandler.fatalError( new TransformerException( 1062 XSLMessages.createXPATHMessage(XPATHErrorResources.ER_ONLY_ALLOWS, 1063 new Object[]{name, wnae.getMessage()}), m_locator)); 1064 //"name + " only allows " + wnae.getMessage() + " arguments", m_locator)); 1065 } 1066 1067 return func; 1068 } 1069 else 1070 { 1071 error(XPATHErrorResources.ER_FUNCTION_TOKEN_NOT_FOUND, null); //"function token not found."); 1072 1073 return null; 1074 } 1075 } 1076 1077 // The current id for extension functions. 1078 private static long s_nextMethodId = 0; 1079 1080 /** 1081 * Get the next available method id 1082 */ 1083 synchronized private long getNextMethodId() 1084 { 1085 if (s_nextMethodId == Long.MAX_VALUE) 1086 s_nextMethodId = 0; 1087 1088 return s_nextMethodId++; 1089 } 1090 1091 /** 1092 * Compile an extension function. 1093 * 1094 * @param opPos The current position in the m_opMap array. 1095 * 1096 * @return reference to {@link org.apache.xpath.functions.FuncExtFunction} instance. 1097 * 1098 * @throws TransformerException if a error occurs creating the Expression. 1099 */ 1100 private Expression compileExtension(int opPos) 1101 throws TransformerException 1102 { 1103 1104 int endExtFunc = opPos + getOp(opPos + 1) - 1; 1105 1106 opPos = getFirstChildPos(opPos); 1107 1108 java.lang.String ns = (java.lang.String) getTokenQueue().elementAt(getOp(opPos)); 1109 1110 opPos++; 1111 1112 java.lang.String funcName = 1113 (java.lang.String) getTokenQueue().elementAt(getOp(opPos)); 1114 1115 opPos++; 1116 1117 // We create a method key to uniquely identify this function so that we 1118 // can cache the object needed to invoke it. This way, we only pay the 1119 // reflection overhead on the first call. 1120 1121 Function extension = new FuncExtFunction(ns, funcName, String.valueOf(getNextMethodId())); 1122 1123 try 1124 { 1125 int i = 0; 1126 1127 while (opPos < endExtFunc) 1128 { 1129 int nextOpPos = getNextOpPos(opPos); 1130 1131 extension.setArg(this.compile(opPos), i); 1132 1133 opPos = nextOpPos; 1134 1135 i++; 1136 } 1137 } 1138 catch (WrongNumberArgsException wnae) 1139 { 1140 ; // should never happen 1141 } 1142 1143 return extension; 1144 } 1145 1146 /** 1147 * Warn the user of an problem. 1148 * 1149 * @param msg An error msgkey that corresponds to one of the constants found 1150 * in {@link org.apache.xpath.res.XPATHErrorResources}, which is 1151 * a key for a format string. 1152 * @param args An array of arguments represented in the format string, which 1153 * may be null. 1154 * 1155 * @throws TransformerException if the current ErrorListoner determines to 1156 * throw an exception. 1157 */ 1158 public void warn(String msg, Object[] args) throws TransformerException 1159 { 1160 1161 java.lang.String fmsg = XSLMessages.createXPATHWarning(msg, args); 1162 1163 if (null != m_errorHandler) 1164 { 1165 m_errorHandler.warning(new TransformerException(fmsg, m_locator)); 1166 } 1167 else 1168 { 1169 System.out.println(fmsg 1170 +"; file "+m_locator.getSystemId() 1171 +"; line "+m_locator.getLineNumber() 1172 +"; column "+m_locator.getColumnNumber()); 1173 } 1174 } 1175 1176 /** 1177 * Tell the user of an assertion error, and probably throw an 1178 * exception. 1179 * 1180 * @param b If false, a runtime exception will be thrown. 1181 * @param msg The assertion message, which should be informative. 1182 * 1183 * @throws RuntimeException if the b argument is false. 1184 */ 1185 public void assertion(boolean b, java.lang.String msg) 1186 { 1187 1188 if (!b) 1189 { 1190 java.lang.String fMsg = XSLMessages.createXPATHMessage( 1191 XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION, 1192 new Object[]{ msg }); 1193 1194 throw new RuntimeException(fMsg); 1195 } 1196 } 1197 1198 /** 1199 * Tell the user of an error, and probably throw an 1200 * exception. 1201 * 1202 * @param msg An error msgkey that corresponds to one of the constants found 1203 * in {@link org.apache.xpath.res.XPATHErrorResources}, which is 1204 * a key for a format string. 1205 * @param args An array of arguments represented in the format string, which 1206 * may be null. 1207 * 1208 * @throws TransformerException if the current ErrorListoner determines to 1209 * throw an exception. 1210 */ 1211 public void error(String msg, Object[] args) throws TransformerException 1212 { 1213 1214 java.lang.String fmsg = XSLMessages.createXPATHMessage(msg, args); 1215 1216 1217 if (null != m_errorHandler) 1218 { 1219 m_errorHandler.fatalError(new TransformerException(fmsg, m_locator)); 1220 } 1221 else 1222 { 1223 1224 // System.out.println(te.getMessage() 1225 // +"; file "+te.getSystemId() 1226 // +"; line "+te.getLineNumber() 1227 // +"; column "+te.getColumnNumber()); 1228 throw new TransformerException(fmsg, (SAXSourceLocator)m_locator); 1229 } 1230 } 1231 1232 /** 1233 * The current prefixResolver for the execution context. 1234 */ 1235 private PrefixResolver m_currentPrefixResolver = null; 1236 1237 /** 1238 * Get the current namespace context for the xpath. 1239 * 1240 * @return The current prefix resolver, *may* be null, though hopefully not. 1241 */ 1242 public PrefixResolver getNamespaceContext() 1243 { 1244 return m_currentPrefixResolver; 1245 } 1246 1247 /** 1248 * Set the current namespace context for the xpath. 1249 * 1250 * @param pr The resolver for prefixes in the XPath expression. 1251 */ 1252 public void setNamespaceContext(PrefixResolver pr) 1253 { 1254 m_currentPrefixResolver = pr; 1255 } 1256 1257 /** The error listener where errors will be sent. If this is null, errors 1258 * and warnings will be sent to System.err. May be null. */ 1259 ErrorListener m_errorHandler; 1260 1261 /** The source locator for the expression being compiled. May be null. */ 1262 SourceLocator m_locator; 1263 1264 /** 1265 * The FunctionTable for all xpath build-in functions 1266 */ 1267 private FunctionTable m_functionTable; 1268 }