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.trans.DynamicError; 5 import net.sf.saxon.trans.StaticError; 6 import net.sf.saxon.trans.XPathException; 7 import net.sf.saxon.type.AtomicType; 8 import net.sf.saxon.type.ItemType; 9 import net.sf.saxon.type.Type; 10 import net.sf.saxon.type.BuiltInAtomicType; 11 import net.sf.saxon.value.*; 12 13 18 19 public final class CastExpression extends UnaryExpression { 20 21 private AtomicType targetType; 22 private AtomicType targetPrimitiveType; 23 private boolean allowEmpty = false; 24 private boolean derived = false; 25 26 27 28 public CastExpression(Expression source, AtomicType target, boolean allowEmpty) { 29 super(source); 30 this.allowEmpty = allowEmpty; 31 targetType = target; 32 targetPrimitiveType = (AtomicType)target.getPrimitiveItemType(); 33 derived = (targetType.getFingerprint() != targetPrimitiveType.getFingerprint()); 34 adoptChildExpression(source); 35 } 36 37 40 41 public AtomicValue doQNameCast(StaticContext env) throws XPathException { 42 if (!(operand instanceof StringValue)) { 43 throw new StaticError("The argument of a QName or NOTATION constructor must be a string literal"); 44 } 45 return QNameValue.castToQName((StringValue)operand, targetType, env); 46 } 47 48 49 53 54 public Expression simplify(StaticContext env) throws XPathException { 55 if ((targetType instanceof BuiltInAtomicType) && !env.isAllowedBuiltInType(targetType)) { 56 env.issueWarning("The type " + targetType.getDisplayName() + " is not recognized by a Basic XSLT Processor. " + 59 "Saxon permits it for the time being.", this); 60 } 61 operand = operand.simplify(env); 62 if (operand instanceof AtomicValue) { 63 return typeCheck(env, Type.ITEM_TYPE); 64 } 65 return this; 66 } 67 68 71 72 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 73 operand = operand.typeCheck(env, contextItemType); 74 SequenceType atomicType = SequenceType.makeSequenceType(Type.ANY_ATOMIC_TYPE, getCardinality()); 75 76 RoleLocator role = new RoleLocator(RoleLocator.TYPE_OP, "cast as", 0, null); 77 role.setSourceLocator(this); 78 operand = TypeChecker.staticTypeCheck(operand, atomicType, false, role, env); 79 80 if (Type.isSubType(operand.getItemType(), targetType)) { 81 return operand; 82 } 86 if (targetType.isNamespaceSensitive()) { 87 return new CastAsQName(operand, targetType).analyze(env, contextItemType); 88 } 89 if (operand instanceof AtomicValue) { 90 return (AtomicValue)evaluateItem(null); 91 } 92 return this; 94 } 95 96 97 100 101 public int computeCardinality() { 102 return (allowEmpty ? StaticProperty.ALLOWS_ZERO_OR_ONE : StaticProperty.EXACTLY_ONE); 103 } 104 105 108 109 public ItemType getItemType() { 110 return targetType; 111 } 112 113 117 118 public int computeSpecialProperties() { 119 int p = super.computeSpecialProperties(); 120 return p | StaticProperty.NON_CREATIVE; 121 } 122 123 126 127 public Item evaluateItem(XPathContext context) throws XPathException { 128 AtomicValue value = (AtomicValue)operand.evaluateItem(context); 129 if (value==null) { 130 if (allowEmpty) { 131 return null; 132 } else { 133 DynamicError e = new DynamicError("Cast does not allow an empty sequence"); 134 e.setXPathContext(context); 135 throw e; 136 } 137 } 138 AtomicValue result = value.convert(targetPrimitiveType, context, true); 139 if (result instanceof ValidationErrorValue) { 140 XPathException err = ((ValidationErrorValue)result).getException(); 141 String code = err.getErrorCodeLocalPart(); 142 dynamicError(err.getMessage(), code, context); 143 } 144 if (derived) { 145 result = result.convert(targetType, context, true); 146 if (result instanceof ValidationErrorValue) { 147 XPathException err = ((ValidationErrorValue)result).getException(); 148 String code = err.getErrorCodeLocalPart(); 149 dynamicError(err.getMessage(), code, context); 150 } 151 } 152 return result; 153 } 154 155 158 159 public boolean equals(Object other) { 160 return super.equals(other) && 161 targetType == ((CastExpression)other).targetType && 162 allowEmpty == ((CastExpression)other).allowEmpty; 163 } 164 165 169 170 protected String displayOperator(NamePool pool) { 171 return "cast as " + targetType.toString(pool); 172 } 173 } 174 175 | Popular Tags |