package client.net.sf.saxon.ce.value;
import client.net.sf.saxon.ce.event.SequenceReceiver;
import client.net.sf.saxon.ce.expr.ExpressionTool;
import client.net.sf.saxon.ce.expr.StaticContext;
import client.net.sf.saxon.ce.expr.XPathContext;
import client.net.sf.saxon.ce.functions.Count;
import client.net.sf.saxon.ce.om.Item;
import client.net.sf.saxon.ce.om.NodeInfo;
import client.net.sf.saxon.ce.om.SequenceIterator;
import client.net.sf.saxon.ce.om.ValueRepresentation;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.tree.iter.EmptyIterator;
import client.net.sf.saxon.ce.tree.iter.SingletonIterator;
import client.net.sf.saxon.ce.tree.util.FastStringBuffer;
import client.net.sf.saxon.ce.type.AnyItemType;
import client.net.sf.saxon.ce.type.ItemType;
import client.net.sf.saxon.ce.type.SchemaType;
import client.net.sf.saxon.ce.type.TypeHierarchy;
/**
* A value is the result of an expression but it is also an expression in its own right.
* Note that every value can be regarded as a sequence - in many cases, a sequence of
* length one.
*/
public abstract class Value
implements ValueRepresentation {
/**
* Static method to make a Value from a given Item (which may be either an AtomicValue
* or a NodeInfo or a FunctionItem
* @param val The supplied value, or null, indicating the empty sequence.
* @return The supplied value, if it is a value, or a SingletonNode that
* wraps the item, if it is a node. If the supplied value was null,
* return an EmptySequence
*/
public static Value asValue(ValueRepresentation val) {
if (val instanceof Value) {
return (Value)val;
} else if (val == null) {
return EmptySequence.getInstance();
} else {
return new SingletonItem((Item)val);
}
}
/**
* Static method to make an Item from a Value
* @param value the value to be converted
* @return null if the value is an empty sequence; or the only item in the value
* if it is a singleton sequence
* @throws XPathException if the Value contains multiple items
*/
public static Item asItem(ValueRepresentation value) throws XPathException {
if (value instanceof Item) {
return (Item)value;
} else {
return ((Value)value).asItem();
}
}
/**
* Return the value in the form of an Item
* @return the value in the form of an Item
*/
public Item asItem() throws XPathException {
SequenceIterator iter = iterate();
Item item = iter.next();
if (item == null) {
return null;
} else if (iter.next() != null) {
throw new XPathException("Attempting to access a sequence as a singleton item");
} else {
return item;
}
}
/**
* Static method to get an Iterator over any ValueRepresentation (which may be either a Value
* or a NodeInfo or a FunctionItem
* @param val The supplied value, or null, indicating the empty sequence.
* @return The supplied value, if it is a value, or a SingletonNode that
* wraps the item, if it is a node. If the supplied value was null,
* return an EmptySequence
*/
public static SequenceIterator asIterator(ValueRepresentation val) throws XPathException {
if (val instanceof Value) {
return ((Value)val).iterate();
} else if (val == null) {
return EmptyIterator.getInstance();
} else {
return SingletonIterator.makeIterator((Item)val);
}
}
/**
* Get a SequenceIterator over a ValueRepresentation
* @param val the value to iterate over
* @return the iterator
*/
public static SequenceIterator getIterator(ValueRepresentation val) throws XPathException {
if (val instanceof Value) {
return ((Value)val).iterate();
} else if (val instanceof Item) {
return SingletonIterator.makeIterator((Item)val);
} else if (val == null) {
throw new AssertionError("Value of variable is undefined (null)");
} else {
throw new AssertionError("Unknown value representation " + val.getClass());
}
}
/**
* Iterate over the items contained in this value.
* @return an iterator over the sequence of items
* @throws XPathException if a dynamic error occurs. This is possible only in the case of values
* that are materialized lazily, that is, where the iterate() method leads to computation of an
* expression that delivers the values.
*/
public abstract SequenceIterator iterate() throws XPathException;
/**
* 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() throws XPathException {
return getStringValue();
}
/**
* Determine the data type of the items in the expression, if possible
* @return for the default implementation: AnyItemType (not known)
* @param th The TypeHierarchy. Can be null if the target is an AtomicValue.
*/
public ItemType getItemType(TypeHierarchy th) {
return AnyItemType.getInstance();
}
/**
* 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 Item itemAt(int n) throws XPathException {
if (n < 0) {
return null;
}
int i = 0; // indexing is zero-based
SequenceIterator iter = iterate();
while (true) {
Item item = iter.next();
if (item == null) {
return null;
}
if (i++ == n) {
return item;
}
}
}
/**
* Get the length of the sequence
* @return the number of items in the sequence
*/
public int getLength() throws XPathException {
return Count.count(iterate());
}
/**
* Process the value as an 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 {
SequenceIterator iter = iterate();
SequenceReceiver out = context.getReceiver();
while (true) {
Item it = iter.next();
if (it==null) break;
out.append(it, NodeInfo.ALL_NAMESPACES);
}
}
/**
* 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.
* @throws XPathException The method can fail if evaluation of the value
* has been deferred, and if a failure occurs during the deferred evaluation.
* No failure is possible in the case of an AtomicValue.
*/
public String getStringValue() throws XPathException {
FastStringBuffer sb = new FastStringBuffer(FastStringBuffer.SMALL);
SequenceIterator iter = iterate();
Item item = iter.next();
if (item != null) {
while (true) {
sb.append(item.getStringValueCS());
item = iter.next();
if (item == null) {
break;
}
sb.append(' ');
}
}
return sb.toString();
}
/**
* Get the effective boolean value of the expression. This returns false if the value
* is the empty sequence, a zero-length string, a number equal to zero, or the boolean
* false. Otherwise it returns true.
*
* @exception XPathException if any dynamic error occurs evaluating the
* expression
* @return the effective boolean value
*/
public boolean effectiveBooleanValue() throws XPathException {
return ExpressionTool.effectiveBooleanValue(iterate());
}
/**
* Constant returned by compareTo() method to indicate an indeterminate ordering between two values
*/
public static final int INDETERMINATE_ORDERING = Integer.MIN_VALUE;
/**
* Compare two (sequence) values for equality. This method throws an UnsupportedOperationException,
* because it should not be used: there are too many "equality" operators that can be defined on
* values for the concept to be meaningful.
* <p>Consider creating an XPathComparable from each value, and comparing those; or creating a
* SchemaComparable to achieve equality comparison as defined in XML Schema.</p>
* @throws UnsupportedOperationException (always)
*/
public boolean equals(Object obj) {
throw new UnsupportedOperationException("Value.equals()");
}
public int hashCode() {
return 42;
}
/**
* 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 value accounts for the entire content of the containing node
* @throws XPathException if the expression doesn't match the required content type
*/
public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException {
//return;
}
/**
* Reduce a value to its simplest form. If the value is a closure or some other form of deferred value
* such as a FunctionCallPackage, then it is reduced to a SequenceExtent. If it is a SequenceExtent containing
* a single item, then it is reduced to that item. One consequence that is exploited by class FilterExpression
* is that if the value is a singleton numeric value, then the result will be an instance of NumericValue
* @return the value in simplified form
*/
public Value reduce() throws XPathException {
return this;
}
}
// 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.