package client.net.sf.saxon.ce.functions;
import client.net.sf.saxon.ce.expr.*;
import client.net.sf.saxon.ce.om.Item;
import client.net.sf.saxon.ce.om.SequenceIterator;
import client.net.sf.saxon.ce.om.StandardNames;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.type.BuiltInAtomicType;
import client.net.sf.saxon.ce.type.ItemType;
import client.net.sf.saxon.ce.type.TypeHierarchy;
import client.net.sf.saxon.ce.value.*;
/**
* Implementation of the fn:avg function
*/
public class Average extends Aggregate {
public Average newInstance() {
return new Average();
}
/**
* Determine the item type of the value returned by the function
* @param th the type hierarchy cache
*/
public ItemType getItemType(TypeHierarchy th) {
ItemType base = Atomizer.getAtomizedItemType(argument[0], false, th);
if (base.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) {
return BuiltInAtomicType.DOUBLE;
} else if (base.getPrimitiveType() == StandardNames.XS_INTEGER) {
return BuiltInAtomicType.DECIMAL;
} else {
return base;
}
}
/**
* Evaluate the function
*/
public Item evaluateItem(XPathContext context) throws XPathException {
SequenceIterator iter = argument[0].iterate(context);
int count = 0;
AtomicValue item = (AtomicValue) iter.next();
if (item == null) {
// the sequence is empty
return null;
}
count++;
if (item instanceof UntypedAtomicValue) {
try {
item = item.convert(BuiltInAtomicType.DOUBLE, true).asAtomic();
} catch (XPathException e) {
e.maybeSetLocation(getSourceLocator());
throw e;
}
}
if (item instanceof NumericValue) {
while (true) {
AtomicValue next = (AtomicValue) iter.next();
if (next == null) {
return ArithmeticExpression.compute(item, Calculator.DIV, IntegerValue.makeIntegerValue(count), context);
}
count++;
if (next instanceof UntypedAtomicValue) {
next = next.convert(BuiltInAtomicType.DOUBLE, true).asAtomic();
} else if (!(next instanceof NumericValue)) {
badMix(context);
}
item = ArithmeticExpression.compute(item, Calculator.PLUS, next, context);
}
} else if (item instanceof DurationValue) {
while (true) {
AtomicValue next = (AtomicValue) iter.next();
if (next == null) {
return ((DurationValue)item).multiply(1.0/count);
}
count++;
if (!(next instanceof DurationValue)) {
badMix(context);
}
item = ((DurationValue)item).add((DurationValue)next);
}
} else {
badMix(context);
return null;
}
}
private void badMix(XPathContext context) throws XPathException {
dynamicError("Input to avg() contains invalid or mixed data types", "FORG0006", context);
}
}
// 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.