1 package net.sf.saxon.expr; 2 3 import net.sf.saxon.om.Axis; 4 import net.sf.saxon.om.Item; 5 import net.sf.saxon.om.NamePool; 6 import net.sf.saxon.om.SequenceIterator; 7 import net.sf.saxon.pattern.AnyNodeTest; 8 import net.sf.saxon.pattern.NodeKindTest; 9 import net.sf.saxon.pattern.NodeTest; 10 import net.sf.saxon.sort.DocumentSorter; 11 import net.sf.saxon.sort.Reverser; 12 import net.sf.saxon.trace.Location; 13 import net.sf.saxon.trans.XPathException; 14 import net.sf.saxon.type.ItemType; 15 import net.sf.saxon.type.Type; 16 import net.sf.saxon.value.Cardinality; 17 import net.sf.saxon.value.EmptySequence; 18 import net.sf.saxon.value.SequenceType; 19 20 import java.io.PrintStream ; 21 import java.util.Iterator ; 22 23 29 30 public final class PathExpression extends ComputedExpression implements MappingFunction { 31 32 private Expression start; 33 private Expression step; 34 private transient int state = 0; 36 43 44 public PathExpression(Expression start, Expression step) { 45 this.start = start; 46 this.step = step; 47 adoptChildExpression(start); 48 adoptChildExpression(step); 49 50 54 59 if (step instanceof PathExpression) { 60 PathExpression stepPath = (PathExpression) step; 61 if (isFilteredAxisPath(stepPath.start) && isFilteredAxisPath(stepPath.step)) { 62 this.start = new PathExpression(start, stepPath.start); 63 ExpressionTool.copyLocationInfo(start, this.start); 64 this.step = stepPath.step; 65 resetStaticProperties(); 66 } 67 } 68 } 69 70 73 74 public Expression getStartExpression() { 75 return start; 76 } 77 78 81 82 public Expression getStepExpression() { 83 return step; 84 } 85 86 90 91 private static boolean isFilteredAxisPath(Expression exp) { 92 if (exp instanceof AxisExpression) { 93 return true; 94 } else { 95 while (exp instanceof FilterExpression) { 96 exp = ((FilterExpression) exp).getBaseExpression(); 97 } 98 return exp instanceof AxisExpression; 99 } 100 } 101 102 106 107 public final ItemType getItemType() { 108 return step.getItemType(); 109 } 110 111 115 116 public Expression simplify(StaticContext env) throws XPathException { 117 if (state > 0) return this; 118 state = 1; 119 start = start.simplify(env); 120 step = step.simplify(env); 121 resetStaticProperties(); 122 123 if (start instanceof EmptySequence) { 125 return start; 126 } 127 128 if (step instanceof EmptySequence) { 130 return step; 131 } 132 133 137 if (start instanceof ContextItemExpression) { 138 if (step instanceof PathExpression || (step.getSpecialProperties() & StaticProperty.ORDERED_NODESET) != 0) { 139 return step; 140 } 141 } 142 143 if (step instanceof ContextItemExpression && 144 (start instanceof PathExpression || (start.getSpecialProperties() & StaticProperty.ORDERED_NODESET) != 0)) { 145 return start; 146 } 147 148 150 if (step instanceof PathExpression && ((PathExpression)step).getFirstStep() instanceof ContextItemExpression) { 151 return new PathExpression(start, ((PathExpression)step).getRemainingSteps()); 152 } 153 154 if (start instanceof PathExpression && ((PathExpression)start).getLastStep() instanceof ContextItemExpression) { 155 return new PathExpression(((PathExpression)start).getLeadingSteps(), step); 156 } 157 158 160 if (start instanceof RootExpression && step instanceof ParentNodeExpression) { 161 return EmptySequence.getInstance(); 162 } 163 164 return this; 165 } 166 167 173 private PathExpression simplifyDescendantPath(StaticContext env) throws XPathException { 174 175 Expression st = start; 176 177 179 if (start instanceof AxisExpression) { 180 AxisExpression stax = (AxisExpression) start; 181 if (stax.getAxis() != Axis.DESCENDANT_OR_SELF) { 182 return null; 183 } 184 ContextItemExpression cie = new ContextItemExpression(); 185 ExpressionTool.copyLocationInfo(this, cie); 186 st = new PathExpression(cie, stax); 187 ExpressionTool.copyLocationInfo(this, st); 188 } 189 190 if (!(st instanceof PathExpression)) { 191 return null; 192 } 193 194 PathExpression startPath = (PathExpression) st; 195 if (!(startPath.step instanceof AxisExpression)) { 196 return null; 197 } 198 199 AxisExpression mid = (AxisExpression) startPath.step; 200 if (mid.getAxis() != Axis.DESCENDANT_OR_SELF) { 201 return null; 202 } 203 204 205 NodeTest test = mid.getNodeTest(); 206 if (!(test == null || test instanceof AnyNodeTest)) { 207 return null; 208 } 209 210 Expression underlyingStep = step; 211 while (underlyingStep instanceof FilterExpression) { 212 if (((FilterExpression) underlyingStep).isPositional()) { 213 return null; 214 } 215 underlyingStep = ((FilterExpression) underlyingStep).getBaseExpression(); 216 } 217 218 if (!(underlyingStep instanceof AxisExpression)) { 219 return null; 220 } 221 222 AxisExpression underlyingAxis = (AxisExpression) underlyingStep; 223 if (underlyingAxis.getAxis() == Axis.CHILD) { 224 225 ComputedExpression newStep = 226 new AxisExpression(Axis.DESCENDANT, 227 ((AxisExpression) underlyingStep).getNodeTest()); 228 ExpressionTool.copyLocationInfo(this, newStep); 229 230 underlyingStep = step; 231 while (underlyingStep instanceof FilterExpression) { 232 newStep = new FilterExpression(newStep, 235 ((FilterExpression) underlyingStep).getFilter(), env); 236 ExpressionTool.copyLocationInfo(underlyingStep, newStep); 237 underlyingStep = ((FilterExpression) underlyingStep).getBaseExpression(); 238 } 239 240 245 PathExpression newPath = new PathExpression(startPath.start, newStep); 246 ExpressionTool.copyLocationInfo(this, newPath); 247 return newPath; 248 } 249 250 if (underlyingAxis.getAxis() == Axis.ATTRIBUTE) { 251 252 254 ComputedExpression newStep = 255 new AxisExpression(Axis.DESCENDANT_OR_SELF, NodeKindTest.ELEMENT); 256 ExpressionTool.copyLocationInfo(this, newStep); 257 258 PathExpression newPath = new PathExpression( 259 new PathExpression(startPath.start, newStep), 260 step); 261 ExpressionTool.copyLocationInfo(this, newPath); 262 return newPath; 263 } 264 265 return null; 266 } 267 268 271 272 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 273 274 if (state >= 2) { 275 Expression start2 = start.typeCheck(env, contextItemType); 279 if (start2 != start) { 280 adoptChildExpression(start2); 281 start = start2; 282 } 283 Expression step2 = step.typeCheck(env, start.getItemType()); 284 if (step2 != step) { 285 adoptChildExpression(step2); 286 step = step2; 287 } 288 return this; 289 }; 290 state = 2; 291 292 Expression start2 = start.typeCheck(env, contextItemType); 293 if (start2 != start) { 294 adoptChildExpression(start2); 295 start = start2; 296 } 297 Expression step2 = step.typeCheck(env, start.getItemType()); 298 if (step2 != step) { 299 adoptChildExpression(step2); 300 step = step2; 301 } 302 303 305 RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, "/", 0, null); 306 role0.setSourceLocator(this); 307 role0.setErrorCode("XPTY0019"); 308 start2 = TypeChecker.staticTypeCheck(start, 309 SequenceType.NODE_SEQUENCE, 310 false, role0, env); 311 if (start2 != start) { 312 adoptChildExpression(start2); 313 start = start2; 314 } 315 316 337 341 ItemType stepType = step.getItemType(); 342 if (Type.isSubType(stepType, Type.NODE_TYPE)) { 343 344 if ((step.getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) { 345 346 348 351 Optimizer opt = env.getConfiguration().getOptimizer(); 352 start2 = ExpressionTool.unsorted(opt, start, false); 353 if (start2 != start) { 354 resetStaticProperties(); 355 adoptChildExpression(start2); 356 start = start2; 357 } 358 step2 = ExpressionTool.unsorted(opt, step, false); 359 if (step2 != step) { 360 resetStaticProperties(); 361 adoptChildExpression(step2); 362 step = step2; 363 } 364 365 PathExpression p = simplifyDescendantPath(env); 367 if (p != null) { 368 p.setParentExpression(getParentExpression()); 369 return p.simplify(env).typeCheck(env, contextItemType); 370 } 371 } 372 373 376 int props = getSpecialProperties(); 377 378 if ((props & StaticProperty.ORDERED_NODESET) != 0) { 379 return this; 380 } else if ((props & StaticProperty.REVERSE_DOCUMENT_ORDER) != 0) { 381 return new Reverser(this); 382 } else { 383 return new DocumentSorter(this); 384 } 385 386 } else if (Type.isSubType(stepType, Type.ANY_ATOMIC_TYPE)) { 387 return new SimpleMappingExpression(start, step, false).simplify(env).typeCheck(env, contextItemType); 389 } else { 390 return new SimpleMappingExpression(start, step, true).simplify(env).typeCheck(env, contextItemType); 393 } 394 } 395 396 399 400 public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 401 402 if (state >= 3) { 403 Expression start2 = start.optimize(opt, env, contextItemType); 407 if (start2 != start) { 408 adoptChildExpression(start2); 409 start = start2; 410 } 411 Expression step2 = step.optimize(opt, env, start.getItemType()); 412 if (step2 != step) { 413 adoptChildExpression(step2); 414 step = step2; 415 } 416 return this; 417 }; 418 state = 3; 419 420 Expression k = opt.convertPathExpressionToKey(this, env); 421 if (k != null) { 422 return k; 423 } 424 425 Expression start2 = start.optimize(opt, env, contextItemType); 426 if (start2 != start) { 427 adoptChildExpression(start2); 428 start = start2; 429 } 430 Expression step2 = step.optimize(opt, env, start.getItemType()); 431 if (step2 != step) { 432 adoptChildExpression(step2); 433 step = step2; 434 } 435 436 440 PromotionOffer offer = new PromotionOffer(opt); 441 offer.action = PromotionOffer.FOCUS_INDEPENDENT; 442 offer.promoteDocumentDependent = (start.getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0; 443 offer.containingExpression = this; 444 445 step = doPromotion(step, offer); 446 resetStaticProperties(); 447 if (offer.containingExpression != this) { 448 state = 0; offer.containingExpression = 450 offer.containingExpression.typeCheck(env, contextItemType).optimize(opt, env, contextItemType); 451 return offer.containingExpression; 452 } 453 return this; 454 455 } 456 457 460 461 public Expression promote(PromotionOffer offer) throws XPathException { 462 Expression p = this; 463 if (offer.action == PromotionOffer.RANGE_INDEPENDENT) { 464 FilterExpression p2 = offer.getOptimizer().convertToFilterExpression(this); 466 if (p2 != null) { 467 return p2.promote(offer); 468 } 469 } 470 Expression exp = offer.accept(p); 471 if (exp != null) { 472 return exp; 473 } else { 474 start = doPromotion(start, offer); 475 if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES || 476 offer.action == PromotionOffer.REPLACE_CURRENT) { 477 step = doPromotion(step, offer); 481 } 482 return this; 483 } 484 } 485 486 487 488 491 492 public Iterator iterateSubExpressions() { 493 return new PairIterator(start, step); 494 } 495 500 501 public int computeDependencies() { 502 return start.getDependencies() | 503 (step.getDependencies() & 506 (StaticProperty.DEPENDS_ON_XSLT_CONTEXT | 507 StaticProperty.DEPENDS_ON_LOCAL_VARIABLES | 508 StaticProperty.DEPENDS_ON_USER_FUNCTIONS)); 509 } 510 511 516 517 public int computeSpecialProperties() { 518 int startProperties = start.getSpecialProperties(); 519 int stepProperties = step.getSpecialProperties(); 520 521 int p = 0; 522 if (!Cardinality.allowsMany(start.getCardinality())) { 523 startProperties |= StaticProperty.ORDERED_NODESET | StaticProperty.PEER_NODESET; 524 } 525 if (!Cardinality.allowsMany(step.getCardinality())) { 526 stepProperties |= StaticProperty.ORDERED_NODESET | StaticProperty.PEER_NODESET; 527 } 528 529 530 if ((startProperties & stepProperties & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) { 531 p |= StaticProperty.CONTEXT_DOCUMENT_NODESET; 532 } 533 if (((startProperties & StaticProperty.SINGLE_DOCUMENT_NODESET) != 0) && 534 ((stepProperties & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0)) { 535 p |= StaticProperty.SINGLE_DOCUMENT_NODESET; 536 } 537 if ((startProperties & stepProperties & StaticProperty.PEER_NODESET) != 0) { 538 p |= StaticProperty.PEER_NODESET; 539 } 540 if ((startProperties & stepProperties & StaticProperty.SUBTREE_NODESET) != 0) { 541 p |= StaticProperty.SUBTREE_NODESET; 542 } 543 544 if (testNaturallySorted(startProperties, stepProperties)) { 545 p |= StaticProperty.ORDERED_NODESET; 546 } 547 548 if (testNaturallyReverseSorted()) { 549 p |= StaticProperty.REVERSE_DOCUMENT_ORDER; 550 } 551 552 if ((startProperties & stepProperties & StaticProperty.NON_CREATIVE) != 0) { 553 p |= StaticProperty.NON_CREATIVE; 554 } 555 556 return p; 557 } 558 559 565 566 private boolean testNaturallySorted(int startProperties, int stepProperties) { 567 568 574 if ((stepProperties & StaticProperty.ORDERED_NODESET) == 0) { 575 return false; 576 } 577 if (Cardinality.allowsMany(start.getCardinality())) { 578 if ((startProperties & StaticProperty.ORDERED_NODESET) == 0) { 579 return false; 580 } 581 } else { 582 return true; 584 } 586 587 590 593 if ((stepProperties & StaticProperty.ATTRIBUTE_NS_NODESET) != 0) { 594 return true; 595 } 596 597 601 if (((startProperties & StaticProperty.PEER_NODESET) != 0) && ((stepProperties & StaticProperty.SUBTREE_NODESET) != 0)) { 602 return true; 603 } 604 605 return false; 606 } 607 608 611 612 private boolean testNaturallyReverseSorted() { 613 614 620 625 626 if (!Cardinality.allowsMany(start.getCardinality()) && 627 (step instanceof AxisExpression)) { 628 return !Axis.isForwards[((AxisExpression) step).getAxis()]; 629 } 630 631 if (!(start instanceof AxisExpression)) { 632 return false; 633 } 634 635 if (Axis.isForwards[((AxisExpression) start).getAxis()]) { 636 return false; 637 } 638 639 643 return false; 644 } 645 646 649 650 public int computeCardinality() { 651 int c1 = start.getCardinality(); 652 int c2 = step.getCardinality(); 653 return Cardinality.multiply(c1, c2); 654 } 655 656 659 660 public boolean equals(Object other) { 661 if (!(other instanceof PathExpression)) { 662 return false; 663 } 664 PathExpression p = (PathExpression) other; 665 return (start.equals(p.start) && step.equals(p.step)); 666 } 667 668 671 672 public int hashCode() { 673 return "PathExpression".hashCode() + start.hashCode() + step.hashCode(); 674 } 675 676 680 681 public Expression getFirstStep() { 682 if (start instanceof PathExpression) { 683 return ((PathExpression) start).getFirstStep(); 684 } else { 685 return start; 686 } 687 } 688 689 694 695 public Expression getRemainingSteps() { 696 if (start instanceof PathExpression) { 697 PathExpression rem = 698 new PathExpression(((PathExpression) start).getRemainingSteps(), step); 699 rem.setParentExpression(getParentExpression()); 700 ExpressionTool.copyLocationInfo(start, rem); 701 return rem; 702 } else { 703 return step; 704 } 705 } 706 707 710 711 public Expression getLastStep() { 712 if (step instanceof PathExpression) { 713 return ((PathExpression)step).getLastStep(); 714 } else { 715 return step; 716 } 717 } 718 719 722 723 public Expression getLeadingSteps() { 724 if (step instanceof PathExpression) { 725 PathExpression rem = 726 new PathExpression(start, ((PathExpression) step).getLeadingSteps()); 727 ExpressionTool.copyLocationInfo(start, rem); 728 return rem; 729 } else { 730 return start; 731 } 732 } 733 734 738 739 public boolean isAbsolute() { 740 return getFirstStep().getItemType().getPrimitiveType() == Type.DOCUMENT; 741 } 742 743 747 748 public SequenceIterator iterate(XPathContext context) throws XPathException { 749 750 754 SequenceIterator master = start.iterate(context); 755 XPathContext context2 = context.newMinorContext(); 756 context2.setCurrentIterator(master); 757 context2.setOriginatingConstructType(Location.PATH_EXPRESSION); 758 759 master = new MappingIterator(master, this, context2); 760 return master; 761 762 } 763 764 768 769 public Object map(Item item, XPathContext context) throws XPathException { 770 return step.iterate(context); 771 } 772 773 776 777 public void display(int level, NamePool pool, PrintStream out) { 778 out.println(ExpressionTool.indent(level) + "path /"); 779 start.display(level + 1, pool, out); 780 step.display(level + 1, pool, out); 781 } 782 783 784 } 785 786 787 | Popular Tags |