1 package net.sf.saxon.pattern; 2 import net.sf.saxon.expr.*; 3 import net.sf.saxon.om.*; 4 import net.sf.saxon.style.ExpressionContext; 5 import net.sf.saxon.trace.Location; 6 import net.sf.saxon.trans.DynamicError; 7 import net.sf.saxon.trans.StaticError; 8 import net.sf.saxon.trans.XPathException; 9 import net.sf.saxon.type.ItemType; 10 import net.sf.saxon.type.Type; 11 import net.sf.saxon.value.BooleanValue; 12 import net.sf.saxon.value.IntegerValue; 13 14 import java.util.Arrays ; 15 import java.util.Collections ; 16 import java.util.Iterator ; 17 18 22 23 public final class LocationPathPattern extends Pattern { 24 25 27 public Pattern parentPattern = null; 28 public Pattern ancestorPattern = null; 29 public NodeTest nodeTest = AnyNodeTest.getInstance(); 30 protected Expression[] filters = null; 31 protected int numberOfFilters = 0; 32 protected Expression equivalentExpr = null; 33 protected boolean firstElementPattern = false; 34 protected boolean lastElementPattern = false; 35 protected boolean specialFilter = false; 36 private Expression variableBinding = null; 37 private NodeTest refinedNodeTest = null; 38 39 43 44 public void addFilter(Expression filter) { 45 if (filters==null) { 46 filters = new Expression[3]; 47 } else if (numberOfFilters == filters.length) { 48 Expression[] f2 = new Expression[numberOfFilters * 2]; 49 System.arraycopy(filters, 0, f2, 0, numberOfFilters); 50 filters = f2; 51 } 52 filters[numberOfFilters++] = filter; 53 ExpressionTool.makeParentReferences(filter); 54 if (filter instanceof ComputedExpression) { 55 ((ComputedExpression)filter).setParentExpression(this); 56 } 57 } 58 59 62 63 public Pattern simplify(StaticContext env) throws XPathException { 64 65 67 if ( parentPattern == null && 68 ancestorPattern == null && 69 filters == null && 70 !firstElementPattern && 71 !lastElementPattern) { 72 NodeTestPattern ntp = new NodeTestPattern(nodeTest); 73 ntp.setSystemId(getSystemId()); 74 ntp.setLineNumber(getLineNumber()); 75 return ntp; 76 } 77 78 80 if (parentPattern != null) { 81 parentPattern = parentPattern.simplify(env); 82 } else if (ancestorPattern != null) { 83 ancestorPattern = ancestorPattern.simplify(env); 84 } 85 86 if (filters != null) { 87 for (int i=numberOfFilters-1; i>=0; i--) { 88 Expression filter = filters[i]; 89 filter = filter.simplify(env); 90 filters[i] = filter; 91 int dep = filter.getDependencies(); 92 if ((dep & StaticProperty.DEPENDS_ON_CURRENT_GROUP) != 0) { 93 String errorCode = "XTSE1060"; 94 String function = "current-group()"; 95 if (toString().indexOf("current-grouping-key") >= 0) { 96 errorCode = "XTSE1070"; 97 function = "current-grouping-key()"; 98 } 99 StaticError err = new StaticError("The " + function + " function cannot be used in a pattern"); 100 err.setErrorCode(errorCode); 101 throw err; 102 } 103 } 104 } 105 106 return this; 107 } 108 109 113 114 public Pattern analyze(StaticContext env, ItemType contextItemType) throws XPathException { 115 116 118 if (parentPattern != null) { 119 parentPattern = parentPattern.analyze(env, contextItemType); 120 AxisExpression step; 122 if (nodeTest.getPrimitiveType() == Type.ATTRIBUTE) { 123 step = new AxisExpression(Axis.ATTRIBUTE, nodeTest); 124 } else { 125 step = new AxisExpression(Axis.CHILD, nodeTest); 126 } 127 step.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), getLineNumber())); 128 step.setParentExpression(this); 129 Expression exp = step.typeCheck(env, parentPattern.getNodeTest()); 130 refinedNodeTest = (NodeTest)exp.getItemType(); 131 } else if (ancestorPattern != null) { 132 ancestorPattern = ancestorPattern.analyze(env, contextItemType); 133 } 134 135 if (filters != null) { 136 for (int i=numberOfFilters-1; i>=0; i--) { 137 Expression filter = filters[i].typeCheck(env, getNodeTest()); 138 filters[i] = filter; 140 if ((filter instanceof BooleanValue) && ((BooleanValue)filter).getBooleanValue()) { 142 if (i==numberOfFilters-1) { 143 numberOfFilters--; 144 } } 146 147 if (env instanceof ExpressionContext) { 151 ((ExpressionContext)env).getStyleElement().allocateSlots(filter); 152 filters[i] = filter; 153 } 154 } 155 } 156 157 159 if (nodeTest.getPrimitiveType() == Type.ELEMENT && numberOfFilters==1) { 160 if (((filters[0] instanceof IntegerValue) && 161 ((IntegerValue)filters[0]).longValue()==1) || 162 ((filters[0] instanceof PositionRange) && 163 ((PositionRange)filters[0]).isFirstPositionOnly()) ) { 164 firstElementPattern = true; 165 specialFilter = true; 166 numberOfFilters = 0; 167 filters = null; 168 } 169 } 170 171 174 if (nodeTest.getPrimitiveType() == Type.ELEMENT && 175 numberOfFilters==1 && 176 filters[0] instanceof IsLastExpression && 177 ((IsLastExpression)filters[0]).getCondition()) { 178 lastElementPattern = true; 179 specialFilter = true; 180 numberOfFilters = 0; 181 filters = null; 182 } 183 184 if (isPositional()) { 185 equivalentExpr = makeEquivalentExpression(env); 186 equivalentExpr = equivalentExpr.typeCheck(env, contextItemType); 187 ((ExpressionContext)env).getStyleElement().allocateSlots(equivalentExpr); 190 specialFilter = true; 191 } 192 193 return this; 194 195 } 198 199 203 204 public int getDependencies() { 205 int dependencies = 0; 206 if (parentPattern != null) { 207 dependencies |= parentPattern.getDependencies(); 208 } 209 if (ancestorPattern != null) { 210 dependencies |= ancestorPattern.getDependencies(); 211 } 212 for (int i=0; i<numberOfFilters; i++) { 213 dependencies |= filters[i].getDependencies(); 214 } 215 dependencies &= StaticProperty.DEPENDS_ON_LOCAL_VARIABLES; 217 return dependencies; 218 } 219 220 223 224 public Iterator iterateSubExpressions() { 225 Iterator iter; 226 if (numberOfFilters == 0) { 227 iter = Collections.EMPTY_LIST.iterator(); 228 } else { 229 iter = Arrays.asList(filters).subList(0, numberOfFilters).iterator(); 230 } 231 if (variableBinding != null) { 232 Iterator [] pair = {iter, new MonoIterator(variableBinding)}; 233 iter = new MultiIterator(pair); 234 } 235 if (parentPattern != null) { 236 Iterator [] pair = {iter, parentPattern.iterateSubExpressions()}; 237 iter = new MultiIterator(pair); 238 } 239 if (ancestorPattern != null) { 240 Iterator [] pair = {iter, ancestorPattern.iterateSubExpressions()}; 241 iter = new MultiIterator(pair); 242 } 243 return iter; 244 } 245 246 264 265 public void promote(PromotionOffer offer) throws XPathException { 266 267 if (parentPattern != null) { 268 parentPattern.promote(offer); 269 } 270 if (ancestorPattern != null) { 271 ancestorPattern.promote(offer); 272 } 273 for (int i=0; i<numberOfFilters; i++) { 274 filters[i] = filters[i].promote(offer); 275 } 276 } 277 278 281 282 private ComputedExpression makeEquivalentExpression(StaticContext env) throws XPathException { 283 byte axis = (nodeTest.getPrimitiveType()==Type.ATTRIBUTE ? 284 Axis.ATTRIBUTE : 285 Axis.CHILD ); 286 ComputedExpression step = new AxisExpression(axis, nodeTest); 287 for (int n=0; n<numberOfFilters; n++) { 288 step = new FilterExpression(step, filters[n], env); 289 } 290 PathExpression path = new PathExpression(new ParentNodeExpression(), step); 291 path.setParentExpression(this); 292 return path; 293 } 295 296 301 302 public boolean matches(NodeInfo node, XPathContext context) throws XPathException { 303 if (variableBinding != null) { 304 variableBinding.evaluateItem(context); 305 } 306 return internalMatches(node, context); 307 } 311 312 315 316 protected boolean internalMatches(NodeInfo node, XPathContext context) throws XPathException { 317 if (!nodeTest.matches(node)) { 319 return false; 320 } 321 if (parentPattern!=null) { 322 NodeInfo par = node.getParent(); 324 if (par==null) return false; 325 if (!parentPattern.internalMatches(par, context)) { 326 return false; 327 } 328 } 329 330 if (ancestorPattern!=null) { 331 NodeInfo anc = node.getParent(); 332 while (true) { 333 if (anc==null) return false; 334 if (ancestorPattern.internalMatches(anc, context)) break; 335 anc = anc.getParent(); 336 } 337 } 338 339 if (specialFilter) { 340 if (firstElementPattern) { 341 SequenceIterator iter = node.iterateAxis(Axis.PRECEDING_SIBLING, nodeTest); 342 return iter.next() == null; 343 } 344 345 if (lastElementPattern) { 346 SequenceIterator iter = node.iterateAxis(Axis.FOLLOWING_SIBLING, nodeTest); 347 return iter.next() == null; 348 } 349 350 if (equivalentExpr!=null) { 351 352 356 XPathContext c2 = context.newMinorContext(); 358 c2.setOriginatingConstructType(Location.PATTERN); 359 AxisIterator single = SingletonIterator.makeIterator(node); 360 single.next(); 361 c2.setCurrentIterator(single); 362 try { 363 SequenceIterator nsv = equivalentExpr.iterate(c2); 364 while (true) { 365 NodeInfo n = (NodeInfo)nsv.next(); 366 if (n == null) { 367 return false; 368 } 369 if (n.isSameNodeInfo(node)) { 370 return true; 371 } 372 } 373 } catch (DynamicError e) { 374 DynamicError err = new DynamicError("An error occurred matching pattern {" + toString() + "}: ", e); 375 err.setXPathContext(c2); 376 err.setErrorCode(e.getErrorCodeLocalPart()); 377 err.setLocator(this); 378 c2.getController().recoverableError(err); 379 return false; 380 } 381 } 382 } 383 384 if (filters!=null) { 385 XPathContext c2 = context.newMinorContext(); 386 c2.setOriginatingConstructType(Location.PATTERN); 387 AxisIterator iter = SingletonIterator.makeIterator(node); 388 iter.next(); 389 c2.setCurrentIterator(iter); 390 392 for (int i=0; i<numberOfFilters; i++) { 393 try { 394 if (!filters[i].effectiveBooleanValue(c2)) { 395 return false; 396 } 397 } catch (DynamicError e) { 398 DynamicError err = new DynamicError("An error occurred matching pattern {" + toString() + "}: ", e); 399 err.setXPathContext(c2); 400 err.setErrorCode(e.getErrorCodeLocalPart()); 401 err.setLocator(this); 402 c2.getController().recoverableError(err); 403 return false; 404 } 405 } 406 } 407 408 return true; 409 } 410 411 416 417 public int getNodeKind() { 418 return nodeTest.getPrimitiveType(); 419 } 420 421 426 427 public int getFingerprint() { 428 return nodeTest.getFingerprint(); 429 } 430 431 434 435 public NodeTest getNodeTest() { 436 if (refinedNodeTest != null) { 437 return refinedNodeTest; 438 } else { 439 return nodeTest; 440 } 441 } 442 443 448 449 private boolean isPositional() { 450 if (filters==null) return false; 451 for (int i=0; i<numberOfFilters; i++) { 452 int type = filters[i].getItemType().getPrimitiveType(); 453 if (type==Type.DOUBLE || type==Type.DECIMAL || 454 type==Type.INTEGER || type==Type.FLOAT || type==Type.ATOMIC) return true; 455 if ((filters[i].getDependencies() & 456 (StaticProperty.DEPENDS_ON_POSITION | StaticProperty.DEPENDS_ON_LAST)) != 0) return true; 457 } 458 return false; 459 } 460 461 470 471 public void resolveCurrent(LetExpression let, PromotionOffer offer) throws XPathException { 472 for (int i=0; i<numberOfFilters; i++) { 473 filters[i] = filters[i].promote(offer); 474 } 475 if (parentPattern instanceof LocationPathPattern) { 476 ((LocationPathPattern)parentPattern).resolveCurrent(let, offer); 477 } 478 if (ancestorPattern instanceof LocationPathPattern) { 479 ((LocationPathPattern)ancestorPattern).resolveCurrent(let, offer); 480 } 481 variableBinding = let; 482 } 483 } 484 485 | Popular Tags |