KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > expr > AxisExpression


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 JavaDoc;
11
12
13 /**
14  * An AxisExpression is always obtained by simplifying a PathExpression.
15  * It represents a PathExpression that starts at the context node, and uses
16  * a simple node-test with no filters. For example "*", "title", "./item",
17  * "@*", or "ancestor::chapter*".
18  *
19  * <p>An AxisExpression delivers nodes in axis order (not in document order).
20  * To get nodes in document order, in the case of a reverse axis, the expression
21  * should be wrapped in a Reverser.</p>
22 */

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     /**
32     * Constructor
33     * @param axis The axis to be used in this AxisExpression: relevant constants are defined
34      * in class net.sf.saxon.om.Axis.
35     * @param nodeTest The conditions to be satisfied by selected nodes. May be null,
36      * indicating that any node on the axis is acceptable
37      * @see net.sf.saxon.om.Axis
38     */

39
40     public AxisExpression(byte axis, NodeTest nodeTest) {
41         this.axis = axis;
42         this.test = nodeTest;
43     }
44
45     /**
46     * Simplify an expression
47     * @return the simplified expression
48     */

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     /**
62     * Type-check the expression
63     */

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                 // If the content type of the context item is known, see whether the node test can select anything
115

116                 SchemaType contentType = ((NodeTest)contextItemType).getContentType();
117                 if (contentType == AnyType.getInstance()) {
118                     // fast exit in non-schema-aware case
119
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 JavaDoc 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                         // ignore the exception
180
}
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 JavaDoc 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                         // ignore the exception
211
}
212                 }
213             }
214         }
215
216         return this;
217     }
218
219     /**
220      * Perform optimisation of an expression and its subexpressions.
221      * <p/>
222      * <p>This method is called after all references to functions and variables have been resolved
223      * to the declaration of the function or variable, and after all type checking has been done.</p>
224      *
225      * @param opt the optimizer in use. This provides access to supporting functions; it also allows
226      * different optimization strategies to be used in different circumstances.
227      * @param env the static context of the expression
228      * @param contextItemType the static type of "." at the point where this expression is invoked.
229      * The parameter is set to null if it is known statically that the context item will be undefined.
230      * If the type of the context item is not known statically, the argument is set to
231      * {@link net.sf.saxon.type.Type#ITEM_TYPE}
232      * @return the original expression, rewritten if appropriate to optimize execution
233      */

234
235     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) {
236         return this;
237     }
238
239     /**
240     * Is this expression the same as another expression?
241     */

242
243     public boolean equals(Object JavaDoc 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     /**
257     * get HashCode for comparing two expressions
258     */

259
260     public int hashCode() {
261         // generate an arbitrary hash code that depends on the axis and the node test
262
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     /**
271     * Determine which aspects of the context the expression depends on. The result is
272     * a bitwise-or'ed value composed from constants such as XPathContext.VARIABLES and
273     * XPathContext.CURRENT_NODE
274     */

275
276     public int getIntrinsicDependencies() {
277         return StaticProperty.DEPENDS_ON_CONTEXT_ITEM;
278     }
279
280     /**
281     * Get the static properties of this expression (other than its type). The result is
282     * bit-signficant. These properties are used for optimizations. In general, if
283     * property bit is set, it is true, but if it is unset, the value is unknown.
284     */

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     /**
297     * Determine the data type of the items returned by this expression
298     * @return Type.NODE or a subtype, based on the NodeTest in the axis step, plus
299      * information about the content type if this is known from schema analysis
300     */

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                 //return NodeKindTest.makeNodeKindTest(test.getPrimitiveType());
317
}
318         }
319     }
320
321     /**
322     * Specify that the expression returns a singleton
323     */

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         // the parent axis isn't handled by this class
337
}
338
339     /**
340     * Get the axis
341     */

342
343     public byte getAxis() {
344         return axis;
345     }
346
347     /**
348     * Get the NodeTest. Returns null if the AxisExpression can return any node.
349     */

350
351     public NodeTest getNodeTest() {
352         return test;
353     }
354
355     /**
356     * Evaluate the path-expression in a given context to return a NodeSet
357     * @param context the evaluation context
358     */

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 JavaDoc 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 JavaDoc 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 JavaDoc err) {
383             // the namespace axis is not supported for all tree implementations
384
dynamicError(err.getMessage(), context);
385             return null;
386         }
387     }
388
389     /**
390     * Diagnostic print of expression structure
391     */

392
393     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
394         out.println(ExpressionTool.indent(level) + toString());
395     }
396
397     /**
398      * Represent the expression as a string for diagnostics
399      */

400
401     public String JavaDoc toString() {
402         return Axis.axisName[axis] +
403                 "::" +
404                 (test==null ? "node()" : test.toString());
405     }
406 }
407
408
409
410 //
411
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
412
// you may not use this file except in compliance with the License. You may obtain a copy of the
413
// License at http://www.mozilla.org/MPL/
414
//
415
// Software distributed under the License is distributed on an "AS IS" basis,
416
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
417
// See the License for the specific language governing rights and limitations under the License.
418
//
419
// The Original Code is: all this file.
420
//
421
// The Initial Developer of the Original Code is Michael H. Kay.
422
//
423
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
424
//
425
// Contributor(s): none.
426
//
427
Popular Tags