KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.expr;
2 import net.sf.saxon.om.Item;
3 import net.sf.saxon.om.NamePool;
4 import net.sf.saxon.om.NodeInfo;
5 import net.sf.saxon.om.SequenceIterator;
6 import net.sf.saxon.pattern.NoNodeTest;
7 import net.sf.saxon.pattern.NodeTest;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.type.*;
10 import net.sf.saxon.value.AtomicValue;
11 import net.sf.saxon.value.EmptySequence;
12 import net.sf.saxon.value.Value;
13
14 /**
15 * A SingletonAtomizer combines the functions of an Atomizer and a CardinalityChecker: it is used to
16  * atomize a sequence of nodes, checking that the result of the atomization contains zero or one atomic
17  * values. Note that the input may be a sequence of nodes or atomic values, even though the result must
18  * contain at most one atomic value.
19 */

20
21 public final class SingletonAtomizer extends UnaryExpression {
22
23     private boolean allowEmpty;
24     private RoleLocator role;
25
26     /**
27     * Constructor
28      * @param sequence the sequence to be atomized
29      * @param allowEmpty true if the result sequence is allowed to be empty.
30     */

31
32     public SingletonAtomizer(Expression sequence, RoleLocator role, boolean allowEmpty) {
33         super(sequence);
34         this.allowEmpty = allowEmpty;
35         this.role = role;
36     }
37
38     /**
39     * Simplify an expression
40     */

41
42      public Expression simplify(StaticContext env) throws XPathException {
43         operand = operand.simplify(env);
44         if (operand instanceof AtomicValue) {
45             return operand;
46         }
47         return this;
48     }
49
50     /**
51     * Type-check the expression
52     */

53
54     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
55         operand = operand.typeCheck(env, contextItemType);
56         resetStaticProperties();
57         if (operand instanceof EmptySequence) {
58             if(!allowEmpty) {
59                 typeError("An empty sequence is not allowed as the " +
60                              role.getMessage(), role.getErrorCode(), null);
61             }
62             return operand;
63         }
64         if (Type.isSubType(operand.getItemType(), Type.ANY_ATOMIC_TYPE)) {
65             return operand;
66         }
67         return this;
68     }
69
70
71     /**
72      * Determine the special properties of this expression
73      * @return {@link StaticProperty#NON_CREATIVE}.
74      */

75
76     public int computeSpecialProperties() {
77         int p = super.computeSpecialProperties();
78         return p | StaticProperty.NON_CREATIVE;
79     }
80
81     /**
82     * Evaluate as an Item. This should only be called if the Atomizer has cardinality zero-or-one,
83     * which will only be the case if the underlying expression has cardinality zero-or-one.
84     */

85
86     public Item evaluateItem(XPathContext context) throws XPathException {
87         int found = 0;
88         Item result = null;
89         SequenceIterator iter = operand.iterate(context);
90         while (true) {
91             Item item = iter.next();
92             if (item == null) {
93                 break;
94             }
95             if (item instanceof AtomicValue) {
96                 if (found++ > 0) {
97                     typeError(
98                         "A sequence of more than one item is not allowed as the " +
99                         role.getMessage(), role.getErrorCode(), context);
100                 }
101                 result = item;
102             } else {
103                 Value value = ((NodeInfo)item).atomize();
104                 found += value.getLength();
105                 if (found > 1) {
106                      typeError(
107                         "A sequence of more than one item is not allowed as the " +
108                         role.getMessage(), role.getErrorCode(), context);
109                 }
110                 result = value.itemAt(0);
111             }
112         }
113         if (found == 0 && !allowEmpty) {
114             typeError("An empty sequence is not allowed as the " +
115                              role.getMessage(), role.getErrorCode(), null);
116         }
117         return result;
118     }
119
120     /**
121     * Determine the data type of the items returned by the expression, if possible
122     * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER. For this class, the
123      * result is always an atomic type, but it might be more specific.
124     */

125
126     public ItemType getItemType() {
127         ItemType in = operand.getItemType();
128         if (in instanceof AtomicType) {
129             return in;
130         }
131         if (in instanceof NodeTest) {
132             // TODO: reinstate optimization in Atomizer that returns untyped if not schema-aware
133
if (in instanceof NoNodeTest) {
134                 return in;
135             }
136             int kinds = ((NodeTest)in).getNodeKindMask();
137             if ((kinds | UNTYPED_KINDS) == UNTYPED_KINDS) {
138                 return Type.UNTYPED_ATOMIC_TYPE;
139             }
140
141             SchemaType schemaType = ((NodeTest)in).getContentType();
142             if (schemaType instanceof SimpleType) {
143                 return ((SimpleType)schemaType).getCommonAtomicType();
144             } else if (((ComplexType)schemaType).isSimpleContent()) {
145                 return ((ComplexType)schemaType).getSimpleContentType().getCommonAtomicType();
146             } else if (schemaType instanceof AnyType) {
147                 // AnyType includes AnySimpleType as a subtype, so the atomized value can be any atomic type
148
// including untypedAtomic
149
return Type.ANY_ATOMIC_TYPE;
150             } else {
151                 // if a complex type with complex content (other than AnyType) can be atomized at all,
152
// then it will return untypedAtomic values
153
return Type.UNTYPED_ATOMIC_TYPE;
154             }
155         }
156         return Type.ANY_ATOMIC_TYPE;
157     }
158
159     /**
160      * Node kinds whose typed value is always a string
161      */

162     private static final int STRING_KINDS =
163             (1<<Type.NAMESPACE) | (1<<Type.COMMENT) | (1<<Type.PROCESSING_INSTRUCTION);
164
165     /**
166      * Node kinds whose typed value is always untypedAtomic
167      */

168
169     private static final int UNTYPED_KINDS =
170             (1<<Type.TEXT) | (1<<Type.DOCUMENT);
171
172     /**
173      * Node kinds whose typed value is untypedAtomic if the configuration is untyped
174      */

175
176     private static final int UNTYPED_IF_UNTYPED_KINDS =
177             (1<<Type.TEXT) | (1<<Type.ELEMENT) | (1<<Type.DOCUMENT) | (1<<Type.ATTRIBUTE);
178
179     /**
180     * Determine the static cardinality of the expression
181     */

182
183     public int computeCardinality() {
184         if (allowEmpty) {
185             return StaticProperty.ALLOWS_ZERO_OR_ONE;
186         } else {
187             return StaticProperty.EXACTLY_ONE;
188         }
189     }
190
191     /**
192      * Give a string representation of the operator for use in diagnostics
193      * @return the operator, as a string
194      */

195
196     protected String JavaDoc displayOperator(NamePool pool) {
197         return "atomize singleton";
198     }
199
200 }
201
202
203
204 //
205
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
206
// you may not use this file except in compliance with the License. You may obtain a copy of the
207
// License at http://www.mozilla.org/MPL/
208
//
209
// Software distributed under the License is distributed on an "AS IS" basis,
210
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
211
// See the License for the specific language governing rights and limitations under the License.
212
//
213
// The Original Code is: all this file.
214
//
215
// The Initial Developer of the Original Code is Michael H. Kay
216
//
217
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
218
//
219
// Contributor(s): none.
220
//
221
Popular Tags