| 1 57 58 package com.sun.org.apache.xerces.internal.impl.xpath; 59 60 import java.util.Vector ; 61 62 import com.sun.org.apache.xerces.internal.util.SymbolTable; 63 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 64 import com.sun.org.apache.xerces.internal.util.XMLChar; 65 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 66 import com.sun.org.apache.xerces.internal.xni.QName; 67 68 74 public class XPath { 75 76 80 private static final boolean DEBUG_ALL = false; 81 82 private static final boolean DEBUG_XPATH_PARSE = DEBUG_ALL || false; 83 84 private static final boolean DEBUG_ANY = DEBUG_XPATH_PARSE; 85 86 90 91 protected String fExpression; 92 93 94 protected SymbolTable fSymbolTable; 95 96 97 protected LocationPath[] fLocationPaths; 98 99 103 104 public XPath(String xpath, SymbolTable symbolTable, 105 NamespaceContext context) 106 throws XPathException { 107 fExpression = xpath; 108 fSymbolTable = symbolTable; 109 parseExpression(context); 110 } 112 116 120 public LocationPath[] getLocationPaths() { 121 LocationPath[] ret=new LocationPath[fLocationPaths.length]; 122 for (int i=0;i<fLocationPaths.length;i++){ 123 ret[i]=(LocationPath)fLocationPaths[i].clone(); 124 } 125 return ret; 126 } 128 129 public LocationPath getLocationPath() { 130 return (LocationPath)fLocationPaths[0].clone(); 131 } 133 137 138 public String toString() { 139 StringBuffer buf=new StringBuffer (); 140 for (int i=0;i<fLocationPaths.length;i++){ 141 if (i>0){ 142 buf.append("|"); 143 } 144 buf.append(fLocationPaths[i].toString()); 145 } 146 return buf.toString(); 147 } 149 153 160 private static void check( boolean b ) throws XPathException { 161 if(!b) throw new XPathException("c-general-xpath"); 162 } 163 164 169 private LocationPath buildLocationPath( Vector stepsVector ) throws XPathException { 170 int size = stepsVector.size(); 171 check(size!=0); 172 Step[] steps = new Step[size]; 173 stepsVector.copyInto(steps); 174 stepsVector.removeAllElements(); 175 176 return new LocationPath(steps); 177 } 178 179 183 private void parseExpression(final NamespaceContext context) 184 throws XPathException { 185 186 final XPath.Tokens xtokens = new XPath.Tokens(fSymbolTable); 188 189 XPath.Scanner scanner = new XPath.Scanner(fSymbolTable) { 191 protected void addToken(XPath.Tokens tokens, int token) 192 throws XPathException { 193 if ( 194 token == XPath.Tokens.EXPRTOKEN_ATSIGN || 195 token == XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME || 196 token == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH || 197 token == XPath.Tokens.EXPRTOKEN_PERIOD || 198 token == XPath.Tokens.EXPRTOKEN_NAMETEST_ANY || 199 token == XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE || 200 token == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH || 201 token == XPath.Tokens.EXPRTOKEN_OPERATOR_UNION 202 ) { 204 super.addToken(tokens, token); 205 return; 206 } 207 throw new XPathException("c-general-xpath"); 208 } 209 }; 210 211 int length = fExpression.length(); 212 213 boolean success = scanner.scanExpr(fSymbolTable, 214 xtokens, fExpression, 0, length); 215 if(!success) 216 throw new XPathException("c-general-xpath"); 217 218 Vector stepsVector = new Vector (); 220 Vector locationPathsVector= new Vector (); 221 222 boolean expectingStep = true; 229 230 while(xtokens.hasMore()) { 231 final int token = xtokens.nextToken(); 232 233 switch (token) { 234 case XPath.Tokens.EXPRTOKEN_OPERATOR_UNION :{ 235 check(!expectingStep); 236 locationPathsVector.addElement(buildLocationPath(stepsVector)); 237 expectingStep=true; 238 break; 239 } 240 241 case XPath.Tokens.EXPRTOKEN_ATSIGN: { 242 check(expectingStep); 243 Step step = new Step( 244 new Axis(Axis.ATTRIBUTE), 245 parseNodeTest(xtokens.nextToken(),xtokens,context)); 246 stepsVector.addElement(step); 247 expectingStep=false; 248 break; 249 } 250 case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: 251 case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE: 252 case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: { 253 check(expectingStep); 254 Step step = new Step( 255 new Axis(Axis.CHILD), 256 parseNodeTest(token,xtokens,context)); 257 stepsVector.addElement(step); 258 expectingStep=false; 259 break; 260 } 261 262 case XPath.Tokens.EXPRTOKEN_PERIOD: { 263 check(expectingStep); 264 expectingStep=false; 265 266 if (stepsVector.size()==0) { 272 Axis axis = new Axis(Axis.SELF); 274 NodeTest nodeTest = new NodeTest(NodeTest.NODE); 275 Step step = new Step(axis, nodeTest); 276 stepsVector.addElement(step); 277 278 if( xtokens.hasMore() 279 && xtokens.peekToken() == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH){ 280 xtokens.nextToken(); 282 283 axis = new Axis(Axis.DESCENDANT); 285 nodeTest = new NodeTest(NodeTest.NODE); 286 step = new Step(axis, nodeTest); 287 stepsVector.addElement(step); 288 expectingStep=true; 289 } 290 } 291 break; 292 } 293 294 case XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH:{ 295 throw new XPathException("c-general-xpath"); 299 } 300 case XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH: { 301 check(!expectingStep); 302 expectingStep=true; 303 break; 304 } 305 default: 306 throw new InternalError (); 308 } 309 } 310 311 check(!expectingStep); 312 313 locationPathsVector.addElement(buildLocationPath(stepsVector)); 314 315 fLocationPaths=new LocationPath[locationPathsVector.size()]; 317 locationPathsVector.copyInto(fLocationPaths); 318 319 320 if (DEBUG_XPATH_PARSE) { 321 System.out.println(">>> "+fLocationPaths); 322 } 323 324 } 326 330 private NodeTest parseNodeTest( int typeToken, Tokens xtokens, NamespaceContext context ) 331 throws XPathException { 332 switch(typeToken) { 333 case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY: 334 return new NodeTest(NodeTest.WILDCARD); 335 336 case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE: 337 case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: 338 String prefix = xtokens.nextTokenAsString(); 340 String uri = null; 341 if (context != null && prefix != XMLSymbols.EMPTY_STRING) { 342 uri = context.getURI(prefix); 343 } 344 if (prefix != XMLSymbols.EMPTY_STRING && context != null && uri == null) { 345 throw new XPathException("c-general-xpath-ns"); 346 } 347 348 if (typeToken==XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE) 349 return new NodeTest(prefix,uri); 350 351 String localpart = xtokens.nextTokenAsString(); 352 String rawname = prefix != XMLSymbols.EMPTY_STRING 353 ? fSymbolTable.addSymbol(prefix+':'+localpart) 354 : localpart; 355 356 return new NodeTest(new QName(prefix, localpart, rawname, uri)); 357 358 default: 359 throw new InternalError (); 361 } 362 } 363 364 365 369 371 376 public static class LocationPath 377 implements Cloneable { 378 379 383 384 public Step[] steps; 385 386 390 391 public LocationPath(Step[] steps) { 392 this.steps = steps; 393 } 395 396 protected LocationPath(LocationPath path) { 397 steps = new Step[path.steps.length]; 398 for (int i = 0; i < steps.length; i++) { 399 steps[i] = (Step)path.steps[i].clone(); 400 } 401 } 403 407 408 public String toString() { 409 StringBuffer str = new StringBuffer (); 410 for (int i = 0; i < steps.length; i++) { 411 if (i > 0 && (steps[i-1].axis.type!=Axis.DESCENDANT 412 && steps[i].axis.type!=Axis.DESCENDANT) ){ 413 str.append('/'); 414 } 415 str.append(steps[i].toString()); 416 } 417 if (false) { 421 str.append('['); 422 String s = super.toString(); 423 str.append(s.substring(s.indexOf('@'))); 424 str.append(']'); 425 } 426 return str.toString(); 427 } 429 430 public Object clone() { 431 return new LocationPath(this); 432 } 434 } 436 441 public static class Step 442 implements Cloneable { 443 444 448 449 public Axis axis; 450 451 452 public NodeTest nodeTest; 453 454 458 459 public Step(Axis axis, NodeTest nodeTest) { 460 this.axis = axis; 461 this.nodeTest = nodeTest; 462 } 464 465 protected Step(Step step) { 466 axis = (Axis)step.axis.clone(); 467 nodeTest = (NodeTest)step.nodeTest.clone(); 468 } 470 474 475 public String toString() { 476 if (axis.type == Axis.SELF) { 477 return "."; 478 } 479 if (axis.type == Axis.ATTRIBUTE) { 480 return "@" + nodeTest.toString(); 481 } 482 if (axis.type == Axis.CHILD) { 483 return nodeTest.toString(); 484 } 485 if (axis.type == Axis.DESCENDANT) { 486 return "//"; 487 } 488 return "??? ("+axis.type+')'; 489 } 491 492 public Object clone() { 493 return new Step(this); 494 } 496 } 498 503 public static class Axis 504 implements Cloneable { 505 506 510 511 public static final short CHILD = 1; 512 513 514 public static final short ATTRIBUTE = 2; 515 516 517 public static final short SELF = 3; 518 519 520 521 public static final short DESCENDANT = 4; 522 526 527 public short type; 528 529 533 534 public Axis(short type) { 535 this.type = type; 536 } 538 539 protected Axis(Axis axis) { 540 type = axis.type; 541 } 543 547 548 public String toString() { 549 switch (type) { 550 case CHILD: return "child"; 551 case ATTRIBUTE: return "attribute"; 552 case SELF: return "self"; 553 case DESCENDANT: return "descendant"; 554 } 555 return "???"; 556 } 558 559 public Object clone() { 560 return new Axis(this); 561 } 563 } 565 570 public static class NodeTest 571 implements Cloneable { 572 573 577 578 public static final short QNAME = 1; 579 580 581 public static final short WILDCARD = 2; 582 583 584 public static final short NODE = 3; 585 586 587 public static final short NAMESPACE= 4; 588 589 593 594 public short type; 595 596 597 public final QName name = new QName(); 598 599 603 604 public NodeTest(short type) { 605 this.type = type; 606 } 608 609 public NodeTest(QName name) { 610 this.type = QNAME; 611 this.name.setValues(name); 612 } 614 public NodeTest(String prefix, String uri) { 615 this.type = NAMESPACE; 616 this.name.setValues(prefix, null, null, uri); 617 } 619 620 public NodeTest(NodeTest nodeTest) { 621 type = nodeTest.type; 622 name.setValues(nodeTest.name); 623 } 625 629 630 public String toString() { 631 632 switch (type) { 633 case QNAME: { 634 if (name.prefix.length() !=0) { 635 if (name.uri != null) { 636 return name.prefix+':'+name.localpart; 637 } 638 return "{"+name.uri+'}'+name.prefix+':'+name.localpart; 639 } 640 return name.localpart; 641 } 642 case NAMESPACE: { 643 if (name.prefix.length() !=0) { 644 if (name.uri != null) { 645 return name.prefix+":*"; 646 } 647 return "{"+name.uri+'}'+name.prefix+":*"; 648 } 649 return "???:*"; 650 } 651 case WILDCARD: { 652 return "*"; 653 } 654 case NODE: { 655 return "node()"; 656 } 657 } 658 return "???"; 659 660 } 662 663 public Object clone() { 664 return new NodeTest(this); 665 } 667 } 669 671 677 685 private static final class Tokens { 686 687 static final boolean DUMP_TOKENS = false; 688 689 694 public static final int 695 EXPRTOKEN_OPEN_PAREN = 0, 696 EXPRTOKEN_CLOSE_PAREN = 1, 697 EXPRTOKEN_OPEN_BRACKET = 2, 698 EXPRTOKEN_CLOSE_BRACKET = 3, 699 EXPRTOKEN_PERIOD = 4, 700 EXPRTOKEN_DOUBLE_PERIOD = 5, 701 EXPRTOKEN_ATSIGN = 6, 702 EXPRTOKEN_COMMA = 7, 703 EXPRTOKEN_DOUBLE_COLON = 8, 704 EXPRTOKEN_NAMETEST_ANY = 9, 710 EXPRTOKEN_NAMETEST_NAMESPACE = 10, 711 EXPRTOKEN_NAMETEST_QNAME = 11, 712 EXPRTOKEN_NODETYPE_COMMENT = 12, 716 EXPRTOKEN_NODETYPE_TEXT = 13, 717 EXPRTOKEN_NODETYPE_PI = 14, 718 EXPRTOKEN_NODETYPE_NODE = 15, 719 EXPRTOKEN_OPERATOR_AND = 16, 727 EXPRTOKEN_OPERATOR_OR = 17, 728 EXPRTOKEN_OPERATOR_MOD = 18, 729 EXPRTOKEN_OPERATOR_DIV = 19, 730 EXPRTOKEN_OPERATOR_MULT = 20, 731 EXPRTOKEN_OPERATOR_SLASH = 21, 732 EXPRTOKEN_OPERATOR_DOUBLE_SLASH = 22, 733 EXPRTOKEN_OPERATOR_UNION = 23, 734 EXPRTOKEN_OPERATOR_PLUS = 24, 735 EXPRTOKEN_OPERATOR_MINUS = 25, 736 EXPRTOKEN_OPERATOR_EQUAL = 26, 737 EXPRTOKEN_OPERATOR_NOT_EQUAL = 27, 738 EXPRTOKEN_OPERATOR_LESS = 28, 739 EXPRTOKEN_OPERATOR_LESS_EQUAL = 29, 740 EXPRTOKEN_OPERATOR_GREATER = 30, 741 EXPRTOKEN_OPERATOR_GREATER_EQUAL = 31, 742 743 746 EXPRTOKEN_FUNCTION_NAME = 32, 752 EXPRTOKEN_AXISNAME_ANCESTOR = 33, 764 EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF = 34, 765 EXPRTOKEN_AXISNAME_ATTRIBUTE = 35, 766 EXPRTOKEN_AXISNAME_CHILD = 36, 767 EXPRTOKEN_AXISNAME_DESCENDANT = 37, 768 EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF = 38, 769 EXPRTOKEN_AXISNAME_FOLLOWING = 39, 770 EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING = 40, 771 EXPRTOKEN_AXISNAME_NAMESPACE = 41, 772 EXPRTOKEN_AXISNAME_PARENT = 42, 773 EXPRTOKEN_AXISNAME_PRECEDING = 43, 774 EXPRTOKEN_AXISNAME_PRECEDING_SIBLING = 44, 775 EXPRTOKEN_AXISNAME_SELF = 45, 776 EXPRTOKEN_LITERAL = 46, 782 EXPRTOKEN_NUMBER = 47, 789 EXPRTOKEN_VARIABLE_REFERENCE = 48; 795 796 private static final String [] fgTokenNames = { 797 "EXPRTOKEN_OPEN_PAREN", 798 "EXPRTOKEN_CLOSE_PAREN", 799 "EXPRTOKEN_OPEN_BRACKET", 800 "EXPRTOKEN_CLOSE_BRACKET", 801 "EXPRTOKEN_PERIOD", 802 "EXPRTOKEN_DOUBLE_PERIOD", 803 "EXPRTOKEN_ATSIGN", 804 "EXPRTOKEN_COMMA", 805 "EXPRTOKEN_DOUBLE_COLON", 806 "EXPRTOKEN_NAMETEST_ANY", 807 "EXPRTOKEN_NAMETEST_NAMESPACE", 808 "EXPRTOKEN_NAMETEST_QNAME", 809 "EXPRTOKEN_NODETYPE_COMMENT", 810 "EXPRTOKEN_NODETYPE_TEXT", 811 "EXPRTOKEN_NODETYPE_PI", 812 "EXPRTOKEN_NODETYPE_NODE", 813 "EXPRTOKEN_OPERATOR_AND", 814 "EXPRTOKEN_OPERATOR_OR", 815 "EXPRTOKEN_OPERATOR_MOD", 816 "EXPRTOKEN_OPERATOR_DIV", 817 "EXPRTOKEN_OPERATOR_MULT", 818 "EXPRTOKEN_OPERATOR_SLASH", 819 "EXPRTOKEN_OPERATOR_DOUBLE_SLASH", 820 "EXPRTOKEN_OPERATOR_UNION", 821 "EXPRTOKEN_OPERATOR_PLUS", 822 "EXPRTOKEN_OPERATOR_MINUS", 823 "EXPRTOKEN_OPERATOR_EQUAL", 824 "EXPRTOKEN_OPERATOR_NOT_EQUAL", 825 "EXPRTOKEN_OPERATOR_LESS", 826 "EXPRTOKEN_OPERATOR_LESS_EQUAL", 827 "EXPRTOKEN_OPERATOR_GREATER", 828 "EXPRTOKEN_OPERATOR_GREATER_EQUAL", 829 "EXPRTOKEN_FUNCTION_NAME", 830 "EXPRTOKEN_AXISNAME_ANCESTOR", 831 |