1 package net.sf.saxon.expr; 2 import net.sf.saxon.om.*; 3 import net.sf.saxon.pattern.*; 4 import net.sf.saxon.trans.DynamicError; 5 import net.sf.saxon.trans.StaticError; 6 import net.sf.saxon.trans.XPathException; 7 import net.sf.saxon.type.*; 8 import net.sf.saxon.value.EmptySequence; 9 10 import java.io.PrintStream ; 11 12 13 23 24 public final class AxisExpression extends ComputedExpression { 25 26 private byte axis; 27 private NodeTest test; 28 private ItemType itemType = null; 29 int computedCardinality = -1; 30 31 39 40 public AxisExpression(byte axis, NodeTest nodeTest) { 41 this.axis = axis; 42 this.test = nodeTest; 43 } 44 45 49 50 public Expression simplify(StaticContext env) { 51 52 Expression exp = this; 53 if (axis == Axis.PARENT && (test==null || test instanceof AnyNodeTest)) { 54 exp = new ParentNodeExpression(); 55 ExpressionTool.copyLocationInfo(this, exp); 56 } 57 58 return exp; 59 } 60 61 64 65 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 66 if (contextItemType == null) { 67 StaticError err = new StaticError("Axis step " + toString() + 68 " cannot be used here: the context item is undefined"); 69 err.setIsTypeError(true); 70 err.setErrorCode("XPDY0002"); 71 err.setLocator(this); 72 throw err; 73 } 74 if (contextItemType instanceof AtomicType) { 75 StaticError err = new StaticError("Axis step " + toString() + 76 " cannot be used here: the context item is an atomic value"); 77 err.setIsTypeError(true); 78 err.setErrorCode("XPTY0020"); 79 err.setLocator(this); 80 throw err; 81 } 82 83 if (contextItemType instanceof NodeTest) { 84 int origin = contextItemType.getPrimitiveType(); 85 if (origin != Type.NODE) { 86 if (Axis.isAlwaysEmpty(axis, origin)) { 87 env.issueWarning("The " + Axis.axisName[axis] + " axis starting at " + 88 (origin==Type.ELEMENT || origin == Type.ATTRIBUTE ? "an " : "a ") + 89 NodeKindTest.toString(origin) + " node will never select anything", 90 this); 91 return EmptySequence.getInstance(); 92 } 93 } 94 95 if (test != null) { 96 int kind = test.getPrimitiveType(); 97 if (kind != Type.NODE) { 98 if (!Axis.containsNodeKind(axis, kind)) { 99 env.issueWarning("The " + Axis.axisName[axis] + " axis will never select any " + 100 NodeKindTest.toString(kind) + " nodes", 101 this); 102 return EmptySequence.getInstance(); 103 } 104 } 105 if (axis==Axis.SELF && kind!=Type.NODE && origin!=Type.NODE && kind!=origin) { 106 env.issueWarning("The self axis will never select any " + 107 NodeKindTest.toString(origin) + 108 " nodes when starting at " + 109 (origin==Type.ELEMENT || origin == Type.ATTRIBUTE ? "an " : "a ") + 110 NodeKindTest.toString(kind) + " node", this); 111 return EmptySequence.getInstance(); 112 } 113 114 116 SchemaType contentType = ((NodeTest)contextItemType).getContentType(); 117 if (contentType == AnyType.getInstance()) { 118 return this; 120 } 121 122 int targetfp = test.getFingerprint(); 123 124 if (contentType.isSimpleType()) { 125 if ((axis == Axis.CHILD || axis==Axis.ATTRIBUTE || axis==Axis.DESCENDANT || axis==Axis.DESCENDANT_OR_SELF) && 126 (kind==Type.ELEMENT || kind==Type.ATTRIBUTE || kind==Type.DOCUMENT)) { 127 StaticError err = new StaticError("The " + Axis.axisName[axis] + " axis will never select any " + 128 NodeKindTest.toString(kind) + 129 " nodes when starting at a node with simple type " + 130 contentType.getDescription(), this); 131 err.setLocator(this); 132 throw err; 133 } 134 } else if (((ComplexType)contentType).isSimpleContent() && 135 (axis==Axis.CHILD || axis==Axis.DESCENDANT || axis==Axis.DESCENDANT_OR_SELF) && 136 (kind==Type.ELEMENT || kind==Type.DOCUMENT)) { 137 StaticError err = new StaticError("The " + Axis.axisName[axis] + " axis will never select any " + 138 NodeKindTest.toString(kind) + 139 " nodes when starting at a node with type " + 140 contentType.getDescription() + 141 ", as this type requires simple content", this); 142 err.setLocator(this); 143 throw err; 144 } else if (((ComplexType)contentType).isEmptyContent() && 145 (axis==Axis.CHILD || axis==Axis.DESCENDANT || axis==Axis.DESCENDANT_OR_SELF)) { 146 StaticError err = new StaticError("The " + Axis.axisName[axis] + " axis will never select any " + 147 " nodes when starting at a node with type " + 148 contentType.getDescription() + 149 ", as this type requires empty content", this); 150 err.setLocator(this); 151 throw err; 152 } else if (axis==Axis.ATTRIBUTE && targetfp != -1) { 153 try { 154 SchemaType schemaType = ((ComplexType)contentType).getAttributeUseType(targetfp); 155 if (schemaType == null) { 156 String n = env.getNamePool().getDisplayName(targetfp); 157 if (contentType.allowsDerivation(SchemaType.DERIVATION_EXTENSION)) { 158 env.issueWarning("The complex type " + 159 contentType.getDescription() + 160 " does not allow an attribute named " + 161 n + 162 ". The expression will select nothing, unless " + 163 "there is another type that extends this type", this); 164 itemType = NodeKindTest.ELEMENT; 165 } else { 166 StaticError err = new StaticError("The complex type " + 167 contentType.getDescription() + 168 " does not allow an attribute named " + n); 169 err.setLocator(this); 170 throw err; 171 } 172 } else { 173 itemType = new CombinedNodeTest( 174 test, 175 Token.INTERSECT, 176 new ContentTypeTest(Type.ATTRIBUTE, schemaType, env.getConfiguration())); 177 } 178 } catch (SchemaException e) { 179 } 181 } else if (axis==Axis.CHILD && kind==Type.ELEMENT && targetfp != -1) { 182 try { 183 SchemaType schemaType = ((ComplexType)contentType).getElementParticleType(targetfp); 184 if (schemaType == null) { 185 String n = env.getNamePool().getDisplayName(targetfp); 186 if (contentType.allowsDerivation(SchemaType.DERIVATION_EXTENSION)) { 187 env.issueWarning("The complex type " + 188 contentType.getDescription() + 189 " does not allow a child element named " + 190 n + 191 ". The expression will select nothing, unless " + 192 "there is another type that extends this one", this); 193 itemType = NodeKindTest.ELEMENT; 194 } else { 195 StaticError err = new StaticError("The complex type " + 196 contentType.getDescription() + 197 " does not allow a child element named " + n); 198 err.setLocator(this); 199 throw err; 200 } 201 } else { 202 itemType = new CombinedNodeTest( 203 test, 204 Token.INTERSECT, 205 new ContentTypeTest(Type.ELEMENT, schemaType, env.getConfiguration())); 206 computedCardinality = ((ComplexType)contentType).getElementParticleCardinality(targetfp); 207 resetStaticProperties(); 208 } 209 } catch (SchemaException e) { 210 } 212 } 213 } 214 } 215 216 return this; 217 } 218 219 234 235 public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) { 236 return this; 237 } 238 239 242 243 public boolean equals(Object other) { 244 if (!(other instanceof AxisExpression)) { 245 return false; 246 } 247 if (axis != ((AxisExpression)other).axis) { 248 return false; 249 } 250 if (test==null) { 251 return ((AxisExpression)other).test==null; 252 } 253 return test.toString().equals(((AxisExpression)other).test.toString()); 254 } 255 256 259 260 public int hashCode() { 261 int h = 9375162 + axis<<20; 263 if (test != null) { 264 h ^= test.getPrimitiveType()<<16; 265 h ^= test.getFingerprint(); 266 } 267 return h; 268 } 269 270 275 276 public int getIntrinsicDependencies() { 277 return StaticProperty.DEPENDS_ON_CONTEXT_ITEM; 278 } 279 280 285 286 public int computeSpecialProperties() { 287 return StaticProperty.CONTEXT_DOCUMENT_NODESET | 288 StaticProperty.SINGLE_DOCUMENT_NODESET | 289 StaticProperty.NON_CREATIVE | 290 (Axis.isForwards[axis] ? StaticProperty.ORDERED_NODESET : StaticProperty.REVERSE_DOCUMENT_ORDER) | 291 (Axis.isPeerAxis[axis] ? StaticProperty.PEER_NODESET : 0) | 292 (Axis.isSubtreeAxis[axis] ? StaticProperty.SUBTREE_NODESET : 0) | 293 ((axis==Axis.ATTRIBUTE || axis==Axis.NAMESPACE) ? StaticProperty.ATTRIBUTE_NS_NODESET : 0); 294 } 295 296 301 302 public final ItemType getItemType() { 303 if (itemType != null) { 304 return itemType; 305 } 306 int p = Axis.principalNodeType[axis]; 307 switch (p) { 308 case Type.ATTRIBUTE: 309 case Type.NAMESPACE: 310 return NodeKindTest.makeNodeKindTest(p); 311 default: 312 if (test==null) { 313 return AnyNodeTest.getInstance(); 314 } else { 315 return test; 316 } 318 } 319 } 320 321 324 325 public final int computeCardinality() { 326 if (computedCardinality != -1) { 327 return computedCardinality; 328 } 329 if (axis == Axis.ATTRIBUTE && test instanceof NameTest) { 330 return StaticProperty.ALLOWS_ZERO_OR_ONE; 331 } else if (axis == Axis.SELF) { 332 return StaticProperty.ALLOWS_ZERO_OR_ONE; 333 } else { 334 return StaticProperty.ALLOWS_ZERO_OR_MORE; 335 } 336 } 338 339 342 343 public byte getAxis() { 344 return axis; 345 } 346 347 350 351 public NodeTest getNodeTest() { 352 return test; 353 } 354 355 359 360 public SequenceIterator iterate(XPathContext context) throws XPathException { 361 Item item = context.getContextItem(); 362 try { 363 if (test==null) { 364 return ((NodeInfo)item).iterateAxis(axis); 365 } else { 366 return ((NodeInfo)item).iterateAxis(axis, test); 367 } 368 } catch (NullPointerException npe) { 369 DynamicError err = new DynamicError("The context item for axis step " + toString() + " is undefined"); 370 err.setErrorCode("XPDY0002"); 371 err.setXPathContext(context); 372 err.setLocator(this); 373 err.setIsTypeError(true); 374 throw err; 375 } catch (ClassCastException cce) { 376 DynamicError err = new DynamicError("The context item for axis step " + toString() + " is not a node"); 377 err.setErrorCode("XPTY0020"); 378 err.setXPathContext(context); 379 err.setLocator(this); 380 err.setIsTypeError(true); 381 throw err; 382 } catch (UnsupportedOperationException err) { 383 dynamicError(err.getMessage(), context); 385 return null; 386 } 387 } 388 389 392 393 public void display(int level, NamePool pool, PrintStream out) { 394 out.println(ExpressionTool.indent(level) + toString()); 395 } 396 397 400 401 public String toString() { 402 return Axis.axisName[axis] + 403 "::" + 404 (test==null ? "node()" : test.toString()); 405 } 406 } 407 408 409 410 | Popular Tags |