use of org.exist.xquery.value.FunctionReference in project exist by eXist-db.
the class ContentFunctions method eval.
@Override
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
// is argument the empty sequence?
if (args[0].isEmpty()) {
return Sequence.EMPTY_SEQUENCE;
}
ContentExtraction ce = new ContentExtraction();
if (isCalledAs("stream-content")) {
/* binary content */
BinaryValue binary = (BinaryValue) args[0].itemAt(0);
/* callback function */
FunctionReference ref = (FunctionReference) args[2].itemAt(0);
Map<String, String> mappings = new HashMap<>();
if (args[3].hasOne()) {
NodeValue namespaces = (NodeValue) args[3].itemAt(0);
parseMappings(namespaces, mappings);
}
return streamContent(ce, binary, args[1], ref, mappings, args[4]);
} else {
try {
if (isCalledAs("get-metadata")) {
context.pushDocumentContext();
try {
final MemTreeBuilder builder = context.getDocumentBuilder();
builder.startDocument();
builder.startElement(new QName("html", XHTML_NS), null);
builder.startElement(new QName("head", XHTML_NS), null);
final QName qnMeta = new QName("meta", XHTML_NS);
final Metadata metadata = ce.extractMetadata((BinaryValue) args[0].itemAt(0));
for (final String name : metadata.names()) {
for (final String value : metadata.getValues(name)) {
final AttributesImpl attributes = new AttributesImpl();
attributes.addAttribute("", "name", "name", "string", name);
attributes.addAttribute("", "content", "content", "string", value);
builder.startElement(qnMeta, attributes);
builder.endElement();
}
}
builder.endElement();
builder.endElement();
builder.endDocument();
return builder.getDocument();
} finally {
context.popDocumentContext();
}
} else {
final DocumentBuilderReceiver builder = new DocumentBuilderReceiver();
builder.setSuppressWhitespace(false);
final Metadata metadata = ce.extractContentAndMetadata((BinaryValue) args[0].itemAt(0), (ContentHandler) builder);
return (NodeValue) builder.getDocument();
}
} catch (IOException | SAXException | ContentExtractionException ex) {
LOG.error(ex.getMessage(), ex);
throw new XPathException(this, ex.getMessage(), ex);
}
}
}
use of org.exist.xquery.value.FunctionReference in project exist by eXist-db.
the class FunSort method eval.
@Override
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
Sequence seq = args[0];
Collator collator = collator(args, 1);
ArrayList<Sequence> keys = new ArrayList<>(seq.getItemCount());
try (FunctionReference ref = function(args, 2)) {
final Sequence[] refArgs = new Sequence[1];
Item item;
Sequence value;
for (final SequenceIterator i = seq.iterate(); i.hasNext(); ) {
item = i.nextItem();
if (ref != null) {
refArgs[0] = item.toSequence();
value = ref.evalFunction(null, null, refArgs);
} else {
value = item.toSequence();
}
keys.add(Atomize.atomize(value));
}
}
return sort(seq, keys, collator);
}
use of org.exist.xquery.value.FunctionReference in project exist by eXist-db.
the class FunHigherOrderFun method eval.
@Override
public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException {
Sequence result = new ValueSequence();
if (isCalledAs("for-each")) {
try (final FunctionReference ref = (FunctionReference) args[1].itemAt(0)) {
ref.analyze(cachedContextInfo);
if (funcRefHasDifferentArity(ref, 1)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "The supplied function (" + ref.getStringValue() + ") has " + ref.getSignature().getArgumentCount() + " arguments - expected 1");
}
for (final SequenceIterator i = args[0].iterate(); i.hasNext(); ) {
final Item item = i.nextItem();
final Sequence r = ref.evalFunction(null, null, new Sequence[] { item.toSequence() });
result.addAll(r);
}
}
} else if (isCalledAs("filter")) {
final FunctionReference refParam;
final Sequence seq;
// Hack: switch parameters for backwards compatibility
if (Type.subTypeOf(args[1].getItemType(), Type.FUNCTION_REFERENCE)) {
refParam = (FunctionReference) args[1].itemAt(0);
seq = args[0];
} else {
refParam = (FunctionReference) args[0].itemAt(0);
seq = args[1];
}
try (final FunctionReference ref = refParam) {
ref.analyze(cachedContextInfo);
if (funcRefHasDifferentArity(ref, 1)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "The supplied function (" + ref.getStringValue() + ") has " + ref.getSignature().getArgumentCount() + " arguments - expected 1");
}
for (final SequenceIterator i = seq.iterate(); i.hasNext(); ) {
final Item item = i.nextItem();
final Sequence r = ref.evalFunction(null, null, new Sequence[] { item.toSequence() });
// two pending tests in exist-core/src/test/xquery/xquery3/fnHigherOrderFunctions.xql
if (r.effectiveBooleanValue()) {
result.add(item);
}
}
}
} else if (isCalledAs("fold-left")) {
try (final FunctionReference ref = (FunctionReference) args[2].itemAt(0)) {
ref.analyze(cachedContextInfo);
if (funcRefHasDifferentArity(ref, 2)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "The supplied function (" + ref.getStringValue() + ") has " + ref.getSignature().getArgumentCount() + " arguments - expected 2");
}
final Sequence seq = args[0];
final Sequence zero = args[1];
result = foldLeft(ref, zero, seq.iterate());
}
} else if (isCalledAs("fold-right")) {
try (final FunctionReference ref = (FunctionReference) args[2].itemAt(0)) {
ref.analyze(cachedContextInfo);
if (funcRefHasDifferentArity(ref, 2)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "The supplied function (" + ref.getStringValue() + ") has " + ref.getSignature().getArgumentCount() + " arguments - expected 2");
}
final Sequence zero = args[1];
final Sequence seq = args[0];
if (seq instanceof ValueSequence) {
result = foldRightNonRecursive(ref, zero, ((ValueSequence) seq).iterateInReverse());
} else if (seq instanceof RangeSequence) {
result = foldRightNonRecursive(ref, zero, ((RangeSequence) seq).iterateInReverse());
} else {
result = foldRight(ref, zero, seq);
}
}
} else if (isCalledAs("for-each-pair")) {
try (final FunctionReference ref = (FunctionReference) args[2].itemAt(0)) {
ref.analyze(cachedContextInfo);
if (funcRefHasDifferentArity(ref, 2)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "The supplied function (" + ref.getStringValue() + ") has " + ref.getSignature().getArgumentCount() + " arguments - expected 2");
}
final SequenceIterator i1 = args[0].iterate();
final SequenceIterator i2 = args[1].iterate();
while (i1.hasNext() && i2.hasNext()) {
final Sequence r = ref.evalFunction(null, null, new Sequence[] { i1.nextItem().toSequence(), i2.nextItem().toSequence() });
result.addAll(r);
}
}
} else if (isCalledAs("apply")) {
try (final FunctionReference ref = (FunctionReference) args[0].itemAt(0)) {
ref.analyze(cachedContextInfo);
final ArrayType array = (ArrayType) args[1].itemAt(0);
if (funcRefHasDifferentArity(ref, array.getSize())) {
throw new XPathException(this, ErrorCodes.FOAP0001, "Number of arguments supplied to fn:apply does not match function signature. Expected: " + ref.getSignature().getArgumentCount() + ", got: " + array.getSize());
}
final Sequence[] fargs = array.toArray();
return ref.evalFunction(null, null, fargs);
}
}
return result;
}
use of org.exist.xquery.value.FunctionReference in project exist by eXist-db.
the class PartialFunctionApplication method createPartial.
private FunctionReference createPartial(Sequence contextSequence, Item contextItem, FunctionCall staticCall) throws XPathException {
final FunctionSignature signature = staticCall.getSignature();
final SequenceType[] paramTypes = signature.getArgumentTypes();
// the parameters of the newly created inline function:
// old params except the fixed ones
final List<SequenceType> newParamTypes = new ArrayList<>();
// the arguments to pass to the inner call
final List<Expression> callArgs = new ArrayList<>();
// parameter variables of the new inline function
final List<QName> variables = new ArrayList<>();
// the inline function
final int argCount = staticCall.getArgumentCount();
for (int i = 0; i < argCount; i++) {
final Expression param = staticCall.getArgument(i);
if (param instanceof Function.Placeholder) {
// overloaded functions like concat may have an arbitrary number of arguments
if (i < paramTypes.length) {
newParamTypes.add(paramTypes[i]);
} else // overloaded function: add last sequence type
{
newParamTypes.add(paramTypes[paramTypes.length - 1]);
}
// create local parameter variables
final QName varName = new QName("vp" + i, XMLConstants.NULL_NS_URI);
variables.add(varName);
// the argument to the inner call is a variable ref
final VariableReference ref = new VariableReference(context, varName);
callArgs.add(ref);
} else {
// fixed argument: just compute the argument value
try {
param.analyze(cachedContextInfo);
final Sequence seq = param.eval(contextSequence, contextItem);
callArgs.add(new PrecomputedValue(context, seq));
} catch (final XPathException e) {
if (e.getLine() <= 0) {
e.setLocation(line, column, getSource());
}
// append location of the function call to the exception message:
e.addFunctionCall(function.functionDef, this);
throw e;
}
}
}
final SequenceType[] newParamArray = newParamTypes.toArray(new SequenceType[0]);
final QName name = new QName(PARTIAL_FUN_PREFIX + hashCode(), XMLConstants.NULL_NS_URI);
final FunctionSignature newSignature = new FunctionSignature(name, newParamArray, signature.getReturnType());
final UserDefinedFunction func = new UserDefinedFunction(context, newSignature);
func.setLocation(staticCall.getLine(), staticCall.getColumn());
// add the created parameter variables to the function
for (final QName varName : variables) {
func.addVariable(varName);
}
final FunctionCall innerCall = new FunctionCall(staticCall);
innerCall.setArguments(callArgs);
func.setFunctionBody(innerCall);
final FunctionCall newCall = new FunctionCall(context, func);
newCall.setLocation(staticCall.getLine(), staticCall.getColumn());
return new FunctionReference(newCall);
}
Aggregations