KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.expr;
2
3 import net.sf.saxon.om.*;
4 import net.sf.saxon.sort.DocumentOrderIterator;
5 import net.sf.saxon.sort.GlobalOrderComparer;
6 import net.sf.saxon.trace.Location;
7 import net.sf.saxon.trans.DynamicError;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.type.ItemType;
10 import net.sf.saxon.value.AtomicValue;
11 import net.sf.saxon.value.Cardinality;
12
13 import java.io.PrintStream JavaDoc;
14 import java.util.Iterator JavaDoc;
15
16 /**
17  * A simple mapping expression is an expression A/B where B has a static type that is an atomic type.
18  * For example, * / name().
19  */

20
21 public final class SimpleMappingExpression extends ComputedExpression implements MappingFunction {
22
23     private Expression start;
24     private Expression step;
25     private boolean isHybrid;
26
27     /**
28      * Constructor
29      * @param start A node-set expression denoting the absolute or relative set of nodes from which the
30      * navigation path should start.
31      * @param step The step to be followed from each node in the start expression to yield a new
32      * node-set
33      * @param isHybrid if true, indicates that we don't know statically whether the step expression will
34      * return nodes or atomic values. If false, we know it will return atomic values.
35      */

36
37     public SimpleMappingExpression(Expression start, Expression step, boolean isHybrid) {
38         this.start = start;
39         this.step = step;
40         this.isHybrid = isHybrid;
41         adoptChildExpression(start);
42         adoptChildExpression(step);
43
44     }
45
46     /**
47      * Get the start expression (the left-hand operand)
48      */

49
50     public Expression getStartExpression() {
51         return start;
52     }
53
54     /**
55      * Get the step expression (the right-hand operand)
56      */

57
58     public Expression getStepExpression() {
59         return step;
60     }
61     /**
62      * Determine the data type of the items returned by this exprssion
63      * @return the type of the step
64      */

65
66     public final ItemType getItemType() {
67         return step.getItemType();
68     }
69
70     /**
71      * Simplify an expression
72      * @return the simplified expression
73      */

74
75      public Expression simplify(StaticContext env) {
76         // We rely on the fact that the operands were already simplified
77
return this;
78     }
79
80     /**
81      * Type-check the expression
82      */

83
84     public Expression typeCheck(StaticContext env, ItemType contextItemType) {
85         // rely on the fact that the original path expression has already been type-checked
86
return this;
87     }
88
89     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
90         return this;
91     }
92
93     /**
94      * Promote this expression if possible
95      */

96
97     public Expression promote(PromotionOffer offer) throws XPathException {
98         Expression exp = offer.accept(this);
99         if (exp != null) {
100             return exp;
101         } else {
102             start = doPromotion(start, offer);
103             if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES ||
104                     offer.action == PromotionOffer.REPLACE_CURRENT) {
105                 // Don't pass on other requests. We could pass them on, but only after augmenting
106
// them to say we are interested in subexpressions that don't depend on either the
107
// outer context or the inner context.
108
step = doPromotion(step, offer);
109             }
110             resetStaticProperties();
111             return this;
112         }
113     }
114
115     /**
116      * Get the immediate subexpressions of this expression
117      */

118
119     public Iterator iterateSubExpressions() {
120         return new PairIterator(start, step);
121     }
122     /**
123      * Determine which aspects of the context the expression depends on. The result is
124      * a bitwise-or'ed value composed from constants such as XPathContext.VARIABLES and
125      * XPathContext.CURRENT_NODE
126      */

127
128     public int computeDependencies() {
129         return start.getDependencies() |
130                 // not all dependencies in the step matter, because the context node, etc,
131
// are not those of the outer expression
132
(step.getDependencies() & StaticProperty.DEPENDS_ON_XSLT_CONTEXT);
133     }
134
135     /**
136      * Get the static properties of this expression (other than its type). The result is
137      * bit-signficant. These properties are used for optimizations. In general, if
138      * property bit is set, it is true, but if it is unset, the value is unknown.
139      */

140
141     public int computeSpecialProperties() {
142         int p = super.computeSpecialProperties();
143         if ((start.getSpecialProperties() & step.getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) {
144             p |= StaticProperty.NON_CREATIVE;
145         }
146         return p;
147     }
148
149     /**
150      * Determine the static cardinality of the expression
151      */

152
153     public int computeCardinality() {
154         int c1 = start.getCardinality();
155         int c2 = step.getCardinality();
156         return Cardinality.multiply(c1, c2);
157     }
158
159     /**
160      * Is this expression the same as another expression?
161      */

162
163     public boolean equals(Object JavaDoc other) {
164         if (!(other instanceof SimpleMappingExpression)) {
165             return false;
166         }
167         SimpleMappingExpression p = (SimpleMappingExpression) other;
168         return (start.equals(p.start) && step.equals(p.step));
169     }
170
171     /**
172      * get HashCode for comparing two expressions
173      */

174
175     public int hashCode() {
176         return "SimpleMappingExpression".hashCode() + start.hashCode() + step.hashCode();
177     }
178
179     /**
180      * Iterate the path-expression in a given context
181      * @param context the evaluation context
182      */

183
184     public SequenceIterator iterate(XPathContext context) throws XPathException {
185
186         // This class delivers the result of the path expression in unsorted order,
187
// without removal of duplicates. If sorting and deduplication are needed,
188
// this is achieved by wrapping the path expression in a DocumentSorter
189

190         SequenceIterator result = start.iterate(context);
191         XPathContext context2 = context.newMinorContext();
192         context2.setCurrentIterator(result);
193         context2.setOriginatingConstructType(Location.PATH_EXPRESSION);
194
195         result = new MappingIterator(result, this, context2);
196         if (isHybrid) {
197             // This case is rare so we don't worry too much about performance
198
// Peek at the first node, and depending on its type, check that all the items
199
// are atomic values or that all are nodes.
200
Item first = result.next();
201             if (first == null) {
202                 return EmptyIterator.getInstance();
203             } else if (first instanceof AtomicValue) {
204                 return new MappingIterator(result.getAnother(), AtomicValueChecker.theInstance, null);
205             } else {
206                 return new DocumentOrderIterator(
207                     new MappingIterator(result.getAnother(), NodeChecker.theInstance, null),
208                     GlobalOrderComparer.getInstance());
209             }
210         } else {
211             return result;
212         }
213     }
214
215     /**
216      * Mapping function, from a node returned by the start iteration, to a sequence
217      * returned by the child.
218      */

219
220     public Object JavaDoc map(Item item, XPathContext context) throws XPathException {
221         return step.iterate(context);
222     }
223
224     /**
225      * Diagnostic print of expression structure
226      */

227
228     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
229         out.println(ExpressionTool.indent(level) + "map /");
230         start.display(level + 1, pool, out);
231         step.display(level + 1, pool, out);
232     }
233
234     private static class AtomicValueChecker implements MappingFunction {
235         public static AtomicValueChecker theInstance = new AtomicValueChecker();
236         public Object JavaDoc map(Item item, XPathContext context) throws XPathException {
237             if (item instanceof AtomicValue) {
238                 return item;
239             } else {
240                 DynamicError err = new DynamicError(
241                         "Cannot mix nodes and atomic values in the result of a path expression");
242                 err.setErrorCode("XPTY0018");
243                 err.setXPathContext(context);
244                 throw err;
245             }
246         }
247     }
248
249     private static class NodeChecker implements MappingFunction {
250         public static NodeChecker theInstance = new NodeChecker();
251         public Object JavaDoc map(Item item, XPathContext context) throws XPathException {
252             if (item instanceof NodeInfo) {
253                 return item;
254             } else {
255                 DynamicError err = new DynamicError(
256                         "Cannot mix nodes and atomic values in the result of a path expression");
257                 err.setErrorCode("XPTY0018");
258                 err.setXPathContext(context);
259                 throw err;
260             }
261         }
262     }
263 }
264
265
266 //
267
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
268
// you may not use this file except in compliance with the License. You may obtain a copy of the
269
// License at http://www.mozilla.org/MPL/
270
//
271
// Software distributed under the License is distributed on an "AS IS" basis,
272
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
273
// See the License for the specific language governing rights and limitations under the License.
274
//
275
// The Original Code is: all this file.
276
//
277
// The Initial Developer of the Original Code is Michael H. Kay.
278
//
279
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
280
//
281
// Contributor(s): none.
282
//
283
Popular Tags