All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.value.AtomicValue Maven / Gradle / Ivy

Go to download

Saxon a complete and conformant implementation of the XSLT 2.0, XQuery 1.0, and XPath 2.0 Recommendations published on 23 January 2007 by W3C

The newest version!
package net.sf.saxon.value;

import net.sf.saxon.trans.Err;
import net.sf.saxon.sort.StringCollator;
import net.sf.saxon.expr.StaticContext;
import net.sf.saxon.expr.StaticProperty;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.om.*;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.trans.NoDynamicContextException;
import net.sf.saxon.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.
 * 

* 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. *

* * @author Michael H. Kay */ public abstract class AtomicValue extends Value implements Item, GroundedValue, ConversionResult { protected AtomicType typeLabel; /** * Set the type label on this atomic value. Note that this modifies the value, so it must only called * if the caller is confident that the value is not shared. In other cases, * use {@link #copyAsSubType(net.sf.saxon.type.AtomicType)} * * @param type the type label to be set */ public void setTypeLabel(AtomicType type) { typeLabel = type; } /** * Get a Comparable value that implements the XML Schema ordering comparison semantics for this value. * An implementation must be provided for all atomic types. *

*

In the case of data types that are partially ordered, the returned Comparable extends the standard * semantics of the compareTo() method by returning the value {@link #INDETERMINATE_ORDERING} when there * is no defined order relationship between two given values. This value is also returned when two values * of different types are compared.

* * @return a Comparable that follows XML Schema comparison rules */ public abstract Comparable getSchemaComparable(); /** * 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. * *

The hashCode() method is consistent with equals().

* @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 CharSequence getStringValueCS() { return getStringValue(); } /** * 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, 0, 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 ObjectValue. * @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}, except in the case of external objects * (instances of {@link ObjectValue}, where the method may deliver a less specific type. * * @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(); /** * Determine the static cardinality * * @return code identifying the cardinality * @see net.sf.saxon.value.Cardinality */ public final int getCardinality() { return StaticProperty.EXACTLY_ONE; } /** * 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 * @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, context).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. * @param context The conversion context to be used. This is required at present only when converting to * xs:Name or similar types: it determines the NameChecker to be used. * @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, XPathContext context); /** * 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 * @param validate true if validation is required, false if the caller already knows that the * value is valid * @param context provides access to conversion context * @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, XPathContext context) { if (targetType.isPrimitiveType()) { return convertPrimitive((BuiltInAtomicType)targetType, validate, context); } else if (targetType.isAbstract()) { return new ValidationFailure("Cannot convert to an abstract type"); } else if (targetType.isExternalType()) { return new ValidationFailure("Cannot convert to an external type"); } else { BuiltInAtomicType primitiveType = (BuiltInAtomicType)targetType.getPrimitiveItemType(); ConversionResult cr = convertPrimitive(primitiveType, validate, context); if (cr instanceof ValidationFailure) { return cr; } CharSequence lexicalValue; if (primitiveType.getFingerprint() == StandardNames.XS_STRING) { int whitespaceAction = targetType.getWhitespaceAction( context == null ? null : context.getConfiguration().getTypeHierarchy()); CharSequence cs = Whitespace.applyWhitespaceNormalization( whitespaceAction, ((StringValue)cr).getStringValueCS()); cr = new StringValue(cs); lexicalValue = cs; } else { lexicalValue = getCanonicalLexicalRepresentation(); } ValidationFailure vf = targetType.validate((AtomicValue)cr, lexicalValue, (context == null ? Name10Checker.getInstance() : context.getConfiguration().getNameChecker())); if (vf != null) { return vf; } return ((AtomicValue)cr).copyAsSubType(targetType); } } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. * @return the copied value */ public abstract AtomicValue copyAsSubType(AtomicType typeLabel); /** * Test whether the value is the double/float value NaN * @return true if the value is float NaN or double 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 abstract String getStringValue(); /** * Get the typed value of this item * * @return the typed value of the expression (which is this value) */ public final SequenceIterator getTypedValue() { return SingletonIterator.makeIterator(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 net.sf.saxon.functions.Component}, for example {@link net.sf.saxon.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 net.sf.saxon.trans.XPathException * if the expression doesn't match the required content type */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { if (whole) { SimpleType stype = null; if (parentType instanceof SimpleType) { stype = (SimpleType)parentType; } else if (parentType instanceof ComplexType && ((ComplexType)parentType).isSimpleContent()) { stype = ((ComplexType)parentType).getSimpleContentType(); } if (stype != null && !stype.isNamespaceSensitive()) { // Can't validate namespace-sensitive content statically ValidationFailure err = stype.validateContent( getStringValueCS(), null, env.getConfiguration().getNameChecker()); if (err != null) { throw err.makeException(); } return; } } if (parentType instanceof ComplexType && !((ComplexType)parentType).isSimpleContent() && !((ComplexType)parentType).isMixedContent() && !Whitespace.isWhite(getStringValueCS())) { XPathException err = new XPathException("Complex type " + parentType.getDescription() + " does not allow text content " + Err.wrap(getStringValueCS())); err.setIsTypeError(true); throw err; } } /** * 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. *

*

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.

* * @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() + "\")"; } /** * Convert to Java object (for passing to external functions) * * @param target the required target class * @param context the XPath dynamic evaluation context * @return the (boxed) Java object that best represents the XPath value */ // public final Object convertToJava(Class target, XPathContext context) throws XPathException { // return convertAtomicToJava(target, context); // } /** * Convert an atomic value to a Java object. Abstract method implemented by all subclasses * @param target the required target class * @param context the XPath dynamic evaluation context * @return the (boxed) Java object that best represents the XPath value */ //public abstract Object convertAtomicToJava(Class target, XPathContext context) throws XPathException; // TODO: delete this method and its implementations } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //




© 2015 - 2024 Weber Informatics LLC | Privacy Policy