001: package net.sf.saxon.value;
002:
003: import net.sf.saxon.Err;
004: import net.sf.saxon.expr.ExpressionTool;
005: import net.sf.saxon.expr.StaticContext;
006: import net.sf.saxon.expr.StaticProperty;
007: import net.sf.saxon.expr.XPathContext;
008: import net.sf.saxon.om.*;
009: import net.sf.saxon.trans.StaticError;
010: import net.sf.saxon.trans.XPathException;
011: import net.sf.saxon.trans.DynamicError;
012: import net.sf.saxon.type.*;
013:
014: import java.io.PrintStream;
015:
016: /**
017: * The AtomicValue class corresponds to the concept of an atomic value in the
018: * XPath 2.0 data model. Atomic values belong to one of the 19 primitive types
019: * defined in XML Schema; or they are of type xdt:untypedAtomic; or they are
020: * "external objects", representing a Saxon extension to the XPath 2.0 type system.
021: * <p>
022: * The AtomicValue class contains some methods that are suitable for applications
023: * to use, and many others that are designed for internal use by Saxon itself.
024: * These have not been fully classified. At present, therefore, none of the methods on this
025: * class should be considered to be part of the public Saxon API.
026: * <p>
027: * @author Michael H. Kay
028: */
029:
030: public abstract class AtomicValue extends Value implements Item {
031:
032: /**
033: * Test whether the type of this atomic value is a built-in type.
034: * Default implementation returns true.
035: */
036:
037: public boolean hasBuiltInType() {
038: return true;
039: }
040:
041: /**
042: * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
043: * This method indicates which of these methods is prefered.
044: */
045:
046: public int getImplementationMethod() {
047: return EVALUATE_METHOD;
048: }
049:
050: /**
051: * Process the instruction, without returning any tail calls
052: *
053: * @param context The dynamic context, giving access to the current node,
054: * the current variables, etc.
055: */
056:
057: public void process(XPathContext context) throws XPathException {
058: Item item = evaluateItem(context);
059: if (item != null) {
060: context.getReceiver().append(item, 0,
061: NodeInfo.ALL_NAMESPACES);
062: }
063: }
064:
065: /**
066: * Determine the static cardinality
067: *
068: * @return code identifying the cardinality
069: * @see net.sf.saxon.value.Cardinality
070: */
071:
072: public final int getCardinality() {
073: return StaticProperty.EXACTLY_ONE;
074: }
075:
076: /**
077: * Convert the value to a given type. The result of the conversion will be an
078: * atomic value of the required type. This method works only where the target
079: * type is a built-in type.
080: *
081: * @param requiredType type code of the required atomic type
082: * @param context
083: * @return the result of the conversion, if conversion was possible. This
084: * will always be an instance of the class corresponding to the type
085: * of value requested
086: * @throws XPathException if conversion is not allowed for this
087: * required type, or if the particular value cannot be converted
088: */
089:
090: public final AtomicValue convert(int requiredType,
091: XPathContext context) throws XPathException {
092: SchemaType schemaType = BuiltInSchemaFactory
093: .getSchemaType(requiredType);
094: if (schemaType instanceof BuiltInAtomicType) {
095: AtomicValue val = convertPrimitive(
096: (BuiltInAtomicType) schemaType, true, context);
097: if (val instanceof ValidationErrorValue) {
098: throw ((ValidationErrorValue) val).getException();
099: }
100: return val;
101: } else {
102: throw new IllegalArgumentException(
103: "This method can only be used for conversion to a built-in atomic type");
104: }
105: };
106:
107: /**
108: * Convert a value to another primitive data type, with control over how validation is
109: * handled.
110: *
111: * @param requiredType type code of the required atomic type
112: * @param validate true if validation is required. If set to false, the caller guarantees that
113: * the value is valid for the target data type, and that further validation is therefore not required.
114: * Note that a validation failure may be reported even if validation was not requested.
115: * @param context The conversion context to be used. This is required at present only when converting to
116: * a date or time: it provides the implicit timezone.
117: * @return the result of the conversion, if successful. If unsuccessful, the value returned
118: * will be an ErrorValue. The caller must check for this condition. No exception is thrown, instead
119: * the exception will be encapsulated within the ErrorValue.
120: */
121: public abstract AtomicValue convertPrimitive(
122: BuiltInAtomicType requiredType, boolean validate,
123: XPathContext context);
124:
125: /**
126: * Convert the value to a given type. The result of the conversion will be
127: * an atomic value of the required type. This method works where the target
128: * type is a built-in atomic type and also where it is a user-defined atomic
129: * type.
130: *
131: * @param targetType the type to which the value is to be converted
132: * @param context provides access to conversion context
133: * @param validate true if validation is required, false if the caller already knows that the
134: * value is valid
135: * @return the value after conversion if successful; or a {@link ValidationErrorValue} if conversion failed. The
136: * caller must check for this condition. Validation may fail even if validation was not requested.
137: */
138:
139: public AtomicValue convert(AtomicType targetType,
140: XPathContext context, boolean validate) {
141: if (targetType instanceof BuiltInAtomicType) {
142: return convertPrimitive((BuiltInAtomicType) targetType,
143: validate, context);
144: } else {
145: CharSequence lexicalValue = getStringValueCS();
146: AtomicValue v = convertPrimitive(
147: (BuiltInAtomicType) targetType
148: .getPrimitiveItemType(), validate, context);
149: if (v instanceof ValidationErrorValue) {
150: // conversion has failed
151: return v;
152: }
153: return targetType.makeDerivedValue(v, lexicalValue,
154: validate);
155: }
156: }
157:
158: /**
159: * Get the length of the sequence
160: *
161: * @return always 1 for an atomic value
162: */
163:
164: public final int getLength() {
165: return 1;
166: }
167:
168: /**
169: * Evaluate the value (this simply returns the value unchanged)
170: *
171: * @param context the evaluation context (not used in this implementation)
172: * @return the value, unchanged
173: * @throws XPathException
174: */
175:
176: public Item evaluateItem(XPathContext context)
177: throws XPathException {
178: return this ;
179: }
180:
181: /**
182: * Iterate over the (single) item in the sequence
183: *
184: * @param context the evaluation context (not used in this implementation)
185: * @return a SequenceIterator that iterates over the single item in this
186: * value
187: */
188:
189: public final SequenceIterator iterate(XPathContext context) {
190: return SingletonIterator.makeIterator(this );
191: }
192:
193: /**
194: * Evaluate as a string
195: */
196:
197: public final String evaluateAsString(XPathContext context) {
198: return getStringValue();
199: }
200:
201: /**
202: * Convert the value to a string, using the serialization rules.
203: * For atomic values this is the same as a cast; for sequence values
204: * it gives a space-separated list. This method is refined for AtomicValues
205: * so that it never throws an Exception.
206: */
207:
208: public abstract String getStringValue();
209:
210: /**
211: * Get the value of the item as a CharSequence. This is in some cases more efficient than
212: * the version of the method that returns a String.
213: */
214:
215: public CharSequence getStringValueCS() {
216: return getStringValue();
217: }
218:
219: /**
220: * Get the typed value of this item
221: *
222: * @return the typed value of the expression (which is this value)
223: */
224:
225: public final SequenceIterator getTypedValue() {
226: return SingletonIterator.makeIterator(this );
227: }
228:
229: /**
230: * Get the primitive value (the value in the value space). This returns an
231: * AtomicValue of a class that would be used to represent the primitive value.
232: * In effect this means that for built-in types, it returns the value itself,
233: * but for user-defined type, it returns the primitive value minus the type
234: * annotation. Note that getItemType() when applied to the result of this
235: * function does not not necessarily return a primitive type: for example, this
236: * function may return a value of type xdt:dayTimeDuration, which is not a
237: * primitive type as defined by {@link net.sf.saxon.type.Type#isPrimitiveType(int)}
238: */
239:
240: public AtomicValue getPrimitiveValue() {
241: // overridden where necessary
242: return this ;
243: }
244:
245: /**
246: * Get the effective boolean value of the value
247: *
248: * @param context the evaluation context (not used in this implementation)
249: * @return true, unless the value is boolean false, numeric zero, or
250: * zero-length string
251: */
252: public boolean effectiveBooleanValue(XPathContext context)
253: throws XPathException {
254: final NamePool namePool = context.getNamePool();
255: final TypeHierarchy th = namePool.getTypeHierarchy();
256: DynamicError err = new DynamicError(
257: "Effective boolean value is not defined for an atomic value of type "
258: + (context == null ? "other than boolean, number, or string"
259: : getItemType(th).toString(namePool)));
260: err.setIsTypeError(true);
261: err.setErrorCode("FORG0006");
262: err.setXPathContext(context);
263: throw err;
264: // unless otherwise specified in a subclass
265: }
266:
267: /**
268: * Method to extract components of a value. Implemented by some subclasses,
269: * but defined at this level for convenience
270: */
271:
272: public AtomicValue getComponent(int component)
273: throws XPathException {
274: throw new UnsupportedOperationException(
275: "Data type does not support component extraction");
276: }
277:
278: /**
279: * Check statically that the results of the expression are capable of constructing the content
280: * of a given schema type.
281: *
282: * @param parentType The schema type
283: * @param env the static context
284: * @param whole true if this atomic value accounts for the entire content of the containing node
285: * @throws net.sf.saxon.trans.XPathException
286: * if the expression doesn't match the required content type
287: */
288:
289: public void checkPermittedContents(SchemaType parentType,
290: StaticContext env, boolean whole) throws XPathException {
291: if (whole) {
292: SimpleType stype = null;
293: if (parentType instanceof SimpleType) {
294: stype = (SimpleType) parentType;
295: } else if (parentType instanceof ComplexType
296: && ((ComplexType) parentType).isSimpleContent()) {
297: stype = ((ComplexType) parentType)
298: .getSimpleContentType();
299: }
300: if (stype != null && !stype.isNamespaceSensitive()) {
301: // Can't validate namespace-sensitive content statically
302: XPathException err = stype.validateContent(
303: getStringValueCS(), null, env
304: .getConfiguration().getNameChecker());
305: if (err != null) {
306: throw err;
307: }
308: return;
309: }
310: }
311: if (parentType instanceof ComplexType
312: && !((ComplexType) parentType).isSimpleContent()
313: && !((ComplexType) parentType).isMixedContent()
314: && !Whitespace.isWhite(getStringValueCS())) {
315: StaticError err = new StaticError("Complex type "
316: + parentType.getDescription()
317: + " does not allow text content "
318: + Err.wrap(getStringValueCS()));
319: err.setIsTypeError(true);
320: throw err;
321: }
322: }
323:
324: /**
325: * Get string value. In general toString() for an atomic value displays the value as it would be
326: * written in XPath: that is, as a literal if available, or as a call on a constructor function
327: * otherwise.
328: */
329:
330: public String toString() {
331: return getItemType(null).toString() + " (\""
332: + getStringValueCS() + "\")";
333: }
334:
335: /**
336: * Compare two values for equality. This supports identity constraints in XML Schema,
337: * which allow list-valued elements and attributes to participate in key and uniqueness constraints.
338: * This method returns false if any error occurs during the comparison, or if any of the items
339: * in either sequence is a node rather than an atomic value. The default implementation of
340: * schemaEquals() is the same as equals(), but subclasses can override this.
341: */
342:
343: public boolean schemaEquals(Value obj) {
344: return equals(obj);
345: }
346:
347: /**
348: * Diagnostic print of expression structure
349: *
350: * @param level the indentation level of the output
351: * @param out
352: */
353:
354: public final void display(int level, NamePool pool, PrintStream out) {
355: out.println(ExpressionTool.indent(level) + toString());
356: }
357:
358: }
359:
360: //
361: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
362: // you may not use this file except in compliance with the License. You may obtain a copy of the
363: // License at http://www.mozilla.org/MPL/
364: //
365: // Software distributed under the License is distributed on an "AS IS" basis,
366: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
367: // See the License for the specific language governing rights and limitations under the License.
368: //
369: // The Original Code is: all this file.
370: //
371: // The Initial Developer of the Original Code is Michael H. Kay.
372: //
373: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
374: //
375: // Contributor(s): none.
376: //
|