use of org.exist.xquery.value.NumericValue in project exist by eXist-db.
the class Predicate method selectByPosition.
/**
* @param outerSequence the outer sequence
* @param contextSequence the context sequence
* @param mode the mode
* @param innerSeq the inner sequence
*
* @return The result of the positional evaluation of the predicate.
*
* @throws XPathException if an error occurs
*/
private Sequence selectByPosition(final Sequence outerSequence, final Sequence contextSequence, final int mode, final Sequence innerSeq) throws XPathException {
if (outerSequence != null && !outerSequence.isEmpty() && Type.subTypeOf(contextSequence.getItemType(), Type.NODE) && contextSequence.isPersistentSet() && outerSequence.isPersistentSet()) {
final Sequence result = new NewArrayNodeSet();
final NodeSet contextSet = contextSequence.toNodeSet();
switch(mode) {
case Constants.CHILD_AXIS:
case Constants.ATTRIBUTE_AXIS:
case Constants.DESCENDANT_AXIS:
case Constants.DESCENDANT_SELF_AXIS:
case Constants.DESCENDANT_ATTRIBUTE_AXIS:
{
final NodeSet outerNodeSet = outerSequence.toNodeSet();
// TODO: in some cases, especially with in-memory nodes,
// outerSequence.toNodeSet() will generate a document
// which will be different from the one(s) in contextSet
// ancestors will thus be empty :-(
// A special treatment of VirtualNodeSet does not seem to be
// required anymore
final Sequence ancestors = outerNodeSet.selectAncestors(contextSet, true, getExpressionId());
if (contextSet.getDocumentSet().intersection(outerNodeSet.getDocumentSet()).getDocumentCount() == 0) {
LOG.info("contextSet and outerNodeSet don't share any document");
}
final NewArrayNodeSet temp = new NewArrayNodeSet();
for (final SequenceIterator i = ancestors.iterate(); i.hasNext(); ) {
NodeProxy p = (NodeProxy) i.nextItem();
ContextItem contextNode = p.getContext();
temp.reset();
while (contextNode != null) {
if (contextNode.getContextId() == getExpressionId()) {
temp.add(contextNode.getNode());
}
contextNode = contextNode.getNextDirect();
}
p.clearContext(getExpressionId());
// TODO : understand why we sort here...
temp.sortInDocumentOrder();
for (final SequenceIterator j = innerSeq.iterate(); j.hasNext(); ) {
final NumericValue v = (NumericValue) j.nextItem();
// Non integers return... nothing, not even an error !
if (!v.hasFractionalPart() && !v.isZero()) {
// ... whereas we don't want a sorted array here
// TODO : rename this method as getInDocumentOrder ? -pb
p = temp.get(v.getInt() - 1);
if (p != null) {
result.add(p);
}
// TODO : does null make sense here ? Well... sometimes ;-)
}
}
}
break;
}
default:
for (final SequenceIterator i = outerSequence.iterate(); i.hasNext(); ) {
NodeProxy p = (NodeProxy) i.nextItem();
Sequence temp;
boolean reverseAxis = true;
switch(mode) {
case Constants.ANCESTOR_AXIS:
temp = contextSet.selectAncestors(p, false, Expression.IGNORE_CONTEXT);
break;
case Constants.ANCESTOR_SELF_AXIS:
temp = contextSet.selectAncestors(p, true, Expression.IGNORE_CONTEXT);
break;
case Constants.PARENT_AXIS:
// TODO : understand why the contextSet is not involved
// here
// NodeProxy.getParent returns a *theoretical* parent
// which is *not* guaranteed to be in the context set !
temp = p.getParents(Expression.NO_CONTEXT_ID);
break;
case Constants.PRECEDING_AXIS:
temp = contextSet.selectPreceding(p, Expression.IGNORE_CONTEXT);
break;
case Constants.PRECEDING_SIBLING_AXIS:
temp = contextSet.selectPrecedingSiblings(p, Expression.IGNORE_CONTEXT);
break;
case Constants.FOLLOWING_SIBLING_AXIS:
temp = contextSet.selectFollowingSiblings(p, Expression.IGNORE_CONTEXT);
reverseAxis = false;
break;
case Constants.FOLLOWING_AXIS:
temp = contextSet.selectFollowing(p, Expression.IGNORE_CONTEXT);
reverseAxis = false;
break;
case Constants.SELF_AXIS:
temp = p;
reverseAxis = false;
break;
default:
throw new IllegalArgumentException("Tried to test unknown axis");
}
if (!temp.isEmpty()) {
for (final SequenceIterator j = innerSeq.iterate(); j.hasNext(); ) {
final NumericValue v = (NumericValue) j.nextItem();
// Non integers return... nothing, not even an error !
if (!v.hasFractionalPart() && !v.isZero()) {
final int pos = (reverseAxis ? temp.getItemCount() - v.getInt() : v.getInt() - 1);
// Other positions are ignored
if (pos >= 0 && pos < temp.getItemCount()) {
final NodeProxy t = (NodeProxy) temp.itemAt(pos);
// for the current context: filter out those
// context items not selected by the positional predicate
ContextItem ctx = t.getContext();
t.clearContext(Expression.IGNORE_CONTEXT);
while (ctx != null) {
if (ctx.getContextId() == outerContextId) {
if (ctx.getNode().getNodeId().equals(p.getNodeId())) {
t.addContextNode(outerContextId, ctx.getNode());
}
} else {
t.addContextNode(ctx.getContextId(), ctx.getNode());
}
ctx = ctx.getNextDirect();
}
result.add(t);
}
}
}
}
}
}
return result;
} else {
final boolean reverseAxis = Type.subTypeOf(contextSequence.getItemType(), Type.NODE) && (mode == Constants.ANCESTOR_AXIS || mode == Constants.ANCESTOR_SELF_AXIS || mode == Constants.PARENT_AXIS || mode == Constants.PRECEDING_AXIS || mode == Constants.PRECEDING_SIBLING_AXIS);
final Set<NumericValue> set = new TreeSet<>();
final ValueSequence result = new ValueSequence();
for (final SequenceIterator i = innerSeq.iterate(); i.hasNext(); ) {
final NumericValue v = (NumericValue) i.nextItem();
// Non integers return... nothing, not even an error !
if (!v.hasFractionalPart() && !v.isZero()) {
final int pos = (reverseAxis ? contextSequence.getItemCount() - v.getInt() : v.getInt() - 1);
// Other positions are ignored
if (pos >= 0 && pos < contextSequence.getItemCount() && !set.contains(v)) {
result.add(contextSequence.itemAt(pos));
set.add(v);
}
}
}
return result;
}
}
use of org.exist.xquery.value.NumericValue in project exist by eXist-db.
the class OpNumeric method eval.
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
final Sequence lseq = Atomize.atomize(getLeft().eval(contextSequence, contextItem));
final Sequence rseq = Atomize.atomize(getRight().eval(contextSequence, contextItem));
if (lseq.hasMany()) {
throw new XPathException(this, ErrorCodes.XPTY0004, "Too many operands at the left of " + operator.symbol);
}
if (rseq.hasMany()) {
throw new XPathException(this, ErrorCodes.XPTY0004, "Too many operands at the right of " + operator.symbol);
}
Sequence result;
if (rseq.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else if (lseq.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else {
Item lvalue = lseq.itemAt(0);
Item rvalue = rseq.itemAt(0);
try {
if (lvalue.getType() == Type.UNTYPED_ATOMIC || lvalue.getType() == Type.ATOMIC) {
lvalue = lvalue.convertTo(Type.NUMBER);
}
if (rvalue.getType() == Type.UNTYPED_ATOMIC || rvalue.getType() == Type.ATOMIC) {
rvalue = rvalue.convertTo(Type.NUMBER);
}
if (!(lvalue instanceof ComputableValue)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")' can not be an operand for " + operator.symbol);
}
if (!(rvalue instanceof ComputableValue)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(rvalue.getType()) + "(" + rvalue + ")' can not be an operand for " + operator.symbol);
}
// TODO : move to implementations
if (operator == ArithmeticOperator.DIVISION_INTEGER) {
if (!Type.subTypeOfUnion(lvalue.getType(), Type.NUMBER)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")' can not be an operand for " + operator.symbol);
}
if (!Type.subTypeOfUnion(rvalue.getType(), Type.NUMBER)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(rvalue.getType()) + "(" + rvalue + ")' can not be an operand for " + operator.symbol);
}
// If the divisor is (positive or negative) zero, then an error is raised [err:FOAR0001]
if (((NumericValue) rvalue).isZero()) {
throw new XPathException(this, ErrorCodes.FOAR0001, "Division by zero");
}
// If either operand is NaN then an error is raised [err:FOAR0002].
if (((NumericValue) lvalue).isNaN()) {
throw new XPathException(this, ErrorCodes.FOAR0002, "Division of " + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")'");
}
// If either operand is NaN then an error is raised [err:FOAR0002].
if (((NumericValue) rvalue).isNaN()) {
throw new XPathException(this, ErrorCodes.FOAR0002, "Division of " + Type.getTypeName(rvalue.getType()) + "(" + rvalue + ")'");
}
// If $arg1 is INF or -INF then an error is raised [err:FOAR0002].
if (((NumericValue) lvalue).isInfinite()) {
throw new XPathException(this, ErrorCodes.FOAR0002, "Division of " + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")'");
}
result = ((NumericValue) lvalue).idiv((NumericValue) rvalue);
} else {
result = applyOperator((ComputableValue) lvalue, (ComputableValue) rvalue);
}
// TODO : type-checks on MOD operator : maybe the same ones than above -pb
} catch (final XPathException e) {
e.setLocation(line, column);
throw e;
}
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
// Sets the return type if not already set
if (returnType == Type.ATOMIC) // TODO : refine previously set type ? -pb
{
returnType = result.getItemType();
}
return result;
}
use of org.exist.xquery.value.NumericValue in project exist by eXist-db.
the class FunSubstring method eval.
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
// start profiler
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
// get arguments
final Expression argSourceString = getArgument(0);
final Expression argStartingLoc = getArgument(1);
Expression argLength = null;
// get the context sequence
if (contextItem != null) {
contextSequence = contextItem.toSequence();
}
Sequence result;
final Sequence seqSourceString = argSourceString.eval(contextSequence);
// If the value of $sourceString is the empty sequence return EMPTY_STRING, there must be a string to operate on!
if (seqSourceString.isEmpty()) {
result = StringValue.EMPTY_STRING;
} else {
// get the string to substring
final String sourceString = seqSourceString.getStringValue();
// check for a valid start position for the substring
final NumericValue startingLoc = ((NumericValue) (argStartingLoc.eval(contextSequence).itemAt(0).convertTo(Type.NUMBER))).round();
if (!validStartPosition(startingLoc, sourceString.length())) {
// invalid start position
result = StringValue.EMPTY_STRING;
} else {
// are there 2 or 3 arguments to this function?
if (getArgumentCount() > 2) {
argLength = getArgument(2);
final NumericValue length = ((NumericValue) (argLength.eval(contextSequence).itemAt(0).convertTo(Type.NUMBER))).round();
// Relocate length to position according to spec:
// fn:round($startingLoc) <=
// $p
// < fn:round($startingLoc) + fn:round($length)
NumericValue endingLoc;
if (!length.isInfinite()) {
endingLoc = (NumericValue) new IntegerValue(startingLoc.getInt() + length.getInt());
} else {
endingLoc = length;
}
// check for a valid end position for the substring
if (!validEndPosition(endingLoc, startingLoc)) {
// invalid length
result = StringValue.EMPTY_STRING;
} else {
if (endingLoc.getInt() > sourceString.length() || endingLoc.isInfinite()) {
// fallback to fn:substring(string, start)
result = substring(sourceString, startingLoc);
} else {
// three arguments fn:substring(string, start, end)
result = substring(sourceString, startingLoc, endingLoc);
}
}
} else {
// No length argument
// two arguments fn:substring(string, start)
result = substring(sourceString, startingLoc);
}
}
}
// end profiler
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
use of org.exist.xquery.value.NumericValue in project exist by eXist-db.
the class FunMin method eval.
/* (non-Javadoc)
* @see org.exist.xquery.Expression#eval(org.exist.dom.persistent.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
boolean computableProcessing = false;
Sequence result;
final Sequence arg = getArgument(0).eval(contextSequence, contextItem);
if (arg.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else {
// TODO : test if a range index is defined *iff* it is compatible with the collator
final Collator collator = getCollator(contextSequence, contextItem, 2);
final SequenceIterator iter = arg.unorderedIterator();
AtomicValue min = null;
while (iter.hasNext()) {
final Item item = iter.nextItem();
if (item instanceof QNameValue) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(item.getType()), arg);
}
AtomicValue value = item.atomize();
// Duration values must either all be xs:yearMonthDuration values or must all be xs:dayTimeDuration values.
if (Type.subTypeOf(value.getType(), Type.DURATION)) {
value = ((DurationValue) value).wrap();
if (value.getType() == Type.YEAR_MONTH_DURATION) {
if (min != null && min.getType() != Type.YEAR_MONTH_DURATION) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
} else if (value.getType() == Type.DAY_TIME_DURATION) {
if (min != null && min.getType() != Type.DAY_TIME_DURATION) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
} else {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(value.getType()), value);
}
// Any value of type xdt:untypedAtomic is cast to xs:double
} else if (value.getType() == Type.UNTYPED_ATOMIC) {
value = value.convertTo(Type.DOUBLE);
}
if (min == null) {
min = value;
} else {
if (Type.getCommonSuperType(min.getType(), value.getType()) == Type.ATOMIC) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
// Any value of type xdt:untypedAtomic is cast to xs:double
if (value.getType() == Type.ATOMIC) {
value = value.convertTo(Type.DOUBLE);
}
// Numeric tests
if (Type.subTypeOfUnion(value.getType(), Type.NUMBER)) {
// Don't mix comparisons
if (!Type.subTypeOfUnion(min.getType(), Type.NUMBER)) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), min);
}
if (((NumericValue) value).isNaN()) {
// Type NaN correctly
value = value.promote(min);
if (value.getType() == Type.FLOAT) {
min = FloatValue.NaN;
} else {
min = DoubleValue.NaN;
}
// although result will be NaN, we need to continue on order to type correctly
continue;
}
min = min.promote(value);
}
// Ugly test
if (value instanceof ComputableValue) {
if (!(min instanceof ComputableValue)) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), min);
}
// Type value correctly
value = value.promote(min);
min = min.min(collator, value);
computableProcessing = true;
} else {
if (computableProcessing) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
if (Collations.compare(collator, value.getStringValue(), min.getStringValue()) < 0) {
min = value;
}
}
}
}
result = min;
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
use of org.exist.xquery.value.NumericValue in project exist by eXist-db.
the class FunRoundHalfToEven method eval.
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
Sequence result;
IntegerValue precision = null;
final Sequence seq = getArgument(0).eval(contextSequence, contextItem);
if (seq.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else {
if (contextItem != null) {
contextSequence = contextItem.toSequence();
}
if (getSignature().getArgumentCount() > 1) {
precision = (IntegerValue) getArgument(1).eval(contextSequence, contextItem).itemAt(0).convertTo(Type.INTEGER);
}
final Item item = seq.itemAt(0);
NumericValue value;
if (item instanceof NumericValue) {
value = (NumericValue) item;
} else {
value = (NumericValue) item.convertTo(Type.NUMBER);
}
result = value.round(precision);
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
Aggregations