1 %{ 2 /* XPathParser.y - An XPath 1.0 parser. 3 Copyright (C) 2004 The Free Software Foundation 4 5 This file is part of GNU Classpath. 6 7 GNU Classpath is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2, or (at your option) 10 any later version. 11 12 GNU Classpath is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GNU Classpath; see the file COPYING. If not, write to the 19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 02110-1301 USA. 21 22 Linking this library statically or dynamically with other modules is 23 making a combined work based on this library. Thus, the terms and 24 conditions of the GNU General Public License cover the whole 25 combination. 26 27 As a special exception, the copyright holders of this library give you 28 permission to link this library with independent modules to produce an 29 executable, regardless of the license terms of these independent 30 modules, and to copy and distribute the resulting executable under 31 terms of your choice, provided that you also meet, for each linked 32 independent module, the terms and conditions of the license of that 33 module. An independent module is a module which is not derived from 34 or based on this library. If you modify this library, you may extend 35 this exception to your version of the library, but you are not 36 obligated to do so. If you do not wish to do so, delete this 37 exception statement from your version. */ 38 39 40 package gnu.xml.xpath; 41 42 import java.util.ArrayList; 43 import java.util.Collections; 44 import java.util.List; 45 import java.util.Map; 46 import javax.xml.namespace.NamespaceContext; 47 import javax.xml.namespace.QName; 48 import javax.xml.xpath.XPathFunctionResolver; 49 import javax.xml.xpath.XPathVariableResolver; 50 import org.w3c.dom.Node; 51 52 /** 53 * An XPath 1.0 parser. 54 * 55 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> 56 */ 57 public class XPathParser 58 { 59 60 NamespaceContext namespaceContext; 61 XPathVariableResolver variableResolver; 62 XPathFunctionResolver functionResolver; 63 getQName(String name)64 QName getQName(String name) 65 { 66 QName qName = QName.valueOf(name); 67 if (namespaceContext != null) 68 { 69 String prefix = qName.getPrefix(); 70 String uri = qName.getNamespaceURI(); 71 if (prefix != null && (uri == null || uri.length() == 0)) 72 { 73 uri = namespaceContext.getNamespaceURI(prefix); 74 String localName = qName.getLocalPart(); 75 qName = new QName(uri, localName, prefix); 76 } 77 } 78 return qName; 79 } 80 lookupFunction(String name,List<Expr> args)81 Expr lookupFunction(String name, List<Expr> args) 82 { 83 int arity = args.size(); 84 if ("position".equals(name) && arity == 0) 85 { 86 return new PositionFunction(); 87 } 88 else if ("last".equals(name) && arity == 0) 89 { 90 return new LastFunction(); 91 } 92 else if ("string".equals(name) && (arity == 1 || arity == 0)) 93 { 94 return new StringFunction(args); 95 } 96 else if ("number".equals(name) && (arity == 1 || arity == 0)) 97 { 98 return new NumberFunction(args); 99 } 100 else if ("boolean".equals(name) && arity == 1) 101 { 102 return new BooleanFunction(args); 103 } 104 else if ("count".equals(name) && arity == 1) 105 { 106 return new CountFunction(args); 107 } 108 else if ("not".equals(name) && arity == 1) 109 { 110 return new NotFunction(args); 111 } 112 else if ("id".equals(name) && arity == 1) 113 { 114 return new IdFunction(args); 115 } 116 else if ("concat".equals(name) && arity > 1) 117 { 118 return new ConcatFunction(args); 119 } 120 else if ("true".equals(name) && arity == 0) 121 { 122 return new TrueFunction(); 123 } 124 else if ("false".equals(name) && arity == 0) 125 { 126 return new FalseFunction(); 127 } 128 else if ("name".equals(name) && (arity == 1 || arity == 0)) 129 { 130 return new NameFunction(args); 131 } 132 else if ("local-name".equals(name) && (arity == 1 || arity == 0)) 133 { 134 return new LocalNameFunction(args); 135 } 136 else if ("namespace-uri".equals(name) && (arity == 1 || arity == 0)) 137 { 138 return new NamespaceUriFunction(args); 139 } 140 else if ("starts-with".equals(name) && arity == 2) 141 { 142 return new StartsWithFunction(args); 143 } 144 else if ("contains".equals(name) && arity == 2) 145 { 146 return new ContainsFunction(args); 147 } 148 else if ("string-length".equals(name) && (arity == 1 || arity == 0)) 149 { 150 return new StringLengthFunction(args); 151 } 152 else if ("translate".equals(name) && arity == 3) 153 { 154 return new TranslateFunction(args); 155 } 156 else if ("normalize-space".equals(name) && (arity == 1 || arity == 0)) 157 { 158 return new NormalizeSpaceFunction(args); 159 } 160 else if ("substring".equals(name) && (arity == 2 || arity == 3)) 161 { 162 return new SubstringFunction(args); 163 } 164 else if ("substring-before".equals(name) && arity == 2) 165 { 166 return new SubstringBeforeFunction(args); 167 } 168 else if ("substring-after".equals(name) && arity == 2) 169 { 170 return new SubstringAfterFunction(args); 171 } 172 else if ("lang".equals(name) && arity == 1) 173 { 174 return new LangFunction(args); 175 } 176 else if ("sum".equals(name) && arity == 1) 177 { 178 return new SumFunction(args); 179 } 180 else if ("floor".equals(name) && arity == 1) 181 { 182 return new FloorFunction(args); 183 } 184 else if ("ceiling".equals(name) && arity == 1) 185 { 186 return new CeilingFunction(args); 187 } 188 else if ("round".equals(name) && arity == 1) 189 { 190 return new RoundFunction(args); 191 } 192 else if (functionResolver != null) 193 { 194 QName qName = QName.valueOf(name); 195 Object function = functionResolver.resolveFunction(qName, arity); 196 if (function != null && 197 function instanceof Function && 198 function instanceof Expr) 199 { 200 Function f = (Function) function; 201 f.setArguments(args); 202 return (Expr) function; 203 } 204 } 205 return new FunctionCall(functionResolver, name, args); 206 } 207 208 %} 209 210 %token LITERAL 211 %token DIGITS 212 %token NAME 213 214 %token LP // '(' 215 %token RP // ')' 216 %token LB // '[' 217 %token RB // ']' 218 %token COMMA // ',' 219 %token PIPE // '|' 220 %token SLASH // '/' 221 %token DOUBLE_SLASH // '//' 222 %token EQ // '=' 223 %token NE // '!=' 224 %token GT // '>' 225 %token LT // '<' 226 %token GTE // '>=' 227 %token LTE // '<=' 228 %token PLUS // '+' 229 %token MINUS // '-' 230 %token AT // '@' 231 %token STAR // '*' 232 %token DOLLAR // '$' 233 %token COLON // ':' 234 %token DOUBLE_COLON // '::' 235 %token DOT // '.' 236 %token DOUBLE_DOT // '..' 237 238 %token ANCESTOR 239 %token ANCESTOR_OR_SELF 240 %token ATTRIBUTE 241 %token CHILD 242 %token DESCENDANT 243 %token DESCENDANT_OR_SELF 244 %token FOLLOWING 245 %token FOLLOWING_SIBLING 246 %token NAMESPACE 247 %token PARENT 248 %token PRECEDING 249 %token PRECEDING_SIBLING 250 %token SELF 251 %token DIV 252 %token MOD 253 %token OR 254 %token AND 255 %token COMMENT 256 %token PROCESSING_INSTRUCTION 257 %token TEXT 258 %token NODE 259 260 %right UNARY 261 262 %start expr 263 264 %% 265 266 expr: 267 or_expr 268 ; 269 270 location_path: 271 relative_location_path 272 | absolute_location_path 273 ; 274 275 absolute_location_path: 276 SLASH 277 { 278 $$ = new Root(); 279 } 280 | SLASH relative_location_path 281 { 282 Steps steps; 283 if ($2 instanceof Steps) 284 { 285 steps = (Steps) $2; 286 } 287 else 288 { 289 steps = new Steps(); 290 steps.path.addFirst((Expr) $2); 291 } 292 steps.path.addFirst(new Root()); 293 $$ = steps; 294 //$$ = new Step(new Root(), (Path) $2); 295 } 296 | DOUBLE_SLASH relative_location_path 297 { 298 Test nt = new NodeTypeTest((short) 0); 299 Selector s = new Selector(Selector.DESCENDANT_OR_SELF, 300 Collections.singletonList (nt)); 301 Steps steps; 302 if ($2 instanceof Steps) 303 { 304 steps = (Steps) $2; 305 } 306 else 307 { 308 steps = new Steps(); 309 steps.path.addFirst((Expr) $2); 310 } 311 steps.path.addFirst(s); 312 steps.path.addFirst(new Root()); 313 $$ = steps; 314 //Step step = new Step(s, (Path) $2); 315 //$$ = new Step(new Root(), step); 316 } 317 ; 318 319 relative_location_path: 320 step 321 | relative_location_path SLASH step 322 { 323 Steps steps; 324 if ($1 instanceof Steps) 325 { 326 steps = (Steps) $1; 327 } 328 else 329 { 330 steps = new Steps(); 331 steps.path.addFirst((Expr) $1); 332 } 333 steps.path.addLast((Expr) $3); 334 $$ = steps; 335 //$$ = new Step((Expr) $1, (Path) $3); 336 } 337 | relative_location_path DOUBLE_SLASH step 338 { 339 Test nt = new NodeTypeTest((short) 0); 340 Selector s = new Selector(Selector.DESCENDANT_OR_SELF, 341 Collections.singletonList (nt)); 342 Steps steps; 343 if ($1 instanceof Steps) 344 { 345 steps = (Steps) $1; 346 } 347 else 348 { 349 steps = new Steps(); 350 steps.path.addFirst((Expr) $1); 351 } 352 steps.path.addLast(s); 353 steps.path.addLast((Expr) $3); 354 $$ = steps; 355 //Step step = new Step(s, (Path) $3); 356 //$$ = new Step((Expr) $1, step); 357 } 358 ; 359 360 step: 361 step_node_test 362 { 363 @SuppressWarnings("unchecked") List<Test> tests = (List<Test>) $1; 364 $$ = new Selector (Selector.CHILD, tests); 365 } 366 | AT step_node_test 367 { 368 @SuppressWarnings("unchecked") List<Test> tests = (List<Test>) $2; 369 $$ = new Selector (Selector.ATTRIBUTE, tests); 370 } 371 | axis_name DOUBLE_COLON step_node_test 372 { 373 @SuppressWarnings("unchecked") List<Test> tests = (List<Test>) $3; 374 $$ = new Selector (((Integer) $1).intValue (), tests); 375 } 376 | DOT 377 { 378 List<Test> emptyList = Collections.emptyList(); 379 $$ = new Selector (Selector.SELF, emptyList); 380 } 381 | DOUBLE_DOT 382 { 383 List<Test> emptyList = Collections.emptyList(); 384 $$ = new Selector (Selector.PARENT, emptyList); 385 } 386 ; 387 388 step_node_test: 389 node_test 390 { 391 List<Test> list = new ArrayList<Test>(); 392 list.add((Test) $1); 393 $$ = list; 394 } 395 | step_node_test predicate 396 { 397 /* This is safe as we create this in one of the other cases */ 398 @SuppressWarnings("unchecked") List<Test> tests = (List<Test>)$1; 399 tests.add((Test) $2); 400 $$ = list; 401 } 402 ; 403 404 /*predicate_list: 405 predicate 406 { 407 List list = new ArrayList (); 408 list.add ($1); 409 $$ = list; 410 } 411 | predicate predicate_list 412 { 413 List list = (List) $3; 414 list.add (0, $1); 415 $$ = list; 416 } 417 ;*/ 418 419 axis_name: 420 ANCESTOR 421 { 422 $$ = new Integer(Selector.ANCESTOR); 423 } 424 | ANCESTOR_OR_SELF 425 { 426 $$ = new Integer(Selector.ANCESTOR_OR_SELF); 427 } 428 | ATTRIBUTE 429 { 430 $$ = new Integer(Selector.ATTRIBUTE); 431 } 432 | CHILD 433 { 434 $$ = new Integer(Selector.CHILD); 435 } 436 | DESCENDANT 437 { 438 $$ = new Integer(Selector.DESCENDANT); 439 } 440 | DESCENDANT_OR_SELF 441 { 442 $$ = new Integer(Selector.DESCENDANT_OR_SELF); 443 } 444 | FOLLOWING 445 { 446 $$ = new Integer(Selector.FOLLOWING); 447 } 448 | FOLLOWING_SIBLING 449 { 450 $$ = new Integer(Selector.FOLLOWING_SIBLING); 451 } 452 | NAMESPACE 453 { 454 $$ = new Integer(Selector.NAMESPACE); 455 } 456 | PARENT 457 { 458 $$ = new Integer(Selector.PARENT); 459 } 460 | PRECEDING 461 { 462 $$ = new Integer(Selector.PRECEDING); 463 } 464 | PRECEDING_SIBLING 465 { 466 $$ = new Integer(Selector.PRECEDING_SIBLING); 467 } 468 | SELF 469 { 470 $$ = new Integer(Selector.SELF); 471 } 472 ; 473 474 node_test: 475 name_test 476 /*| PROCESSING_INSTRUCTION LP LITERAL RP*/ 477 | PROCESSING_INSTRUCTION LITERAL RP 478 { 479 $$ = new NodeTypeTest(Node.PROCESSING_INSTRUCTION_NODE, (String) $2); 480 } 481 /*| node_type LP RP*/ 482 | node_type RP 483 { 484 $$ = new NodeTypeTest(((Short) $1).shortValue()); 485 } 486 ; 487 488 predicate: 489 LB expr RB 490 { 491 $$ = new Predicate((Expr) $2); 492 } 493 ; 494 495 primary_expr: 496 variable_reference 497 | LP expr RP 498 { 499 $$ = new ParenthesizedExpr((Expr) $2); 500 } 501 | LITERAL 502 { 503 $$ = new Constant($1); 504 } 505 | number 506 { 507 $$ = new Constant($1); 508 } 509 | function_call 510 ; 511 512 function_call: 513 function_name LP RP 514 { 515 List<Expr> emptyList = Collections.emptyList(); 516 $$ = lookupFunction((String) $1, emptyList); 517 } 518 | function_name LP argument_list RP 519 { 520 /* This is safe as we create this below */ 521 @SuppressWarnings("unchecked") List<Expr> exprs = (List<Expr>) $3; 522 $$ = lookupFunction((String) $1, (List) exprs); 523 } 524 ; 525 526 argument_list: 527 expr 528 { 529 List<Expr> list = new ArrayList<Expr>(); 530 list.add((Expr) $1); 531 $$ = list; 532 } 533 | expr COMMA argument_list 534 { 535 /* This is safe as we create this above */ 536 @SuppressWarnings("unchecked") List<Expr> list = (List<Expr>) $3; 537 list.add(0, (Expr) $1); 538 $$ = list; 539 } 540 ; 541 542 union_expr: 543 path_expr 544 | union_expr PIPE path_expr 545 { 546 $$ = new UnionExpr((Expr) $1, (Expr) $3); 547 } 548 ; 549 550 path_expr: 551 location_path 552 | filter_expr 553 | filter_expr SLASH relative_location_path 554 { 555 Steps steps; 556 if ($3 instanceof Steps) 557 { 558 steps = (Steps) $3; 559 } 560 else 561 { 562 steps = new Steps(); 563 steps.path.addFirst((Expr) $3); 564 } 565 steps.path.addFirst((Expr) $1); 566 $$ = steps; 567 //$$ = new Step ((Expr) $1, (Path) $3); 568 } 569 | filter_expr DOUBLE_SLASH relative_location_path 570 { 571 Test nt = new NodeTypeTest((short) 0); 572 Selector s = new Selector(Selector.DESCENDANT_OR_SELF, 573 Collections.singletonList(nt)); 574 Steps steps; 575 if ($3 instanceof Steps) 576 { 577 steps = (Steps) $3; 578 } 579 else 580 { 581 steps = new Steps(); 582 steps.path.addFirst($3); 583 } 584 steps.path.addFirst(s); 585 steps.path.addFirst((Expr) $1); 586 $$ = steps; 587 //Step step = new Step (s, (Path) $3); 588 //$$ = new Step ((Expr) $1, step); 589 } 590 ; 591 592 filter_expr: 593 primary_expr 594 | filter_expr predicate 595 { 596 Predicate filter = (Predicate) $2; 597 Selector s = new Selector(Selector.SELF, 598 Collections.singletonList(filter)); 599 Steps steps; 600 if ($1 instanceof Steps) 601 { 602 steps = (Steps) $1; 603 } 604 else 605 { 606 steps = new Steps(); 607 steps.path.addFirst((Expr) $1); 608 } 609 steps.path.addLast(s); 610 $$ = steps; 611 //$$ = new Step ((Expr) $1, s); 612 } 613 ; 614 615 or_expr: 616 and_expr 617 | or_expr OR and_expr 618 { 619 $$ = new OrExpr((Expr) $1, (Expr) $3); 620 } 621 ; 622 623 and_expr: 624 equality_expr 625 | and_expr AND equality_expr 626 { 627 $$ = new AndExpr((Expr) $1, (Expr) $3); 628 } 629 ; 630 631 equality_expr: 632 relational_expr 633 | equality_expr EQ relational_expr 634 { 635 $$ = new EqualityExpr((Expr) $1, (Expr) $3, false); 636 } 637 | equality_expr NE relational_expr 638 { 639 $$ = new EqualityExpr((Expr) $1, (Expr) $3, true); 640 } 641 ; 642 643 relational_expr: 644 additive_expr 645 | relational_expr LT additive_expr 646 { 647 $$ = new RelationalExpr((Expr) $1, (Expr) $3, true, false); 648 } 649 | relational_expr GT additive_expr 650 { 651 $$ = new RelationalExpr((Expr) $1, (Expr) $3, false, false); 652 } 653 | relational_expr LTE additive_expr 654 { 655 $$ = new RelationalExpr((Expr) $1, (Expr) $3, true, true); 656 } 657 | relational_expr GTE additive_expr 658 { 659 $$ = new RelationalExpr((Expr) $1, (Expr) $3, false, true); 660 } 661 ; 662 663 additive_expr: 664 multiplicative_expr 665 | additive_expr PLUS multiplicative_expr 666 { 667 $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.ADD); 668 } 669 | additive_expr MINUS multiplicative_expr 670 { 671 $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.SUBTRACT); 672 } 673 ; 674 675 multiplicative_expr: 676 unary_expr 677 | multiplicative_expr STAR unary_expr 678 { 679 $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.MULTIPLY); 680 } 681 | multiplicative_expr DIV unary_expr 682 { 683 $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.DIVIDE); 684 } 685 | multiplicative_expr MOD unary_expr 686 { 687 $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.MODULO); 688 } 689 ; 690 691 unary_expr: 692 union_expr 693 | MINUS unary_expr %prec UNARY 694 { 695 $$ = new NegativeExpr((Expr) $2); 696 } 697 ; 698 699 number: 700 DIGITS 701 { 702 $$ = new Double((String) $1 + ".0"); 703 } 704 | DIGITS DOT 705 { 706 $$ = new Double((String) $1 + ".0"); 707 } 708 | DIGITS DOT DIGITS 709 { 710 $$ = new Double((String) $1 + "." + (String) $3); 711 } 712 | DOT DIGITS 713 { 714 $$ = new Double("0." + (String) $2); 715 } 716 ; 717 718 function_name: 719 qname 720 /* | node_type 721 { 722 switch (((Short) $1).shortValue ()) 723 { 724 case Node.COMMENT_NODE: 725 $$ = "comment"; 726 break; 727 case Node.TEXT_NODE: 728 $$ = "text"; 729 break; 730 case Node.PROCESSING_INSTRUCTION_NODE: 731 $$ = "processing-instruction"; 732 break; 733 default: 734 $$ = "node"; 735 break; 736 } 737 }*/ 738 ; 739 740 variable_reference: 741 DOLLAR qname 742 { 743 String name = (String) $2; 744 $$ = new VariableReference(variableResolver, getQName(name)); 745 } 746 ; 747 748 name_test: 749 STAR 750 { 751 $$ = new NameTest(null, true, true); 752 } 753 | NAME COLON STAR 754 { 755 QName qName = getQName((String) $1); 756 $$ = new NameTest(qName, true, false); 757 } 758 | qname 759 { 760 QName qName = getQName((String) $1); 761 $$ = new NameTest(qName, false, false); 762 } 763 ; 764 765 qname: 766 NAME 767 | NAME COLON NAME 768 { 769 $$ = (String) $1 + ':' + (String) $3; 770 } 771 ; 772 773 node_type: 774 COMMENT 775 { 776 $$ = new Short(Node.COMMENT_NODE); 777 } 778 | TEXT 779 { 780 $$ = new Short(Node.TEXT_NODE); 781 } 782 | PROCESSING_INSTRUCTION 783 { 784 $$ = new Short(Node.PROCESSING_INSTRUCTION_NODE); 785 } 786 | NODE 787 { 788 $$ = new Short((short) 0); 789 } 790 ; 791 792 %% 793 794 } 795