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