package client.net.sf.saxon.ce.value; import client.net.sf.saxon.ce.expr.StaticContext; import client.net.sf.saxon.ce.expr.XPathContext; import client.net.sf.saxon.ce.lib.StringCollator; import client.net.sf.saxon.ce.om.*; import client.net.sf.saxon.ce.trans.NoDynamicContextException; import client.net.sf.saxon.ce.trans.XPathException; import client.net.sf.saxon.ce.tree.iter.SingletonIterator; import client.net.sf.saxon.ce.type.*; /** * The AtomicValue class corresponds to the concept of an atomic value in the * XPath 2.0 data model. Atomic values belong to one of the 19 primitive types * defined in XML Schema; or they are of type xs:untypedAtomic; or they are * "external objects", representing a Saxon extension to the XPath 2.0 type system. * <p/> * The AtomicValue class contains some methods that are suitable for applications * to use, and many others that are designed for internal use by Saxon itself. * These have not been fully classified. At present, therefore, none of the methods on this * class should be considered to be part of the public Saxon API. * <p/> * * @author Michael H. Kay */ public abstract class AtomicValue extends Value implements Item, GroundedValue, ConversionResult { protected AtomicType typeLabel; /** * Get an object value that implements the XPath equality and ordering comparison semantics for this value. * If the ordered parameter is set to true, the result will be a Comparable and will support a compareTo() * method with the semantics of the XPath lt/gt operator, provided that the other operand is also obtained * using the getXPathComparable() method. In all cases the result will support equals() and hashCode() methods * that support the semantics of the XPath eq operator, again provided that the other operand is also obtained * using the getXPathComparable() method. A context argument is supplied for use in cases where the comparison * semantics are context-sensitive, for example where they depend on the implicit timezone or the default * collation. * @param ordered true if an ordered comparison is required. In this case the result is null if the * type is unordered; in other cases the returned value will be a Comparable. * @param collator the collation to be used when comparing strings * @param context the XPath dynamic evaluation context, used in cases where the comparison is context * sensitive * @return an Object whose equals() and hashCode() methods implement the XPath comparison semantics * with respect to this atomic value. If ordered is specified, the result will either be null if * no ordering is defined, or will be a Comparable * @throws NoDynamicContextException if the comparison depends on dynamic context information that * is not available, for example implicit timezone */ public abstract Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) throws NoDynamicContextException; /** * The equals() methods on atomic values is defined to follow the semantics of eq when applied * to two atomic values. When the other operand is not an atomic value, the result is undefined * (may be false, may be an exception). When the other operand is an atomic value that cannot be * compared with this one, the method must throw a ClassCastException. * * <p>The hashCode() method is consistent with equals().</p> * @param o the other value * @return true if the other operand is an atomic value and the two values are equal as defined * by the XPath eq operator */ public abstract boolean equals(Object o); /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public final CharSequence getStringValueCS() { return getPrimitiveStringValue(); } /** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { context.getReceiver().append(this, NodeInfo.ALL_NAMESPACES); } /** * Get the n'th item in the sequence (starting from 0). This is defined for all * Values, but its real benefits come for a sequence Value stored extensionally * (or for a MemoClosure, once all the values have been read) * * @param n position of the required item, counting from zero. * @return the n'th item in the sequence, where the first item in the sequence is * numbered zero. If n is negative or >= the length of the sequence, returns null. */ public final Item itemAt(int n) { return (n == 0 ? this : null); } /** * Determine the data type of the items in the expression, if possible * * @param th The TypeHierarchy. Can be null if the target is an AtomicValue, * except in the case where it is an external JSObjectValue. * @return for the default implementation: AnyItemType (not known) */ public ItemType getItemType(TypeHierarchy th) { return typeLabel; } /** * Determine the data type of the value. This * delivers the same answer as {@link #getItemType} * * @return for the default implementation: AnyItemType (not known) */ public AtomicType getTypeLabel() { return typeLabel; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is xs:anyAtomicType. * * @return the primitive type */ public abstract BuiltInAtomicType getPrimitiveType(); /** * Convert the value to a given type. The result of the conversion will be an * atomic value of the required type. This method works only where the target * type is a built-in type. * * @param schemaType the required atomic type. This must not be a namespace-sensitive type such as * QName or NOTATION * @param context the XPath dynamic context * @return the result of the conversion, if conversion was possible. This * will always be an instance of the class corresponding to the type * of value requested * @throws XPathException if conversion is not allowed for this * required type, or if the particular value cannot be converted */ public final AtomicValue convert(AtomicType schemaType, XPathContext context) throws XPathException { // Note this method is used from XQuery compiled code return convert(schemaType, true).asAtomic(); } /** * Convert a value to either (a) another primitive type, or (b) another built-in type derived * from the current primitive type, with control over how validation is * handled. * * @param requiredType the required atomic type. This must either be a primitive type, or a built-in * type derived from the same primitive type as this atomic value. * @param validate true if validation is required. If set to false, the caller guarantees that * the value is valid for the target data type, and that further validation * is therefore not required. * Note that a validation failure may be reported even if validation was not requested. * @return the result of the conversion, if successful. If unsuccessful, the value returned * will be a ValidationFailure. The caller must check for this condition. No exception is thrown, instead * the exception information will be encapsulated within the ValidationFailure. */ protected abstract ConversionResult convertPrimitive( BuiltInAtomicType requiredType, boolean validate); /** * Convert the value to a given type. The result of the conversion will be * an atomic value of the required type. This method works where the target * type is a built-in atomic type and also where it is a user-defined atomic * type. * * @param targetType the type to which the value is to be converted. This must not be a namespace-sensitive type * such as QName or NOTATION. * @param validate true if validation is required, false if the caller already knows that the * value is valid * @return the value after conversion if successful; or a {@link ValidationFailure} if conversion failed. The * caller must check for this condition. Validation may fail even if validation was not requested. */ public final ConversionResult convert(AtomicType targetType, boolean validate) { return convertPrimitive((BuiltInAtomicType)targetType, validate); } /** * Test whether the value is the special value NaN * @return true if the value is float NaN or double NaN or precisionDecimal NaN; otherwise false */ public boolean isNaN() { return false; } /** * Get the length of the sequence * * @return always 1 for an atomic value */ public final int getLength() { return 1; } /** * Iterate over the (single) item in the sequence * * @return a SequenceIterator that iterates over the single item in this * value */ public final SequenceIterator iterate() { return SingletonIterator.makeIterator(this); } /** * Convert the value to a string, using the serialization rules. * For atomic values this is the same as a cast; for sequence values * it gives a space-separated list. This method is refined for AtomicValues * so that it never throws an Exception. */ public final String getStringValue() { return getStringValueCS().toString(); } /** * Convert the value to a string, using the serialization rules for the primitive type. * @return the value converted to a string according to the rules for the primitive type */ protected abstract CharSequence getPrimitiveStringValue(); /** * Get the typed value of this item * * @return the typed value of the expression (which is this value) */ public final AtomicValue getTypedValue() { return this; } /** * Get the effective boolean value of the value * * @return true, unless the value is boolean false, numeric zero, or * zero-length string */ public boolean effectiveBooleanValue() throws XPathException { XPathException err = new XPathException("Effective boolean value is not defined for an atomic value of type " + Type.displayTypeName(this)); err.setIsTypeError(true); err.setErrorCode("FORG0006"); throw err; // unless otherwise specified in a subclass } /** * Method to extract components of a value. Implemented by some subclasses, * but defined at this level for convenience * * @param component identifies the required component, as a constant defined in class * {@link client.net.sf.saxon.ce.functions.Component}, for example {@link client.net.sf.saxon.ce.functions.Component#HOURS} * @return the value of the requested component of this value */ public AtomicValue getComponent(int component) throws XPathException { throw new UnsupportedOperationException("Data type does not support component extraction"); } /** * Check statically that the results of the expression are capable of constructing the content * of a given schema type. * * @param parentType The schema type * @param env the static context * @param whole true if this atomic value accounts for the entire content of the containing node * @throws client.net.sf.saxon.ce.trans.XPathException * if the expression doesn't match the required content type */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { // } /** * Calling this method on a ConversionResult returns the AtomicValue that results * from the conversion if the conversion was successful, and throws a ValidationException * explaining the conversion error otherwise. * <p/> * <p>Use this method if you are calling a conversion method that returns a ConversionResult, * and if you want to throw an exception if the conversion fails.</p> * * @return the atomic value that results from the conversion if the conversion was successful */ public AtomicValue asAtomic() { return this; } /** * Get a subsequence of the value * * @param start the index of the first item to be included in the result, counting from zero. * A negative value is taken as zero. If the value is beyond the end of the sequence, an empty * sequence is returned * @param length the number of items to be included in the result. Specify Integer.MAX_VALUE to * get the subsequence up to the end of the base sequence. If the value is negative, an empty sequence * is returned. If the value goes off the end of the sequence, the result returns items up to the end * of the sequence * @return the required subsequence. If min is */ public GroundedValue subsequence(int start, int length) { if (start <= 0 && start + length > 0) { return this; } else { return EmptySequence.getInstance(); } } /** * Get string value. In general toString() for an atomic value displays the value as it would be * written in XPath: that is, as a literal if available, or as a call on a constructor function * otherwise. */ public String toString() { return typeLabel.toString() + " (\"" + getStringValueCS() + "\")"; } } // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.