KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.expr;
2 import net.sf.saxon.Configuration;
3 import net.sf.saxon.om.*;
4 import net.sf.saxon.pattern.NodeTest;
5 import net.sf.saxon.pattern.NoNodeTest;
6 import net.sf.saxon.trans.XPathException;
7 import net.sf.saxon.type.*;
8 import net.sf.saxon.value.AtomicValue;
9 import net.sf.saxon.value.Cardinality;
10 import net.sf.saxon.value.Value;
11
12 /**
13 * An Atomizer is an expression corresponding essentially to the fn:data() function: it
14 * maps a sequence by replacing nodes with their typed values
15 */

16
17 public final class Atomizer extends UnaryExpression {
18
19     private boolean untyped; //set to true if it is known that the nodes being atomized will be untyped
20

21     /**
22     * Constructor
23      * @param sequence the sequence to be atomized
24      * @param config the Configuration. Used only for optimization, may be null. Atomization is faster if
25      * it is known in advance that all nodes will be untyped.
26     */

27
28     public Atomizer(Expression sequence, Configuration config) {
29         super(sequence);
30
31         if (config == null) {
32             untyped = false;
33         } else {
34             untyped = config.areAllNodesUntyped();
35         }
36     }
37
38     /**
39     * Simplify an expression
40     */

41
42      public Expression simplify(StaticContext env) throws XPathException {
43         if (!env.getConfiguration().isSchemaAware(Configuration.XML_SCHEMA)) {
44             untyped = true;
45         };
46         operand = operand.simplify(env);
47         if (operand instanceof AtomicValue) {
48             return operand;
49         } else if (operand instanceof Value) {
50             SequenceIterator iter = operand.iterate(null);
51             while (true) {
52                 // if all items in the sequence are atomic (they generally will be, since this is
53
// done at compile time), then return the sequence
54
Item i = iter.next();
55                 if (i == null) {
56                     return operand;
57                 }
58                 if (i instanceof NodeInfo) {
59                     return this;
60                 }
61             }
62         }
63         return this;
64     }
65
66     /**
67     * Type-check the expression
68     */

69
70     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
71         if (!env.getConfiguration().isSchemaAware(Configuration.XML_SCHEMA)) {
72             untyped = true;
73         };
74         operand = operand.typeCheck(env, contextItemType);
75         resetStaticProperties();
76         if (Type.isSubType(operand.getItemType(), Type.ANY_ATOMIC_TYPE)) {
77             return operand;
78         }
79         return this;
80     }
81
82
83     /**
84      * Determine the special properties of this expression
85      * @return {@link StaticProperty#NON_CREATIVE}.
86      */

87
88     public int computeSpecialProperties() {
89         int p = super.computeSpecialProperties();
90         return p | StaticProperty.NON_CREATIVE;
91     }
92
93     /**
94     * Iterate over the sequence of values
95     */

96
97     public SequenceIterator iterate(XPathContext context) throws XPathException {
98         SequenceIterator base = operand.iterate(context);
99         if (base instanceof AtomizableIterator) {
100             ((AtomizableIterator)base).setIsAtomizing(true);
101         }
102         return AtomizingFunction.getAtomizingIterator(base);
103     }
104
105     /**
106     * Evaluate as an Item. This should only be called if the Atomizer has cardinality zero-or-one,
107     * which will only be the case if the underlying expression has cardinality zero-or-one.
108     */

109
110     public Item evaluateItem(XPathContext context) throws XPathException {
111         Item i = operand.evaluateItem(context);
112         if (i==null) {
113             return null;
114         }
115         if (i instanceof NodeInfo) {
116             SequenceIterator it = i.getTypedValue();
117             return it.next();
118         } else {
119             return i;
120         }
121     }
122
123     /**
124     * Implement the mapping function. This is stateless, so there is a singleton instance.
125     */

126
127     public static class AtomizingFunction implements MappingFunction {
128
129         /**
130          * Private constructor, ensuring that everyone uses the singleton instance
131          */

132
133         private AtomizingFunction(){};
134
135         private static final AtomizingFunction theInstance = new AtomizingFunction();
136
137         /**
138          * Get the singleton instance
139          * @return the singleton instance of this mapping function
140          */

141
142         public static AtomizingFunction getInstance() {
143             return theInstance;
144         }
145
146         public static SequenceIterator getAtomizingIterator(SequenceIterator base) {
147             return new MappingIterator(base, theInstance, null);
148         }
149
150         public Object JavaDoc map(Item item, XPathContext context) throws XPathException {
151             if (item instanceof NodeInfo) {
152                 return item.getTypedValue();
153             } else {
154                 return item;
155             }
156         }
157     }
158
159     /**
160     * Determine the data type of the items returned by the expression, if possible
161     * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER. For this class, the
162      * result is always an atomic type, but it might be more specific.
163     */

164
165     public ItemType getItemType() {
166         return getAtomizedItemType(operand, untyped);
167     }
168
169     /**
170      * Compute the type that will result from atomizing the result of a given expression
171      * @param operand the given expression
172      * @param alwaysUntyped true if it is known that nodes will always be untyped
173      * @return the item type of the result of evaluating the operand expression, after atomization
174      */

175
176     public static final ItemType getAtomizedItemType(Expression operand, boolean alwaysUntyped) {
177         ItemType in = operand.getItemType();
178         if (in instanceof AtomicType) {
179             return in;
180         }
181         if (in instanceof NodeTest) {
182
183             if (in instanceof NoNodeTest) {
184                 return in;
185             }
186             int kinds = ((NodeTest)in).getNodeKindMask();
187             if (alwaysUntyped) {
188                 // Some node-kinds always have a typed value that's a string
189

190                 if ((kinds | STRING_KINDS) == STRING_KINDS) {
191                     return Type.STRING_TYPE;
192                 }
193                 // Some node-kinds are always untyped atomic; some are untypedAtomic provided that the configuration
194
// is untyped
195

196                 if ((kinds | UNTYPED_IF_UNTYPED_KINDS) == UNTYPED_IF_UNTYPED_KINDS) {
197                     return Type.UNTYPED_ATOMIC_TYPE;
198                 }
199             } else {
200                 if ((kinds | UNTYPED_KINDS) == UNTYPED_KINDS) {
201                     return Type.UNTYPED_ATOMIC_TYPE;
202                 }
203             }
204
205             SchemaType schemaType = ((NodeTest)in).getContentType();
206             if (schemaType instanceof SimpleType) {
207                 return ((SimpleType)schemaType).getCommonAtomicType();
208             } else if (((ComplexType)schemaType).isSimpleContent()) {
209                 return ((ComplexType)schemaType).getSimpleContentType().getCommonAtomicType();
210             } else if (schemaType instanceof AnyType) {
211                 // AnyType includes AnySimpleType as a subtype, so the atomized value can be any atomic type
212
// including untypedAtomic
213
return Type.ANY_ATOMIC_TYPE;
214             } else {
215                 // if a complex type with complex content (other than AnyType) can be atomized at all,
216
// then it will return untypedAtomic values
217
return Type.UNTYPED_ATOMIC_TYPE;
218             }
219         }
220         return Type.ANY_ATOMIC_TYPE;
221     }
222
223     /**
224      * Node kinds whose typed value is always a string
225      */

226     private static final int STRING_KINDS =
227             (1<<Type.NAMESPACE) | (1<<Type.COMMENT) | (1<<Type.PROCESSING_INSTRUCTION);
228
229     /**
230      * Node kinds whose typed value is always untypedAtomic
231      */

232
233     private static final int UNTYPED_KINDS =
234             (1<<Type.TEXT) | (1<<Type.DOCUMENT);
235
236     /**
237      * Node kinds whose typed value is untypedAtomic if the configuration is untyped
238      */

239
240     private static final int UNTYPED_IF_UNTYPED_KINDS =
241             (1<<Type.TEXT) | (1<<Type.ELEMENT) | (1<<Type.DOCUMENT) | (1<<Type.ATTRIBUTE);
242
243     /**
244     * Determine the static cardinality of the expression
245     */

246
247     public int computeCardinality() {
248         if (untyped) {
249             return operand.getCardinality();
250         } else {
251             if (Cardinality.allowsMany(operand.getCardinality())) {
252                 return StaticProperty.ALLOWS_ZERO_OR_MORE;
253             }
254             ItemType in = operand.getItemType();
255             if (in instanceof AtomicType) {
256                 return operand.getCardinality();
257             }
258             if (in instanceof NodeTest) {
259                 SchemaType schemaType = ((NodeTest)in).getContentType();
260                 if (schemaType instanceof AtomicType) {
261                     // can return at most one atomic value per node
262
return operand.getCardinality();
263                 }
264             }
265             return StaticProperty.ALLOWS_ZERO_OR_MORE;
266         }
267     }
268
269     /**
270      * Give a string representation of the operator for use in diagnostics
271      * @return the operator, as a string
272      */

273
274     protected String JavaDoc displayOperator(NamePool pool) {
275         return "atomize";
276     }
277
278 }
279
280
281
282 //
283
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
284
// you may not use this file except in compliance with the License. You may obtain a copy of the
285
// License at http://www.mozilla.org/MPL/
286
//
287
// Software distributed under the License is distributed on an "AS IS" basis,
288
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
289
// See the License for the specific language governing rights and limitations under the License.
290
//
291
// The Original Code is: all this file.
292
//
293
// The Initial Developer of the Original Code is Michael H. Kay
294
//
295
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
296
//
297
// Contributor(s): none.
298
//
299
Popular Tags