001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.om.Item;
004: import net.sf.saxon.om.NamePool;
005: import net.sf.saxon.om.SequenceIterator;
006: import net.sf.saxon.pattern.NodeTest;
007: import net.sf.saxon.trans.XPathException;
008: import net.sf.saxon.type.*;
009: import net.sf.saxon.value.*;
010:
011: /**
012: * An UntypedAtomicConverter is an expression that converts any untypedAtomic items in
013: * a sequence to a specified type
014: */
015:
016: public final class UntypedAtomicConverter extends UnaryExpression
017: implements MappingFunction {
018:
019: private AtomicType requiredItemType;
020: private boolean allConverted;
021:
022: /**
023: * Constructor
024: * @param sequence this must be a sequence of atomic values. This is not checked; a ClassCastException
025: * will occur if the precondition is not satisfied.
026: * @param requiredItemType the item type to which untypedAtomic items in the sequence should be converted,
027: * using the rules for "cast as".
028: * @param allConverted true if the result of this expression is a sequence in which all items
029: * belong to the required type
030: */
031:
032: public UntypedAtomicConverter(Expression sequence,
033: AtomicType requiredItemType, boolean allConverted) {
034: super (sequence);
035: this .requiredItemType = requiredItemType;
036: this .allConverted = allConverted;
037: ExpressionTool.copyLocationInfo(sequence, this );
038: }
039:
040: /**
041: * Determine the data type of the items returned by the expression
042: * @param th
043: */
044:
045: public ItemType getItemType(TypeHierarchy th) {
046: if (allConverted) {
047: return requiredItemType;
048: } else {
049: return Type.getCommonSuperType(requiredItemType, operand
050: .getItemType(th), th);
051: }
052: }
053:
054: /**
055: * Type-check the expression
056: */
057:
058: public Expression typeCheck(StaticContext env,
059: ItemType contextItemType) throws XPathException {
060: operand = operand.typeCheck(env, contextItemType);
061: if (operand instanceof Value) {
062: return SequenceExtent.makeSequenceExtent(
063: iterate(env.makeEarlyEvaluationContext()))
064: .simplify(env);
065: }
066: final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
067: ItemType type = operand.getItemType(th);
068: if (type instanceof NodeTest) {
069: return this ;
070: }
071: if (type == Type.ANY_ATOMIC_TYPE || type instanceof AnyItemType
072: || type == Type.UNTYPED_ATOMIC_TYPE) {
073: return this ;
074: }
075: // the sequence can't contain any untyped atomic values, so there's no need for
076: // a converter
077: return operand;
078: }
079:
080: /**
081: * Determine the special properties of this expression
082: * @return {@link StaticProperty#NON_CREATIVE}.
083: */
084:
085: public int computeSpecialProperties() {
086: int p = super .computeSpecialProperties();
087: return p | StaticProperty.NON_CREATIVE;
088: }
089:
090: /**
091: * Iterate over the sequence of values
092: */
093:
094: public SequenceIterator iterate(XPathContext context)
095: throws XPathException {
096: SequenceIterator base = operand.iterate(context);
097: return new MappingIterator(base, this , context);
098: }
099:
100: /**
101: * Evaluate as an Item. This should only be called if the UntypedAtomicConverter has cardinality zero-or-one
102: */
103:
104: public Item evaluateItem(XPathContext context)
105: throws XPathException {
106: Item item = operand.evaluateItem(context);
107: if (item == null)
108: return null;
109: if (item instanceof UntypedAtomicValue) {
110: try {
111: AtomicValue val = ((UntypedAtomicValue) item).convert(
112: requiredItemType, context, true);
113: if (val instanceof ValidationErrorValue) {
114: throw ((ValidationErrorValue) val).getException();
115: }
116: return val;
117: } catch (XPathException e) {
118: if (e.getLocator() == null) {
119: e.setLocator(this );
120: }
121: throw e;
122: }
123: } else {
124: //testConformance(item, context);
125: return item;
126: }
127: }
128:
129: /**
130: * Implement the mapping function
131: */
132:
133: public Object map(Item item, XPathContext context)
134: throws XPathException {
135: if (item instanceof UntypedAtomicValue) {
136: Value val = ((UntypedAtomicValue) item).convert(
137: requiredItemType, context, true);
138: if (val instanceof ValidationErrorValue) {
139: throw ((ValidationErrorValue) val).getException();
140: }
141: return val;
142: } else {
143: return item;
144: }
145: }
146:
147: /**
148: * Give a string representation of the operator for use in diagnostics
149: * @return the operator, as a string
150: */
151:
152: protected String displayOperator(NamePool pool) {
153: return "convert untyped atomic items to "
154: + requiredItemType.toString(pool);
155: }
156:
157: }
158:
159: //
160: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
161: // you may not use this file except in compliance with the License. You may obtain a copy of the
162: // License at http://www.mozilla.org/MPL/
163: //
164: // Software distributed under the License is distributed on an "AS IS" basis,
165: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
166: // See the License for the specific language governing rights and limitations under the License.
167: //
168: // The Original Code is: all this file.
169: //
170: // The Initial Developer of the Original Code is Michael H. Kay
171: //
172: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
173: //
174: // Contributor(s): none.
175: //
|