1 package net.sf.saxon.expr; 2 import net.sf.saxon.functions.Last; 3 import net.sf.saxon.functions.SystemFunction; 4 import net.sf.saxon.om.*; 5 import net.sf.saxon.trans.StaticError; 6 import net.sf.saxon.trans.XPathException; 7 import net.sf.saxon.type.AnyItemType; 8 import net.sf.saxon.type.ItemType; 9 import net.sf.saxon.type.Type; 10 import net.sf.saxon.value.*; 11 12 import java.io.PrintStream ; 13 import java.util.Iterator ; 14 15 19 20 public final class FilterExpression extends ComputedExpression { 21 22 private Expression start; 23 private Expression filter; 24 private int filterDependencies; private boolean filterIsPositional; private boolean filterIsRange; private int isIndexable = 0; 31 32 38 39 public FilterExpression(Expression start, Expression filter, StaticContext env) throws StaticError { 40 this.start = start; 41 this.filter = filter; 42 adoptChildExpression(start); 43 adoptChildExpression(filter); 44 45 if (env != null) { 46 try { 47 filterDependencies = filter.simplify(env).getDependencies(); 48 } catch (XPathException e) { 49 throw e.makeStatic(); 50 } 51 } 52 53 } 57 58 62 63 public ItemType getItemType() { 64 return start.getItemType(); 65 } 66 67 71 72 public Expression getBaseExpression() { 73 return start; 74 } 75 76 80 81 public Expression getFilter() { 82 return filter; 83 } 84 85 90 91 public boolean isPositional() { 92 return isPositionalFilter(filter); 93 } 94 95 public boolean isIndexable() { 96 return isIndexable != 0; 97 } 98 99 104 105 public Expression simplify(StaticContext env) throws XPathException { 106 107 if (filterDependencies == 0) { 108 filterDependencies = filter.simplify(env).getDependencies(); 109 } 110 111 start = start.simplify(env); 112 filter = filter.simplify(env); 113 114 if (start instanceof EmptySequence) { 116 return start; 117 } 118 119 if (filter instanceof Value && !(filter instanceof NumericValue)) { 121 try { 122 if (filter.effectiveBooleanValue(null)) { 123 return start; 124 } else { 125 return EmptySequence.getInstance(); 126 } 127 } catch (XPathException e) { 128 throw new StaticError(e); 129 } 130 } 131 132 134 if (filter instanceof Last) { 135 filter = new IsLastExpression(true); 136 } 137 138 return this; 139 140 } 141 142 148 149 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 150 151 start = start.typeCheck(env, contextItemType); 152 filter = filter.typeCheck(env, start.getItemType()); 153 154 156 filter = ExpressionTool.unsortedIfHomogeneous(env.getConfiguration().getOptimizer(), filter, false); 157 158 161 if (filter instanceof IntegerValue) { 162 if (((IntegerValue)filter).longValue() == 1) { 163 return new FirstItemExpression(start); 164 } 165 } 166 167 if (filter instanceof PositionRange) { 168 PositionRange range = (PositionRange)filter; 169 if (range.isFirstPositionOnly()) { 170 return new FirstItemExpression(start); 171 } 172 TailExpression tail = range.makeTailExpression(start); 173 if (tail != null) { 174 return tail; 175 } 176 } 177 178 filterIsPositional = isPositionalFilter(filter); 180 181 return this; 182 } 183 184 201 202 public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 203 204 start = start.optimize(opt, env, contextItemType); 205 filter = filter.optimize(opt, env, start.getItemType()); 206 207 209 filter = ExpressionTool.unsortedIfHomogeneous(opt, filter, false); 210 211 214 if (filter instanceof IntegerValue) { 215 if (((IntegerValue)filter).longValue() == 1) { 216 return new FirstItemExpression(start); 217 } 218 } 219 220 222 if (filter instanceof BooleanValue) { 223 if (((BooleanValue)filter).getBooleanValue()) { 224 return start; 225 } else { 226 return EmptySequence.getInstance(); 227 } 228 } 229 230 if (filter instanceof PositionRange) { 231 PositionRange range = (PositionRange)filter; 232 if (range.isFirstPositionOnly()) { 233 return new FirstItemExpression(start); 234 } 235 TailExpression tail = range.makeTailExpression(start); 236 if (tail != null) { 237 return tail; 238 } 239 } 240 241 filterIsPositional = isPositionalFilter(filter); 243 244 if (filterIsPositional) { 246 isIndexable = 0; 247 } else { 248 isIndexable = opt.isIndexableFilter(filter); 249 } 250 251 254 if (filterIsPositional && 255 filter instanceof BooleanExpression && 256 ((BooleanExpression)filter).operator == Token.AND) { 257 BooleanExpression bf = (BooleanExpression)filter; 258 if (isExplicitlyPositional(bf.operand0) && 259 !isExplicitlyPositional(bf.operand1)) { 260 Expression p0 = forceToBoolean(bf.operand0, env.getNamePool()); 261 Expression p1 = forceToBoolean(bf.operand1, env.getNamePool()); 262 FilterExpression f1 = new FilterExpression(start, p0, env); 263 FilterExpression f2 = new FilterExpression(f1, p1, env); 264 return f2.optimize(opt, env, contextItemType); 267 } 268 if (isExplicitlyPositional(bf.operand1) && 269 !isExplicitlyPositional(bf.operand0)) { 270 Expression p0 = forceToBoolean(bf.operand0, env.getNamePool()); 271 Expression p1 = forceToBoolean(bf.operand1, env.getNamePool()); 272 FilterExpression f1 = new FilterExpression(start, p1, env); 273 FilterExpression f2 = new FilterExpression(f1, p0, env); 274 return f2.optimize(opt, env, contextItemType); 277 } 278 } 279 280 filterIsRange = 281 filter instanceof PositionRange && !((PositionRange)filter).hasFocusDependentRange(); 282 283 287 288 289 290 PromotionOffer offer = new PromotionOffer(opt); 291 offer.action = PromotionOffer.FOCUS_INDEPENDENT; 292 offer.promoteDocumentDependent = (start.getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0; 293 offer.containingExpression = this; 294 filter = doPromotion(filter, offer); 295 296 if (offer.containingExpression instanceof LetExpression) { 297 offer.containingExpression = offer.containingExpression.optimize(opt, env, contextItemType); 298 } 299 300 return offer.containingExpression; 301 } 302 303 307 308 private static Expression forceToBoolean(Expression in, NamePool namePool) { 309 if (in.getItemType().getPrimitiveType() == Type.BOOLEAN) { 310 return in; 311 } 312 Expression[] args = {in}; 313 FunctionCall fn = SystemFunction.makeSystemFunction("boolean", 1, namePool); 314 fn.setArguments(args); 315 return fn; 316 } 317 318 323 324 public Expression promote(PromotionOffer offer) throws XPathException { 325 Expression exp = offer.accept(this); 326 if (exp != null) { 327 return exp; 328 } else { 329 if (!(offer.action == PromotionOffer.UNORDERED && filterIsPositional)) { 330 start = doPromotion(start, offer); 331 } 332 if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES || 333 offer.action == PromotionOffer.REPLACE_CURRENT) { 334 filter = doPromotion(filter, offer); 338 } 339 return this; 340 } 341 } 342 343 346 347 private static boolean isPositionalFilter(Expression exp) { 348 ItemType type = exp.getItemType(); 349 return ( type==Type.ANY_ATOMIC_TYPE || 350 type instanceof AnyItemType || 351 Type.isSubType(type, Type.NUMBER_TYPE) || 352 isExplicitlyPositional(exp)); 353 } 354 355 358 359 private static boolean isExplicitlyPositional(Expression exp) { 360 return (exp.getDependencies() & (StaticProperty.DEPENDS_ON_POSITION|StaticProperty.DEPENDS_ON_LAST)) != 0; 361 } 362 363 367 368 public Iterator iterateSubExpressions() { 369 return new PairIterator(start, filter); 370 } 371 372 377 378 public int computeCardinality() { 379 if (filter instanceof NumericValue) { 380 return StaticProperty.ALLOWS_ZERO_OR_ONE; 381 } 382 if (!Cardinality.allowsMany(start.getCardinality())) { 383 return StaticProperty.ALLOWS_ZERO_OR_ONE; 384 } 385 if (filter instanceof PositionRange) { 386 PositionRange p = (PositionRange)filter; 387 if (p.matchesAtMostOneItem()) { 388 return StaticProperty.ALLOWS_ZERO_OR_ONE; 389 } 390 } 391 if (filter instanceof IsLastExpression && ((IsLastExpression)filter).getCondition()) { 392 return StaticProperty.ALLOWS_ZERO_OR_ONE; 393 } 394 int sc = start.getCardinality(); 395 switch (sc) { 396 case StaticProperty.ALLOWS_ONE_OR_MORE: 397 return StaticProperty.ALLOWS_ZERO_OR_MORE; 398 case StaticProperty.EXACTLY_ONE: 399 return StaticProperty.ALLOWS_ZERO_OR_ONE; 400 default: 401 return sc; 402 } 403 } 404 405 411 412 public int computeSpecialProperties() { 413 return start.getSpecialProperties(); 414 } 415 416 421 422 public boolean equals(Object other) { 423 if (other instanceof FilterExpression) { 424 FilterExpression f = (FilterExpression)other; 425 return (start.equals(f.start) && 426 filter.equals(f.filter)); 427 } 428 return false; 429 } 430 431 435 436 public int hashCode() { 437 return "FilterExpression".hashCode() + start.hashCode() + filter.hashCode(); 438 } 439 440 446 447 public SequenceIterator iterate(XPathContext context) throws XPathException { 448 449 451 Expression startExp = start; 452 ValueRepresentation startValue = null; 453 if (startExp instanceof ValueRepresentation) { 454 startValue = (ValueRepresentation)startExp; 455 } else if (startExp instanceof VariableReference) { 456 startValue = ((VariableReference)startExp).evaluateVariable(context); 457 } 458 459 if (startValue instanceof Value) { 460 startExp = (Value)startValue; 461 } 462 463 if (startValue instanceof EmptySequence) { 464 return EmptyIterator.getInstance(); 465 } 466 467 ValueRepresentation filterValue = null; 468 if (filter instanceof ValueRepresentation) { 469 filterValue = (ValueRepresentation)filter; 470 } else if (filter instanceof VariableReference) { 471 filterValue = ((VariableReference)filter).evaluateVariable(context); 472 } 473 474 478 if (filterValue != null) { 479 if (filterValue instanceof Value) { 480 filterValue = ((Value)filterValue).reduce(); 481 } 482 if (filterValue instanceof NumericValue) { 483 if (((NumericValue)filterValue).isWholeNumber()) { 485 int pos = (int)(((NumericValue)filterValue).longValue()); 486 if (startValue != null) { 487 if (startValue instanceof Value) { 488 return SingletonIterator.makeIterator(((Value)startValue).itemAt(pos-1)); 490 } else if (startValue instanceof NodeInfo) { 491 if (pos == 1) { 493 return SingletonIterator.makeIterator((NodeInfo)startValue); 494 } else { 495 return EmptyIterator.getInstance(); 496 } 497 } 498 } 499 if (pos >= 1) { 500 SequenceIterator base = startExp.iterate(context); 501 return PositionIterator.make(base, pos, pos); 502 } else { 503 return EmptyIterator.getInstance(); 505 } 506 } else { 507 return EmptyIterator.getInstance(); 509 } 510 } else if (filterValue instanceof Value) { 511 513 if (((Value)filterValue).effectiveBooleanValue(context)) { 514 return start.iterate(context); 515 } else { 516 return EmptyIterator.getInstance(); 517 } 518 } else if (filterValue instanceof NodeInfo) { 519 return start.iterate(context); 520 } 521 } 522 523 525 if (isIndexable != 0 && startValue instanceof Closure && ((Closure)startValue).isIndexable()) { 526 SequenceIterator indexedResult = 527 context.getController().getConfiguration(). 528 getOptimizer().tryIndexedFilter(startValue, filter, isIndexable, context); 529 if (indexedResult != null) { 530 return indexedResult; 531 } 532 } 533 534 536 SequenceIterator base = startExp.iterate(context); 537 538 540 if (base instanceof EmptyIterator) { 541 return base; 542 } 543 544 547 if (filterIsRange) { 548 PositionRange pr = (PositionRange)filter; 549 return pr.makePositionIterator(base, context); 551 552 } else if (filterIsPositional) { 553 return new FilterIterator(base, filter, context); 554 555 } else { 556 return new FilterIterator.NonNumeric(base, filter, context); 557 } 558 559 } 560 561 567 568 public int computeDependencies() { 569 return (start.getDependencies() | 572 (filterDependencies & (StaticProperty.DEPENDS_ON_XSLT_CONTEXT | 573 StaticProperty.DEPENDS_ON_LOCAL_VARIABLES | 574 StaticProperty.DEPENDS_ON_USER_FUNCTIONS))); 575 } 576 577 578 579 584 585 public void display(int level, NamePool pool, PrintStream out) { 586 out.println(ExpressionTool.indent(level) + "filter []"); 587 start.display(level+1, pool, out); 588 filter.display(level+1, pool, out); 589 } 590 591 } 592 593 594 595 | Popular Tags |