You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by mu...@apache.org on 2023/06/29 15:10:35 UTC
[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xpath 3.1 function item inline function expressions. also committing implementations of xpath 3.1 higher-order functions fn:for-each and fn:filter, that use inline function expressions as arguments. also committing as well, few related working test cases as well.
This is an automated email from the ASF dual-hosted git repository.
mukulg pushed a commit to branch xalan-j_xslt3.0
in repository https://gitbox.apache.org/repos/asf/xalan-java.git
The following commit(s) were added to refs/heads/xalan-j_xslt3.0 by this push:
new 1ed00b9c committing implementation of xpath 3.1 function item inline function expressions. also committing implementations of xpath 3.1 higher-order functions fn:for-each and fn:filter, that use inline function expressions as arguments. also committing as well, few related working test cases as well.
new 0456d97e Merge pull request #13 from mukulga/xalan-j_xslt3.0_mukul
1ed00b9c is described below
commit 1ed00b9c3cb2e34eba6c061301342cbd4e56d2ba
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Thu Jun 29 20:29:25 2023 +0530
committing implementation of xpath 3.1 function item inline function expressions. also committing implementations of xpath 3.1 higher-order functions fn:for-each and fn:filter, that use inline function expressions as arguments. also committing as well, few related working test cases as well.
---
src/org/apache/xalan/templates/ElemCopyOf.java | 60 +++++-
src/org/apache/xpath/XPathContext.java | 14 ++
src/org/apache/xpath/compiler/Compiler.java | 7 +
src/org/apache/xpath/compiler/FunctionTable.java | 16 +-
src/org/apache/xpath/compiler/Keywords.java | 8 +-
src/org/apache/xpath/compiler/OpCodes.java | 4 +-
src/org/apache/xpath/compiler/XPathParser.java | 92 ++++++++-
src/org/apache/xpath/functions/FuncConcat.java | 2 +-
src/org/apache/xpath/functions/FuncFilter.java | 237 ++++++++++++++++++++++
src/org/apache/xpath/functions/FuncForEach.java | 212 +++++++++++++++++++
src/org/apache/xpath/objects/InlineFunction.java | 77 +++++++
src/org/apache/xpath/objects/ResultSequence.java | 9 +-
src/org/apache/xpath/objects/XObject.java | 3 +
src/org/apache/xpath/operations/Mult.java | 22 +-
src/org/apache/xpath/operations/Variable.java | 13 ++
src/org/apache/xpath/res/XPATHErrorResources.java | 21 +-
src/org/apache/xpath/xs/types/XSInteger.java | 4 +
tests/fn_filter/gold/test1.out | 4 +
tests/fn_filter/gold/test2.out | 1 +
tests/fn_filter/gold/test3.out | 9 +
tests/fn_filter/test1.xsl | 36 ++++
tests/fn_filter/test1_a.xml | 10 +
tests/fn_filter/test1_b.xml | 13 ++
tests/fn_filter/test2.xsl | 37 ++++
tests/fn_filter/test3.xsl | 38 ++++
tests/fn_foreach/gold/test1.out | 1 +
tests/fn_foreach/gold/test2.out | 9 +
tests/fn_foreach/gold/test3.out | 14 ++
tests/fn_foreach/gold/test4.out | 9 +
tests/fn_foreach/gold/test5.out | 20 ++
tests/fn_foreach/gold/test6.out | 7 +
tests/fn_foreach/gold/test7.out | 7 +
tests/fn_foreach/gold/test8.out | 7 +
tests/fn_foreach/test1.xsl | 35 ++++
tests/fn_foreach/test1_a.xml | 10 +
tests/fn_foreach/test1_b.xml | 13 ++
tests/fn_foreach/test2.xsl | 39 ++++
tests/fn_foreach/test3.xsl | 41 ++++
tests/fn_foreach/test4.xsl | 45 ++++
tests/fn_foreach/test5.xsl | 53 +++++
tests/fn_foreach/test6.xsl | 52 +++++
tests/fn_foreach/test7.xsl | 52 +++++
tests/fn_foreach/test8.xsl | 52 +++++
tests/org/apache/xalan/xpath3/FnFilterTests.java | 80 ++++++++
tests/org/apache/xalan/xpath3/FnForEachTests.java | 130 ++++++++++++
tests/org/apache/xalan/xslt3/AllXsl3Tests.java | 4 +-
46 files changed, 1612 insertions(+), 17 deletions(-)
diff --git a/src/org/apache/xalan/templates/ElemCopyOf.java b/src/org/apache/xalan/templates/ElemCopyOf.java
index 5fadba64..6acb612a 100644
--- a/src/org/apache/xalan/templates/ElemCopyOf.java
+++ b/src/org/apache/xalan/templates/ElemCopyOf.java
@@ -32,15 +32,21 @@ import org.apache.xalan.serialize.SerializerUtils;
import org.apache.xml.serializer.SerializationHandler;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.ResultSequence;
import org.apache.xpath.objects.XObject;
-/**
- * Implement xsl:copy-of.
- * <pre>
- * <!ELEMENT xsl:copy-of EMPTY>
- * <!ATTLIST xsl:copy-of select %expr; #REQUIRED>
- * </pre>
- * @see <a href="http://www.w3.org/TR/xslt#copy-of">copy-of in XSLT Specification</a>
+/*
+ * Implementation of XSLT xsl:copy-of instruction.
+ *
+ * XSLT 3.0 xsl:copy-of instruction definition,
+ *
+ * <xsl:copy-of
+ select = expression
+ copy-accumulators? = boolean
+ copy-namespaces? = boolean
+ type? = eqname
+ validation? = "strict" | "lax" | "preserve" | "strip" />
+ *
* @xsl.usage advanced
*/
public class ElemCopyOf extends ElemTemplateElement
@@ -192,6 +198,46 @@ public class ElemCopyOf extends ElemTemplateElement
SerializerUtils.outputResultTreeFragment(
handler, value, transformer.getXPathContext());
break;
+ case XObject.CLASS_RESULT_SEQUENCE :
+ // added for XSLT 3.0
+ ResultSequence resultSequence = (ResultSequence)value;
+ for (int idx = 0; idx < resultSequence.size(); idx++) {
+ XObject sequenceItem = resultSequence.item(idx);
+
+ if (sequenceItem.getType() == XObject.CLASS_STRING) {
+ String str = sequenceItem.str();
+ handler.characters(str.toCharArray(), 0, str.length());
+ if (idx < (resultSequence.size() - 1)) {
+ String strSpace = " ";
+ handler.characters(strSpace.toCharArray(), 0, strSpace.length());
+ }
+ continue;
+ }
+
+ DTMIterator dtmIter = sequenceItem.iter();
+
+ DTMTreeWalker dtmTreeWalker = new TreeWalker2Result(transformer, handler);
+ int nodePos;
+
+ while (DTM.NULL != (nodePos = dtmIter.nextNode())) {
+ DTM dtm = xctxt.getDTMManager().getDTM(nodePos);
+ short t = dtm.getNodeType(nodePos);
+
+ if (t == DTM.DOCUMENT_NODE) {
+ for (int child = dtm.getFirstChild(nodePos); child != DTM.NULL;
+ child = dtm.getNextSibling(child)) {
+ dtmTreeWalker.traverse(child);
+ }
+ }
+ else if (t == DTM.ATTRIBUTE_NODE) {
+ SerializerUtils.addAttribute(handler, nodePos);
+ }
+ else {
+ dtmTreeWalker.traverse(nodePos);
+ }
+ }
+ }
+ break;
default :
s = value.str();
diff --git a/src/org/apache/xpath/XPathContext.java b/src/org/apache/xpath/XPathContext.java
index 5ecccfc0..9fba1a4d 100644
--- a/src/org/apache/xpath/XPathContext.java
+++ b/src/org/apache/xpath/XPathContext.java
@@ -49,6 +49,7 @@ import org.apache.xml.utils.IntStack;
import org.apache.xml.utils.NodeVector;
import org.apache.xml.utils.ObjectStack;
import org.apache.xml.utils.PrefixResolver;
+import org.apache.xml.utils.QName;
import org.apache.xml.utils.SAXSourceLocator;
import org.apache.xml.utils.XMLString;
import org.apache.xpath.axes.SubContextList;
@@ -127,6 +128,11 @@ public class XPathContext extends DTMManager // implements ExpressionContext
private GregorianCalendar m_currentDateTime;
private XSDuration m_timezone;
+
+ // we use this java.util.Map object, to store for XPath 3.1 function item
+ // "inline function" the parameter names and their values. we don't use,
+ // XalanJ XPath context's variable stack for this purpose.
+ private Map<QName, XObject> inlineFunctionVarMap = new HashMap<QName, XObject>();
/**
* Though XPathContext context extends
@@ -1450,5 +1456,13 @@ public class XPathContext extends DTMManager // implements ExpressionContext
public void setTimezone(XSDuration timezone) {
this.m_timezone = timezone;
}
+
+ public Map<QName, XObject> getInlineFunctionVarMap() {
+ return inlineFunctionVarMap;
+ }
+
+ public void setInlineFunctionVarMap(Map<QName, XObject> inlineFunctionVarMap) {
+ this.inlineFunctionVarMap = inlineFunctionVarMap;
+ }
}
diff --git a/src/org/apache/xpath/compiler/Compiler.java b/src/org/apache/xpath/compiler/Compiler.java
index d56e8560..23a520f8 100644
--- a/src/org/apache/xpath/compiler/Compiler.java
+++ b/src/org/apache/xpath/compiler/Compiler.java
@@ -195,6 +195,8 @@ public class Compiler extends OpMap
expr = compileExtension(opPos); break;
case OpCodes.OP_FUNCTION :
expr = compileFunction(opPos); break;
+ case OpCodes.OP_INLINE_FUNCTION :
+ expr = compileInlineFunction(opPos); break;
case OpCodes.OP_LOCATIONPATH :
expr = locationPath(opPos); break;
case OpCodes.OP_PREDICATE :
@@ -1156,6 +1158,11 @@ private static final boolean DEBUG = false;
return null;
}
}
+
+ Expression compileInlineFunction(int opPos) throws TransformerException
+ {
+ return XPathParser.fInlineFunction;
+ }
// The current id for extension functions.
private static long s_nextMethodId = 0;
diff --git a/src/org/apache/xpath/compiler/FunctionTable.java b/src/org/apache/xpath/compiler/FunctionTable.java
index e0101823..e9251ee6 100644
--- a/src/org/apache/xpath/compiler/FunctionTable.java
+++ b/src/org/apache/xpath/compiler/FunctionTable.java
@@ -179,6 +179,12 @@ public class FunctionTable
/** The 'index-of()' id. */
public static final int FUNC_INDEX_OF = 52;
+
+ /** The 'for-each()' id. */
+ public static final int FUNC_FOR_EACH = 53;
+
+ /** The 'filter()' id. */
+ public static final int FUNC_FILTER = 54;
// Proprietary
@@ -207,7 +213,7 @@ public class FunctionTable
* Number of built in functions. Be sure to update this as
* built-in functions are added.
*/
- private static final int NUM_BUILT_IN_FUNCS = 53;
+ private static final int NUM_BUILT_IN_FUNCS = 55;
/**
* Number of built-in functions that may be added.
@@ -305,6 +311,10 @@ public class FunctionTable
org.apache.xpath.functions.FuncImplicitTimezone.class;
m_functions[FUNC_INDEX_OF] =
org.apache.xpath.functions.FuncIndexOf.class;
+ m_functions[FUNC_FOR_EACH] =
+ org.apache.xpath.functions.FuncForEach.class;
+ m_functions[FUNC_FILTER] =
+ org.apache.xpath.functions.FuncFilter.class;
}
static{
@@ -410,6 +420,10 @@ public class FunctionTable
new Integer(FunctionTable.FUNC_IMPLICIT_TIMEZONE));
m_functionID.put(Keywords.FUNC_INDEX_OF,
new Integer(FunctionTable.FUNC_INDEX_OF));
+ m_functionID.put(Keywords.FUNC_FOR_EACH,
+ new Integer(FunctionTable.FUNC_FOR_EACH));
+ m_functionID.put(Keywords.FUNC_FILTER,
+ new Integer(FunctionTable.FUNC_FILTER));
}
public FunctionTable(){
diff --git a/src/org/apache/xpath/compiler/Keywords.java b/src/org/apache/xpath/compiler/Keywords.java
index 5bfd7851..9e66c05c 100644
--- a/src/org/apache/xpath/compiler/Keywords.java
+++ b/src/org/apache/xpath/compiler/Keywords.java
@@ -259,13 +259,19 @@ public class Keywords
/** index-of function string. */
public static final String FUNC_INDEX_OF = "index-of";
+
+ /** for-each function string. */
+ public static final String FUNC_FOR_EACH = "for-each";
+
+ /** filter function string. */
+ public static final String FUNC_FILTER = "filter";
// Proprietary, built in functions
/** current function string (Proprietary). */
public static final String FUNC_DOCLOCATION_STRING = "document-location";
- //XML Schema built-in types constructor functions, configurations
+ // XML Schema built-in types constructor functions, configurations
/** xs:decimal data type string. */
public static final String FUNC_XS_DECIMAL = "decimal";
diff --git a/src/org/apache/xpath/compiler/OpCodes.java b/src/org/apache/xpath/compiler/OpCodes.java
index 82076356..c8d71dfa 100644
--- a/src/org/apache/xpath/compiler/OpCodes.java
+++ b/src/org/apache/xpath/compiler/OpCodes.java
@@ -675,8 +675,10 @@ public class OpCodes
* @xsl.usage advanced
*/
public static final int OP_VC_GE = 60;
+
+ public static final int OP_INLINE_FUNCTION = 61;
/** The next free ID. Please keep this up to date. */
- private static final int NEXT_FREE_ID = 61;
+ private static final int NEXT_FREE_ID = 62;
}
diff --git a/src/org/apache/xpath/compiler/XPathParser.java b/src/org/apache/xpath/compiler/XPathParser.java
index ec199d32..867a5813 100644
--- a/src/org/apache/xpath/compiler/XPathParser.java
+++ b/src/org/apache/xpath/compiler/XPathParser.java
@@ -20,6 +20,9 @@
*/
package org.apache.xpath.compiler;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.xml.transform.ErrorListener;
import javax.xml.transform.TransformerException;
@@ -27,6 +30,7 @@ import org.apache.xalan.res.XSLMessages;
import org.apache.xml.utils.PrefixResolver;
import org.apache.xpath.XPathProcessorException;
import org.apache.xpath.domapi.XPathStylesheetDOM3Exception;
+import org.apache.xpath.objects.InlineFunction;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.objects.XString;
import org.apache.xpath.res.XPATHErrorResources;
@@ -71,6 +75,8 @@ public class XPathParser
protected final static int FILTER_MATCH_FAILED = 0;
protected final static int FILTER_MATCH_PRIMARY = 1;
protected final static int FILTER_MATCH_PREDICATES = 2;
+
+ static InlineFunction fInlineFunction = null;
/**
* The parser constructor.
@@ -1494,6 +1500,7 @@ public class XPathParser
* | Literal
* | Number
* | FunctionCall
+ * | FunctionItemExpr
*
* @return true if this method successfully matched a PrimaryExpr
*
@@ -1503,7 +1510,8 @@ public class XPathParser
protected boolean PrimaryExpr() throws javax.xml.transform.TransformerException
{
- boolean matchFound;
+ boolean matchFound = false;
+
int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH);
if ((m_tokenChar == '\'') || (m_tokenChar == '"'))
@@ -1550,6 +1558,19 @@ public class XPathParser
matchFound = true;
}
+ else if (tokenIs("function") && lookahead('(', 1)) {
+ // support for XPath 3.1 function item "inline function" expressions
+
+ appendOp(2, OpCodes.OP_INLINE_FUNCTION);
+
+ fInlineFunction = InlineFunctionExpr();
+
+ m_ops.setOp(opPos + OpMap.MAPINDEX_LENGTH,
+ m_ops.getOp(OpMap.MAPINDEX_LENGTH) - opPos);
+
+ matchFound = true;
+
+ }
else if (lookahead('(', 1) || (lookahead(':', 1) && lookahead('(', 3)))
{
matchFound = FunctionCall();
@@ -1561,6 +1582,75 @@ public class XPathParser
return matchFound;
}
+
+ protected InlineFunction InlineFunctionExpr() throws javax.xml.transform.TransformerException {
+ InlineFunction inlineFunction = new InlineFunction();
+
+ List<String> funcParamNameList = new ArrayList<String>();
+ String funcBodyXPathExprStr = null;
+
+ nextToken();
+
+ consumeExpected('(');
+
+ if (!tokenIs(')')) {
+ while (!tokenIs(')') && m_token != null)
+ {
+ if (tokenIs(','))
+ {
+ error(XPATHErrorResources.ER_FOUND_COMMA_BUT_NO_PRECEDING_PARAM, null);
+ }
+
+ if (m_tokenChar == '$')
+ {
+ nextToken();
+ funcParamNameList.add(m_token);
+ nextToken();
+ }
+
+ if (!tokenIs(')'))
+ {
+ consumeExpected(',');
+
+ if (tokenIs(')'))
+ {
+ error(XPATHErrorResources.ER_FOUND_COMMA_BUT_NO_FOLLOWING_PARAM, null);
+ }
+ }
+ }
+ }
+
+ if (funcParamNameList.size() > 1) {
+ error(XPATHErrorResources.ER_INLINE_FUNCTION_PARAM_CARDINALITY, new Object[] {
+ Integer.valueOf(funcParamNameList.size()) });
+ }
+
+ inlineFunction.setFuncParamNameList(funcParamNameList);
+
+ consumeExpected(')');
+
+ consumeExpected('{');
+
+ StringBuffer funcBodyXPathExprStrBuff = new StringBuffer();
+
+ if (tokenIs('}')) {
+ consumeExpected('}');
+ }
+ else {
+ while (!tokenIs('}') && m_token != null)
+ {
+ funcBodyXPathExprStrBuff.append(m_token);
+ nextToken();
+ }
+ consumeExpected('}');
+ }
+
+ funcBodyXPathExprStr = funcBodyXPathExprStrBuff.toString();
+
+ inlineFunction.setFuncBodyXPathExprStr(funcBodyXPathExprStr);
+
+ return inlineFunction;
+ }
/**
*
diff --git a/src/org/apache/xpath/functions/FuncConcat.java b/src/org/apache/xpath/functions/FuncConcat.java
index 63f4fac8..948f4451 100644
--- a/src/org/apache/xpath/functions/FuncConcat.java
+++ b/src/org/apache/xpath/functions/FuncConcat.java
@@ -124,7 +124,7 @@ public class FuncConcat extends FunctionMultiArgs
}
}
else {
- resultStr = expr.execute(xctxt).str();
+ resultStr = expr.execute(xctxt).str();
}
return resultStr;
diff --git a/src/org/apache/xpath/functions/FuncFilter.java b/src/org/apache/xpath/functions/FuncFilter.java
new file mode 100644
index 00000000..595f9fd6
--- /dev/null
+++ b/src/org/apache/xpath/functions/FuncFilter.java
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xpath.functions;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.utils.QName;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.LocPathIterator;
+import org.apache.xpath.objects.InlineFunction;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XBoolean;
+import org.apache.xpath.objects.XNodeSet;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XObjectFactory;
+import org.apache.xpath.operations.Variable;
+import org.apache.xpath.res.XPATHErrorResources;
+import org.w3c.dom.Node;
+
+/**
+ * Execute the filter() function.
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+/*
+ * fn:filter is one of XPath 3.1's higher-order function
+ * (ref, https://www.w3.org/TR/xpath-functions-31/#higher-order-functions).
+ *
+ * The XPath function fn:filter has following signature, and definition,
+ *
+ * fn:filter($seq as item()*, $f as function(item()) as xs:boolean) as item()*
+ *
+ * The function fn:filter returns those items from the sequence $seq for which the
+ * supplied function $f returns true.
+ *
+ * Error conditions,
+ As a consequence of the function signature and the function calling rules, a type
+ error occurs if the supplied function $f returns anything other than a single
+ xs:boolean item. There is no conversion to an effective boolean value.
+ */
+public class FuncFilter extends Function2Args {
+
+ private static final long serialVersionUID = 2912594883291006421L;
+
+ private static final String FUNCTION_NAME = "filter()";
+
+ /**
+ * Execute the function. The function must return a valid object.
+ *
+ * @param xctxt The current execution context.
+ *
+ * @return A valid XObject.
+ *
+ * @throws javax.xml.transform.TransformerException
+ */
+ public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
+ {
+
+ XObject funcEvaluationResult = null;
+
+ final int contextNode = xctxt.getCurrentNode();
+
+ Expression arg0 = getArg0();
+ Expression arg1 = getArg1();
+
+ DTMIterator arg0DtmIterator = null;
+
+ XObject arg0XsObject = null;
+
+ if (arg0 instanceof LocPathIterator) {
+ arg0DtmIterator = arg0.asIterator(xctxt, contextNode);
+ }
+ else {
+ arg0XsObject = arg0.execute(xctxt, contextNode);
+ }
+
+ ResultSequence resultSeq = new ResultSequence();
+
+ if (arg1 instanceof InlineFunction) {
+ resultSeq = evaluateFnFilter(xctxt, arg0XsObject, arg0DtmIterator, (InlineFunction)arg1);
+ }
+ else if (arg1 instanceof Variable) {
+ XObject arg1VarValue = arg1.execute(xctxt);
+ if (arg1VarValue instanceof InlineFunction) {
+ resultSeq = evaluateFnFilter(xctxt, arg0XsObject, arg0DtmIterator, (InlineFunction)arg1VarValue);
+ }
+ else {
+ throw new javax.xml.transform.TransformerException("FORG0006 : The second argument to function call filter(), "
+ + "is not a function item.", xctxt.getSAXLocator());
+ }
+ }
+ else {
+ throw new javax.xml.transform.TransformerException("FORG0006 : The second argument to function call filter(), "
+ + "is not a function item.", xctxt.getSAXLocator());
+ }
+
+ funcEvaluationResult = resultSeq;
+
+ return funcEvaluationResult;
+ }
+
+ /**
+ * Check that the number of arguments passed to this function is correct.
+ *
+ * @param argNum The number of arguments that is being passed to the function.
+ *
+ * @throws WrongNumberArgsException
+ */
+ public void checkNumberArgs(int argNum) throws WrongNumberArgsException
+ {
+ if (argNum != 2) {
+ reportWrongNumberArgs();
+ }
+ }
+
+ /**
+ * Constructs and throws a WrongNumberArgException with the appropriate
+ * message for this function object.
+ *
+ * @throws WrongNumberArgsException
+ */
+ protected void reportWrongNumberArgs() throws WrongNumberArgsException {
+ throw new WrongNumberArgsException(XSLMessages.createXPATHMessage(
+ XPATHErrorResources.ER_TWO, null)); //"2"
+ }
+
+ /*
+ * Evaluate the function call fn:filter.
+ */
+ private ResultSequence evaluateFnFilter(XPathContext xctxt, XObject arg0XsObject,
+ DTMIterator arg0DtmIterator, InlineFunction arg1)
+ throws TransformerException {
+
+ ResultSequence resultSeq = new ResultSequence();
+
+ List<String> funcParamNameList = arg1.getFuncParamNameList();
+ String funcBodyXPathExprStr = arg1.getFuncBodyXPathExprStr();
+
+ if (funcBodyXPathExprStr == null || "".equals(funcBodyXPathExprStr)) {
+ return resultSeq;
+ }
+
+ QName varQname = null;
+
+ if (funcParamNameList.size() == 1) {
+ varQname = new QName(funcParamNameList.get(0));
+ }
+
+ SourceLocator srcLocator = xctxt.getSAXLocator();
+
+ XPath xpathInlineFn = new XPath(funcBodyXPathExprStr, srcLocator, null, XPath.SELECT, null);
+
+ if (arg0XsObject instanceof ResultSequence) {
+ XPathContext xpathContextNew = new XPathContext(false);
+ Map<QName, XObject> inlineFunctionVarMap = xpathContextNew.getInlineFunctionVarMap();
+
+ ResultSequence inpResultSeq = (ResultSequence)arg0XsObject;
+ for (int idx = 0; idx < inpResultSeq.size(); idx++) {
+ XObject inpSeqItem = inpResultSeq.item(idx);
+ if (varQname != null) {
+ inlineFunctionVarMap.put(varQname, inpSeqItem);
+ }
+
+ XObject resultObj = xpathInlineFn.execute(xpathContextNew, DTM.NULL, null);
+ if (resultObj instanceof XBoolean) {
+ if (((XBoolean)resultObj).bool()) {
+ resultSeq.add(inpSeqItem);
+ }
+ }
+ else {
+ throw new javax.xml.transform.TransformerException("XPTY0004 : The item type of the result of calling "
+ + "function filter() is not xs:boolean.", xctxt.getSAXLocator());
+ }
+ }
+
+ inlineFunctionVarMap.clear();
+ }
+ else if (arg0DtmIterator != null) {
+ Map<QName, XObject> inlineFunctionVarMap = xctxt.getInlineFunctionVarMap();
+
+ int dtmNodeHandle;
+
+ while (DTM.NULL != (dtmNodeHandle = arg0DtmIterator.nextNode())) {
+ DTM dtm = xctxt.getDTM(dtmNodeHandle);
+ Node node = dtm.getNode(dtmNodeHandle);
+ XObject inpSeqItem = XObjectFactory.create(node, xctxt);
+ if (varQname != null) {
+ inlineFunctionVarMap.put(varQname, inpSeqItem);
+ }
+
+ xctxt.pushCurrentNode(dtmNodeHandle);
+
+ XObject resultObj = xpathInlineFn.execute(xctxt, dtmNodeHandle, null);
+ if (resultObj instanceof XBoolean) {
+ if (((XBoolean)resultObj).bool()) {
+ resultSeq.add(new XNodeSet(dtmNodeHandle, xctxt));
+ }
+ }
+ else {
+ throw new javax.xml.transform.TransformerException("XPTY0004 : The item type of the result of calling "
+ + "function filter() is not xs:boolean.", xctxt.getSAXLocator());
+ }
+ }
+
+ inlineFunctionVarMap.clear();
+ }
+
+ return resultSeq;
+ }
+
+}
diff --git a/src/org/apache/xpath/functions/FuncForEach.java b/src/org/apache/xpath/functions/FuncForEach.java
new file mode 100644
index 00000000..113b1335
--- /dev/null
+++ b/src/org/apache/xpath/functions/FuncForEach.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xpath.functions;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.utils.QName;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.LocPathIterator;
+import org.apache.xpath.objects.InlineFunction;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XObjectFactory;
+import org.apache.xpath.operations.Variable;
+import org.apache.xpath.res.XPATHErrorResources;
+import org.w3c.dom.Node;
+
+/**
+ * Execute the for-each() function.
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+/*
+ * fn:for-each is one of XPath 3.1's higher-order function
+ * (ref, https://www.w3.org/TR/xpath-functions-31/#higher-order-functions).
+ *
+ * The XPath function fn:for-each has following signature, and definition,
+ *
+ * fn:for-each($seq as item()*, $action as function(item()) as item()*) as item()*
+ *
+ * The function fn:for-each applies the function item $action to every item from
+ * the sequence $seq in turn, returning the concatenation of the resulting sequences
+ * in order.
+ */
+public class FuncForEach extends Function2Args {
+
+ private static final long serialVersionUID = 2912594883291006421L;
+
+ private static final String FUNCTION_NAME = "for-each()";
+
+ /**
+ * Execute the function. The function must return a valid object.
+ *
+ * @param xctxt The current execution context.
+ *
+ * @return A valid XObject.
+ *
+ * @throws javax.xml.transform.TransformerException
+ */
+ public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
+ {
+
+ XObject funcEvaluationResult = null;
+
+ final int contextNode = xctxt.getCurrentNode();
+
+ Expression arg0 = getArg0();
+ Expression arg1 = getArg1();
+
+ DTMIterator arg0DtmIterator = null;
+
+ XObject arg0XsObject = null;
+
+ if (arg0 instanceof LocPathIterator) {
+ arg0DtmIterator = arg0.asIterator(xctxt, contextNode);
+ }
+ else {
+ arg0XsObject = arg0.execute(xctxt, contextNode);
+ }
+
+ ResultSequence resultSeq = new ResultSequence();
+
+ if (arg1 instanceof InlineFunction) {
+ resultSeq = evaluateFnForEach(xctxt, arg0XsObject, arg0DtmIterator, (InlineFunction)arg1);
+ }
+ else if (arg1 instanceof Variable) {
+ XObject arg1VarValue = arg1.execute(xctxt);
+ if (arg1VarValue instanceof InlineFunction) {
+ resultSeq = evaluateFnForEach(xctxt, arg0XsObject, arg0DtmIterator, (InlineFunction)arg1VarValue);
+ }
+ else {
+ throw new javax.xml.transform.TransformerException("FORG0006 : The second argument to function call for-each(), "
+ + "is not a function item.", xctxt.getSAXLocator());
+ }
+ }
+ else {
+ throw new javax.xml.transform.TransformerException("FORG0006 : The second argument to function call for-each(), "
+ + "is not a function item.", xctxt.getSAXLocator());
+ }
+
+ funcEvaluationResult = resultSeq;
+
+ return funcEvaluationResult;
+ }
+
+ /**
+ * Check that the number of arguments passed to this function is correct.
+ *
+ * @param argNum The number of arguments that is being passed to the function.
+ *
+ * @throws WrongNumberArgsException
+ */
+ public void checkNumberArgs(int argNum) throws WrongNumberArgsException
+ {
+ if (argNum != 2) {
+ reportWrongNumberArgs();
+ }
+ }
+
+ /**
+ * Constructs and throws a WrongNumberArgException with the appropriate
+ * message for this function object.
+ *
+ * @throws WrongNumberArgsException
+ */
+ protected void reportWrongNumberArgs() throws WrongNumberArgsException {
+ throw new WrongNumberArgsException(XSLMessages.createXPATHMessage(
+ XPATHErrorResources.ER_TWO, null)); //"2"
+ }
+
+ /*
+ * Evaluate the function call fn:for-each.
+ */
+ private ResultSequence evaluateFnForEach(XPathContext xctxt, XObject arg0XsObject,
+ DTMIterator arg0DtmIterator, InlineFunction arg1)
+ throws TransformerException {
+
+ ResultSequence resultSeq = new ResultSequence();
+
+ List<String> funcParamNameList = arg1.getFuncParamNameList();
+ String funcBodyXPathExprStr = arg1.getFuncBodyXPathExprStr();
+
+ if (funcBodyXPathExprStr == null || "".equals(funcBodyXPathExprStr)) {
+ return resultSeq;
+ }
+
+ QName varQname = null;
+
+ if (funcParamNameList.size() == 1) {
+ varQname = new QName(funcParamNameList.get(0));
+ }
+
+ SourceLocator srcLocator = xctxt.getSAXLocator();
+
+ XPath xpathInlineFn = new XPath(funcBodyXPathExprStr, srcLocator, null, XPath.SELECT, null);
+
+ if (arg0XsObject instanceof ResultSequence) {
+ XPathContext xpathContextNew = new XPathContext(false);
+ Map<QName, XObject> inlineFunctionVarMap = xpathContextNew.getInlineFunctionVarMap();
+
+ ResultSequence inpResultSeq = (ResultSequence)arg0XsObject;
+ for (int idx = 0; idx < inpResultSeq.size(); idx++) {
+ XObject inpSeqItem = inpResultSeq.item(idx);
+ if (varQname != null) {
+ inlineFunctionVarMap.put(varQname, inpSeqItem);
+ }
+
+ XObject resultObj = xpathInlineFn.execute(xpathContextNew, DTM.NULL, null);
+ resultSeq.add(resultObj);
+ }
+
+ inlineFunctionVarMap.clear();
+ }
+ else if (arg0DtmIterator != null) {
+ Map<QName, XObject> inlineFunctionVarMap = xctxt.getInlineFunctionVarMap();
+
+ int dtmNodeHandle;
+ while (DTM.NULL != (dtmNodeHandle = arg0DtmIterator.nextNode())) {
+ DTM dtm = xctxt.getDTM(dtmNodeHandle);
+ Node node = dtm.getNode(dtmNodeHandle);
+ XObject xObject = XObjectFactory.create(node, xctxt);
+ if (varQname != null) {
+ inlineFunctionVarMap.put(varQname, xObject);
+ }
+
+ XObject resultObj = xpathInlineFn.execute(xctxt, dtmNodeHandle, null);
+ resultSeq.add(resultObj);
+ }
+
+ inlineFunctionVarMap.clear();
+ }
+
+ return resultSeq;
+ }
+
+}
diff --git a/src/org/apache/xpath/objects/InlineFunction.java b/src/org/apache/xpath/objects/InlineFunction.java
new file mode 100644
index 00000000..f9cf1c2b
--- /dev/null
+++ b/src/org/apache/xpath/objects/InlineFunction.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xpath.objects;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPathVisitor;
+
+/*
+ * The XalanJ xpath parser, creates and populates this object,
+ * as a representation of XPath 3.1 function item "inline function"
+ * definition within XPath expressions.
+ *
+ * The XPath 3.1 spec, defines function item "inline function" XPath
+ * expressions with following grammar,
+
+ InlineFunctionExpr ::= "function" "(" ParamList? ")" ("as" SequenceType)? FunctionBody
+
+ ParamList ::= Param ("," Param)*
+
+ Param ::= "$" EQName TypeDeclaration?
+
+ FunctionBody ::= EnclosedExpr
+
+ EnclosedExpr ::= "{" Expr? "}"
+
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+public class InlineFunction extends XObject {
+
+ private static final long serialVersionUID = 9219253671212483045L;
+
+ private List<String> funcParamNameList = new ArrayList<String>();
+
+ private String funcBodyXPathExprStr = null;
+
+ public List<String> getFuncParamNameList() {
+ return funcParamNameList;
+ }
+
+ public void setFuncParamNameList(List<String> funcParamNameList) {
+ this.funcParamNameList = funcParamNameList;
+ }
+
+ public String getFuncBodyXPathExprStr() {
+ return funcBodyXPathExprStr;
+ }
+
+ public void setFuncBodyXPathExprStr(String funcBodyXPathExprStr) {
+ this.funcBodyXPathExprStr = funcBodyXPathExprStr;
+ }
+
+ public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)
+ {
+ // no op
+ }
+
+}
diff --git a/src/org/apache/xpath/objects/ResultSequence.java b/src/org/apache/xpath/objects/ResultSequence.java
index ab4a8c4f..22f22ca5 100644
--- a/src/org/apache/xpath/objects/ResultSequence.java
+++ b/src/org/apache/xpath/objects/ResultSequence.java
@@ -23,7 +23,7 @@ import java.util.List;
import org.apache.xpath.xs.types.XSAnyType;
/**
- * This class represents, the XPath 3.1 data model sequences.
+ * This class represents, the XPath 3.1 data model sequence.
*
* @author Mukul Gandhi <mu...@apache.org>
*
@@ -33,7 +33,7 @@ public class ResultSequence extends XObject
{
static final long serialVersionUID = -5736721866747906182L;
- // the underlying list object, storing items of this result sequence
+ // the underlying list object, to store items of this result sequence
private List<XObject> rsList = new ArrayList<XObject>();
/*
@@ -41,6 +41,11 @@ public class ResultSequence extends XObject
*/
public ResultSequence() {}
+ public int getType()
+ {
+ return CLASS_RESULT_SEQUENCE;
+ }
+
public void add(XObject item) {
rsList.add(item);
}
diff --git a/src/org/apache/xpath/objects/XObject.java b/src/org/apache/xpath/objects/XObject.java
index d7f38c8b..de688eeb 100644
--- a/src/org/apache/xpath/objects/XObject.java
+++ b/src/org/apache/xpath/objects/XObject.java
@@ -210,6 +210,9 @@ public class XObject extends Expression implements Serializable, Cloneable
/** Constant for RESULT TREE FRAGMENT object type */
public static final int CLASS_RTREEFRAG = 5;
+
+ /** Constant for XPath 3.1 sequence object type */
+ public static final int CLASS_RESULT_SEQUENCE = 6;
/** Represents an unresolved variable type as an integer. */
public static final int CLASS_UNRESOLVEDVARIABLE = 600;
diff --git a/src/org/apache/xpath/operations/Mult.java b/src/org/apache/xpath/operations/Mult.java
index dd14f85e..39ae15f2 100644
--- a/src/org/apache/xpath/operations/Mult.java
+++ b/src/org/apache/xpath/operations/Mult.java
@@ -23,6 +23,7 @@ package org.apache.xpath.operations;
import org.apache.xpath.XPathContext;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.objects.XObject;
+import org.apache.xpath.xs.types.XSInteger;
/**
* The '*' operation expression executer.
@@ -45,7 +46,26 @@ public class Mult extends Operation
public XObject operate(XObject left, XObject right)
throws javax.xml.transform.TransformerException
{
- return new XNumber(left.num() * right.num());
+ XObject result = null;
+
+ if ((left instanceof XSInteger) && (right instanceof XSInteger)) {
+ result = ((XSInteger)left).multiply((XSInteger)right);
+ }
+ else if ((left instanceof XSInteger) && (right instanceof XNumber)) {
+ double lDouble = (((XSInteger)left).intValue()).doubleValue();
+ double rDouble = ((XNumber)right).num();
+ result = new XNumber(lDouble * rDouble);
+ }
+ else if ((left instanceof XNumber) && (right instanceof XSInteger)) {
+ double lDouble = ((XNumber)left).num();
+ double rDouble = (((XSInteger)right).intValue()).doubleValue();
+ result = new XNumber(lDouble * rDouble);
+ }
+ else {
+ result = new XNumber(left.num() * right.num());
+ }
+
+ return result;
}
/**
diff --git a/src/org/apache/xpath/operations/Variable.java b/src/org/apache/xpath/operations/Variable.java
index 39e8bf7f..1f247949 100644
--- a/src/org/apache/xpath/operations/Variable.java
+++ b/src/org/apache/xpath/operations/Variable.java
@@ -20,6 +20,8 @@
*/
package org.apache.xpath.operations;
+import java.util.Map;
+
import javax.xml.transform.TransformerException;
import org.apache.xalan.res.XSLMessages;
@@ -206,6 +208,17 @@ public class Variable extends Expression implements PathComponent
org.apache.xml.utils.PrefixResolver xprefixResolver = xctxt.getNamespaceContext();
XObject result;
+
+ Map<QName, XObject> inlineFunctionVarMap = xctxt.getInlineFunctionVarMap();
+ XObject inlineFuncVarValue = inlineFunctionVarMap.get(m_qname);
+
+ if (inlineFuncVarValue != null) {
+ // dereferencing, XPath 3.1 function item "inline function"
+ // parameter references within "inline function" body.
+ result = inlineFuncVarValue;
+ return result;
+ }
+
// Is the variable fetched always the same?
// XObject result = xctxt.getVariable(m_qname);
if(m_fixUpWasCalled)
diff --git a/src/org/apache/xpath/res/XPATHErrorResources.java b/src/org/apache/xpath/res/XPATHErrorResources.java
index eeed93a3..c28a9094 100644
--- a/src/org/apache/xpath/res/XPATHErrorResources.java
+++ b/src/org/apache/xpath/res/XPATHErrorResources.java
@@ -147,8 +147,14 @@ public class XPATHErrorResources extends ListResourceBundle
"ER_BOOLEAN_ARG_NO_LONGER_OPTIONAL";
public static final String ER_FOUND_COMMA_BUT_NO_PRECEDING_ARG =
"ER_FOUND_COMMA_BUT_NO_PRECEDING_ARG";
+ public static final String ER_FOUND_COMMA_BUT_NO_PRECEDING_PARAM =
+ "ER_FOUND_COMMA_BUT_NO_PRECEDING_PARAM";
public static final String ER_FOUND_COMMA_BUT_NO_FOLLOWING_ARG =
"ER_FOUND_COMMA_BUT_NO_FOLLOWING_ARG";
+ public static final String ER_FOUND_COMMA_BUT_NO_FOLLOWING_PARAM =
+ "ER_FOUND_COMMA_BUT_NO_FOLLOWING_PARAM";
+ public static final String ER_INLINE_FUNCTION_PARAM_CARDINALITY =
+ "ER_INLINE_FUNCTION_PARAM_CARDINALITY";
public static final String ER_PREDICATE_ILLEGAL_SYNTAX =
"ER_PREDICATE_ILLEGAL_SYNTAX";
public static final String ER_ILLEGAL_AXIS_NAME = "ER_ILLEGAL_AXIS_NAME";
@@ -230,9 +236,11 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
/** 0 */
public static final String ER_ZERO = "ER_ZERO";
/** 0 or 1 */
- public static final String ER_ZERO_OR_ONE = "ER_ZERO_OR_ONE";
+ public static final String ER_ZERO_OR_ONE = "ER_ZERO_OR_ONE";
/** 1 or 2 */
public static final String ER_ONE_OR_TWO = "ER_ONE_OR_TWO";
+ /** 2 */
+ public static final String ER_TWO = "ER_TWO";
/** 2 or 3 */
public static final String ER_TWO_OR_THREE = "ER_TWO_OR_THREE";
/** 1, 2 or 3 */
@@ -488,9 +496,18 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
{ ER_FOUND_COMMA_BUT_NO_PRECEDING_ARG,
"Found ',' but no preceding argument!"},
+
+ { ER_FOUND_COMMA_BUT_NO_PRECEDING_PARAM,
+ "Found ',' but no preceding function parameter definition."},
{ ER_FOUND_COMMA_BUT_NO_FOLLOWING_ARG,
"Found ',' but no following argument!"},
+
+ { ER_FOUND_COMMA_BUT_NO_FOLLOWING_PARAM,
+ "Found ',' but no following function parameter definition."},
+
+ { ER_INLINE_FUNCTION_PARAM_CARDINALITY,
+ "XPTY0004 : The inline function definition has {0} parameters. Expected 0 or 1."},
{ ER_PREDICATE_ILLEGAL_SYNTAX,
"'..[predicate]' or '.[predicate]' is illegal syntax. Use 'self::node()[predicate]' instead."},
@@ -645,6 +662,8 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED =
{ ER_ONE_OR_TWO,
"1 or 2"},
+ { ER_TWO, "2"},
+
{ ER_TWO_OR_THREE,
"2 or 3"},
diff --git a/src/org/apache/xpath/xs/types/XSInteger.java b/src/org/apache/xpath/xs/types/XSInteger.java
index 8232b066..48b8b420 100644
--- a/src/org/apache/xpath/xs/types/XSInteger.java
+++ b/src/org/apache/xpath/xs/types/XSInteger.java
@@ -140,6 +140,10 @@ public class XSInteger extends XSDecimal {
return (intValue()).compareTo(xsInteger.intValue()) > 0;
}
+ public XSInteger multiply(XSInteger xsInteger) {
+ return new XSInteger((intValue()).multiply(xsInteger.intValue()));
+ }
+
/*
* Cast an object of type XSAnyType, to an object of type
* java.math.BigInteger.
diff --git a/tests/fn_filter/gold/test1.out b/tests/fn_filter/gold/test1.out
new file mode 100644
index 00000000..3c56ffb9
--- /dev/null
+++ b/tests/fn_filter/gold/test1.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <one>1 2 3 4 5 6 7 8 9 10</one>
+ <two/>
+</result>
diff --git a/tests/fn_filter/gold/test2.out b/tests/fn_filter/gold/test2.out
new file mode 100644
index 00000000..934a2f81
--- /dev/null
+++ b/tests/fn_filter/gold/test2.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>7 8 9 10 11</result>
diff --git a/tests/fn_filter/gold/test3.out b/tests/fn_filter/gold/test3.out
new file mode 100644
index 00000000..2f966729
--- /dev/null
+++ b/tests/fn_filter/gold/test3.out
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <item weight="8">D</item>
+ <item weight="9">E</item>
+ <item weight="10">F</item>
+ <item weight="11">G</item>
+ <item weight="12">H</item>
+ <item weight="13">I</item>
+ <item weight="14">J</item>
+</result>
diff --git a/tests/fn_filter/test1.xsl b/tests/fn_filter/test1.xsl
new file mode 100644
index 00000000..b9c10630
--- /dev/null
+++ b/tests/fn_filter/test1.xsl
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- Test for the XPath 3.1 fn:filter() function -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <one><xsl:value-of select="filter(1 to 10, function($a) { true() })"/></one>
+ <two><xsl:value-of select="filter(1 to 10, function($a) { false() })"/></two>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_filter/test1_a.xml b/tests/fn_filter/test1_a.xml
new file mode 100644
index 00000000..e5a0110a
--- /dev/null
+++ b/tests/fn_filter/test1_a.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<elem>
+ <a>5</a>
+ <a>6</a>
+ <a>7</a>
+ <a>8</a>
+ <a>9</a>
+ <a>10</a>
+ <a>11</a>
+</elem>
\ No newline at end of file
diff --git a/tests/fn_filter/test1_b.xml b/tests/fn_filter/test1_b.xml
new file mode 100644
index 00000000..c4fc37e9
--- /dev/null
+++ b/tests/fn_filter/test1_b.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<elem>
+ <item weight="5">A</item>
+ <item weight="6">B</item>
+ <item weight="7">C</item>
+ <item weight="8">D</item>
+ <item weight="9">E</item>
+ <item weight="10">F</item>
+ <item weight="11">G</item>
+ <item weight="12">H</item>
+ <item weight="13">I</item>
+ <item weight="14">J</item>
+</elem>
\ No newline at end of file
diff --git a/tests/fn_filter/test2.xsl b/tests/fn_filter/test2.xsl
new file mode 100644
index 00000000..b87084b5
--- /dev/null
+++ b/tests/fn_filter/test2.xsl
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- use with test1_a.xml -->
+
+ <!-- Test for the XPath 3.1 fn:filter() function -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/elem">
+ <result>
+ <xsl:value-of select="filter(a, function($a) { $a > 6 })"/>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_filter/test3.xsl b/tests/fn_filter/test3.xsl
new file mode 100644
index 00000000..289d5bc7
--- /dev/null
+++ b/tests/fn_filter/test3.xsl
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- use with test1_b.xml -->
+
+ <!-- Test for the XPath 3.1 fn:filter() function -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/elem">
+ <result>
+ <xsl:variable name="filteredElems" select="filter(item, function($x) { $x/@weight > 7 })"/>
+ <xsl:copy-of select="$filteredElems"/>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_foreach/gold/test1.out b/tests/fn_foreach/gold/test1.out
new file mode 100644
index 00000000..8e0ac138
--- /dev/null
+++ b/tests/fn_foreach/gold/test1.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>1 4 9 16 25</result>
diff --git a/tests/fn_foreach/gold/test2.out b/tests/fn_foreach/gold/test2.out
new file mode 100644
index 00000000..15879861
--- /dev/null
+++ b/tests/fn_foreach/gold/test2.out
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <num>8</num>
+ <num>9</num>
+ <num>10</num>
+ <num>11</num>
+ <num>12</num>
+ <num>13</num>
+ <num>14</num>
+</result>
diff --git a/tests/fn_foreach/gold/test3.out b/tests/fn_foreach/gold/test3.out
new file mode 100644
index 00000000..e1735cfa
--- /dev/null
+++ b/tests/fn_foreach/gold/test3.out
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <trfItems>
+ <item>A_5</item>
+ <item>B_6</item>
+ <item>C_7</item>
+ <item>D_8</item>
+ <item>E_9</item>
+ <item>F_10</item>
+ <item>G_11</item>
+ <item>H_12</item>
+ <item>I_13</item>
+ <item>J_14</item>
+ </trfItems>
+</result>
diff --git a/tests/fn_foreach/gold/test4.out b/tests/fn_foreach/gold/test4.out
new file mode 100644
index 00000000..15879861
--- /dev/null
+++ b/tests/fn_foreach/gold/test4.out
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <num>8</num>
+ <num>9</num>
+ <num>10</num>
+ <num>11</num>
+ <num>12</num>
+ <num>13</num>
+ <num>14</num>
+</result>
diff --git a/tests/fn_foreach/gold/test5.out b/tests/fn_foreach/gold/test5.out
new file mode 100644
index 00000000..dbce52d5
--- /dev/null
+++ b/tests/fn_foreach/gold/test5.out
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <result1>
+ <num>8</num>
+ <num>9</num>
+ <num>10</num>
+ <num>11</num>
+ <num>12</num>
+ <num>13</num>
+ <num>14</num>
+ </result1>
+ <result2>
+ <num>8</num>
+ <num>9</num>
+ <num>10</num>
+ <num>11</num>
+ <num>12</num>
+ <num>13</num>
+ <num>14</num>
+ </result2>
+</result>
diff --git a/tests/fn_foreach/gold/test6.out b/tests/fn_foreach/gold/test6.out
new file mode 100644
index 00000000..4ebb723c
--- /dev/null
+++ b/tests/fn_foreach/gold/test6.out
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <num>1</num>
+ <num>4</num>
+ <num>9</num>
+ <num>16</num>
+ <num>25</num>
+</result>
diff --git a/tests/fn_foreach/gold/test7.out b/tests/fn_foreach/gold/test7.out
new file mode 100644
index 00000000..c14bdf18
--- /dev/null
+++ b/tests/fn_foreach/gold/test7.out
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <num>2</num>
+ <num>4</num>
+ <num>6</num>
+ <num>8</num>
+ <num>10</num>
+</result>
diff --git a/tests/fn_foreach/gold/test8.out b/tests/fn_foreach/gold/test8.out
new file mode 100644
index 00000000..2b3f3b27
--- /dev/null
+++ b/tests/fn_foreach/gold/test8.out
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+ <num>3</num>
+ <num>6</num>
+ <num>9</num>
+ <num>12</num>
+ <num>15</num>
+</result>
diff --git a/tests/fn_foreach/test1.xsl b/tests/fn_foreach/test1.xsl
new file mode 100644
index 00000000..8186af09
--- /dev/null
+++ b/tests/fn_foreach/test1.xsl
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- Test for the XPath 3.1 fn:for-each() function -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <xsl:value-of select="for-each(1 to 5, function($a) { $a * $a })"/>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_foreach/test1_a.xml b/tests/fn_foreach/test1_a.xml
new file mode 100644
index 00000000..e5a0110a
--- /dev/null
+++ b/tests/fn_foreach/test1_a.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<elem>
+ <a>5</a>
+ <a>6</a>
+ <a>7</a>
+ <a>8</a>
+ <a>9</a>
+ <a>10</a>
+ <a>11</a>
+</elem>
\ No newline at end of file
diff --git a/tests/fn_foreach/test1_b.xml b/tests/fn_foreach/test1_b.xml
new file mode 100644
index 00000000..c4fc37e9
--- /dev/null
+++ b/tests/fn_foreach/test1_b.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<elem>
+ <item weight="5">A</item>
+ <item weight="6">B</item>
+ <item weight="7">C</item>
+ <item weight="8">D</item>
+ <item weight="9">E</item>
+ <item weight="10">F</item>
+ <item weight="11">G</item>
+ <item weight="12">H</item>
+ <item weight="13">I</item>
+ <item weight="14">J</item>
+</elem>
\ No newline at end of file
diff --git a/tests/fn_foreach/test2.xsl b/tests/fn_foreach/test2.xsl
new file mode 100644
index 00000000..57f2fae7
--- /dev/null
+++ b/tests/fn_foreach/test2.xsl
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- use with test1_a.xml -->
+
+ <!-- Test for the XPath 3.1 fn:for-each() function -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/elem">
+ <result>
+ <xsl:for-each select="for-each(a, function($x) { $x + 3 })">
+ <num><xsl:value-of select="."/></num>
+ </xsl:for-each>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_foreach/test3.xsl b/tests/fn_foreach/test3.xsl
new file mode 100644
index 00000000..4354104b
--- /dev/null
+++ b/tests/fn_foreach/test3.xsl
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- use with test1_b.xml -->
+
+ <!-- Test for the XPath 3.1 fn:for-each() function -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/elem">
+ <result>
+ <trfItems>
+ <xsl:for-each select="for-each(item, function($a) { concat(string($a), '_', $a/@weight) })">
+ <item><xsl:value-of select="."/></item>
+ </xsl:for-each>
+ </trfItems>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_foreach/test4.xsl b/tests/fn_foreach/test4.xsl
new file mode 100644
index 00000000..e60afe77
--- /dev/null
+++ b/tests/fn_foreach/test4.xsl
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- use with test1_a.xml -->
+
+ <!-- Test for the XPath 3.1 fn:for-each() function.
+ Within this stylesheet, we use a function item variable
+ reference as an argument to the fn:for-each() function
+ call.
+ -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:variable name="func1" select="function($x) { $x + 3 }"/>
+
+ <xsl:template match="/elem">
+ <result>
+ <xsl:for-each select="for-each(a, $func1)">
+ <num><xsl:value-of select="."/></num>
+ </xsl:for-each>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_foreach/test5.xsl b/tests/fn_foreach/test5.xsl
new file mode 100644
index 00000000..db56a071
--- /dev/null
+++ b/tests/fn_foreach/test5.xsl
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- use with test1_a.xml -->
+
+ <!-- Test for the XPath 3.1 fn:for-each() function.
+ Within this stylesheet, we use a function item variable
+ reference as an argument to the fn:for-each() function
+ call. We use the, same function item variable reference,
+ on more than one fn:for-each() function call.
+ -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:variable name="func1" select="function($x) { $x + 3 }"/>
+
+ <xsl:template match="/elem">
+ <result>
+ <result1>
+ <xsl:for-each select="for-each(a, $func1)">
+ <num><xsl:value-of select="."/></num>
+ </xsl:for-each>
+ </result1>
+ <result2>
+ <xsl:for-each select="for-each(a, $func1)">
+ <num><xsl:value-of select="."/></num>
+ </xsl:for-each>
+ </result2>
+ </result>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_foreach/test6.xsl b/tests/fn_foreach/test6.xsl
new file mode 100644
index 00000000..dd14494d
--- /dev/null
+++ b/tests/fn_foreach/test6.xsl
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- Test for the XPath 3.1 fn:for-each() function -->
+
+ <!-- This XSLT stylesheet tests, passing an XPath function
+ item as a template parameter argument. -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <xsl:call-template name="Template1">
+ <xsl:with-param name="funcDefn" select="function($x) { $x * $x }"/>
+ <xsl:with-param name="idx1" select="1"/>
+ <xsl:with-param name="idx2" select="5"/>
+ </xsl:call-template>
+ </result>
+ </xsl:template>
+
+ <xsl:template name="Template1">
+ <xsl:param name="funcDefn"/>
+ <xsl:param name="idx1"/>
+ <xsl:param name="idx2"/>
+
+ <xsl:for-each select="for-each($idx1 to $idx2, $funcDefn)">
+ <num><xsl:value-of select="."/></num>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_foreach/test7.xsl b/tests/fn_foreach/test7.xsl
new file mode 100644
index 00000000..60eeccb6
--- /dev/null
+++ b/tests/fn_foreach/test7.xsl
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- Test for the XPath 3.1 fn:for-each() function -->
+
+ <!-- This XSLT stylesheet tests, passing an XPath function
+ item as a template parameter argument. -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <xsl:call-template name="Template1">
+ <xsl:with-param name="funcDefn" select="function($x) { $x * 2 }"/>
+ <xsl:with-param name="idx1" select="1"/>
+ <xsl:with-param name="idx2" select="5"/>
+ </xsl:call-template>
+ </result>
+ </xsl:template>
+
+ <xsl:template name="Template1">
+ <xsl:param name="funcDefn"/>
+ <xsl:param name="idx1"/>
+ <xsl:param name="idx2"/>
+
+ <xsl:for-each select="for-each($idx1 to $idx2, $funcDefn)">
+ <num><xsl:value-of select="."/></num>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_foreach/test8.xsl b/tests/fn_foreach/test8.xsl
new file mode 100644
index 00000000..de555b47
--- /dev/null
+++ b/tests/fn_foreach/test8.xsl
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="3.0">
+
+ <!-- Author: mukulg@apache.org -->
+
+ <!-- Test for the XPath 3.1 fn:for-each() function -->
+
+ <!-- This XSLT stylesheet tests, passing an XPath function
+ item as a template parameter argument. -->
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <result>
+ <xsl:call-template name="Template1">
+ <xsl:with-param name="funcDefn" select="function($x) { 3 * $x }"/>
+ <xsl:with-param name="idx1" select="1"/>
+ <xsl:with-param name="idx2" select="5"/>
+ </xsl:call-template>
+ </result>
+ </xsl:template>
+
+ <xsl:template name="Template1">
+ <xsl:param name="funcDefn"/>
+ <xsl:param name="idx1"/>
+ <xsl:param name="idx2"/>
+
+ <xsl:for-each select="for-each($idx1 to $idx2, $funcDefn)">
+ <num><xsl:value-of select="."/></num>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/org/apache/xalan/xpath3/FnFilterTests.java b/tests/org/apache/xalan/xpath3/FnFilterTests.java
new file mode 100644
index 00000000..12546eb3
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/FnFilterTests.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xalan.xpath3;
+
+import org.apache.xalan.util.XslTransformTestsUtil;
+import org.apache.xalan.xslt3.XSLConstants;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * XPath 3.1 function fn:filter test cases.
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+public class FnFilterTests extends XslTransformTestsUtil {
+
+ private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "fn_filter/";
+
+ private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "fn_filter/gold/";
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ // no op
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ xmlDocumentBuilderFactory = null;
+ xmlDocumentBuilder = null;
+ xslTransformerFactory = null;
+ }
+
+ @Test
+ public void xslFnFilterTest1() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test1.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslFnFilterTest2() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslFnFilterTest3() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+}
diff --git a/tests/org/apache/xalan/xpath3/FnForEachTests.java b/tests/org/apache/xalan/xpath3/FnForEachTests.java
new file mode 100644
index 00000000..07bf68fb
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/FnForEachTests.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xalan.xpath3;
+
+import org.apache.xalan.util.XslTransformTestsUtil;
+import org.apache.xalan.xslt3.XSLConstants;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * XPath 3.1 function fn:for-each test cases.
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ *
+ * @xsl.usage advanced
+ */
+public class FnForEachTests extends XslTransformTestsUtil {
+
+ private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "fn_foreach/";
+
+ private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "fn_foreach/gold/";
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ // no op
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ xmlDocumentBuilderFactory = null;
+ xmlDocumentBuilder = null;
+ xslTransformerFactory = null;
+ }
+
+ @Test
+ public void xslFnForEachTest1() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test1.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslFnForEachTest2() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslFnForEachTest3() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test3.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslFnForEachTest4() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test4.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslFnForEachTest5() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test5.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslFnForEachTest6() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test6.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test6.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test6.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslFnForEachTest7() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test7.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test7.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test7.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+ @Test
+ public void xslFnForEachTest8() {
+ String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test8.xsl";
+ String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test8.xsl";
+
+ String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test8.out";
+
+ runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+ }
+
+}
diff --git a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
index cf777bba..26604646 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -17,6 +17,8 @@
package org.apache.xalan.xslt3;
import org.apache.xalan.xpath3.FnAbsTests;
+import org.apache.xalan.xpath3.FnFilterTests;
+import org.apache.xalan.xpath3.FnForEachTests;
import org.apache.xalan.xpath3.FnIndexOfTests;
import org.apache.xalan.xpath3.FnStringJoinTests;
import org.apache.xalan.xpath3.FnTokenizeTests;
@@ -49,7 +51,7 @@ import org.junit.runners.Suite.SuiteClasses;
FnAbsTests.class, StringTests.class, XsConstructorFunctions.class,
FnIndexOfTests.class, SequenceTests.class, RangeExprTests.class,
W3c_xslt30_IterateTests.class, W3c_xslt30_AxesTests.class, XslIterateTests.class,
- ValueComparisonTests.class })
+ ValueComparisonTests.class, FnForEachTests.class, FnFilterTests.class })
public class AllXsl3Tests {
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org