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/08/11 16:00:32 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xpath 3.1 function fn:for-each-pair, and few new working related test cases as well. doing minor related codebase refactoring as well, and enhancements to few related areas of xalanj codebase on this branch.

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 afe9bce4 committing implementation of xpath 3.1 function fn:for-each-pair, and few new working related test cases as well. doing minor related codebase refactoring as well, and enhancements to few related areas of xalanj codebase on this branch.
     new 1bf8f855 Merge pull request #48 from mukulga/xalan-j_xslt3.0_mukul
afe9bce4 is described below

commit afe9bce461232cf0a572070084fea181b19b85a7
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Fri Aug 11 21:26:35 2023 +0530

    committing implementation of xpath 3.1 function fn:for-each-pair, and few new working related test cases as well. doing minor related codebase refactoring as well, and enhancements to few related areas of xalanj codebase on this branch.
---
 src/org/apache/xpath/compiler/FunctionTable.java   |  34 ++--
 src/org/apache/xpath/compiler/Keywords.java        |  19 ++-
 src/org/apache/xpath/functions/FuncFoldLeft.java   | 180 +++++++--------------
 src/org/apache/xpath/functions/FuncFoldRight.java  | 177 +++++++-------------
 .../apache/xpath/functions/FuncForEachPair.java    | 173 ++++++++++++++++++++
 .../XPathHigherOrderBuiltinFunctionsSupport.java   | 139 ++++++++++++++++
 src/org/apache/xpath/operations/Plus.java          |  40 ++++-
 tests/fn_fold_left/gold/test1.out                  |   1 +
 tests/fn_fold_left/test1.xsl                       |  34 ++--
 tests/fn_fold_right/gold/test1.out                 |   1 +
 tests/fn_fold_right/test1.xsl                      |  11 +-
 tests/fn_for_each_pair/gold/test1.out              |   7 +
 tests/fn_for_each_pair/gold/test2.out              |   6 +
 .../{fn_fold_right => fn_for_each_pair}/test1.xsl  |  30 +++-
 tests/fn_for_each_pair/test1_a.xml                 |  16 ++
 .../test1.xsl => fn_for_each_pair/test2.xsl}       |  20 ++-
 .../apache/xalan/xpath3/FnForEachPairTests.java    |  72 +++++++++
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java     |   3 +-
 18 files changed, 658 insertions(+), 305 deletions(-)

diff --git a/src/org/apache/xpath/compiler/FunctionTable.java b/src/org/apache/xpath/compiler/FunctionTable.java
index 9e26f9e2..b1cd5c39 100644
--- a/src/org/apache/xpath/compiler/FunctionTable.java
+++ b/src/org/apache/xpath/compiler/FunctionTable.java
@@ -257,6 +257,9 @@ public class FunctionTable
   
   /** The 'fold-right()' id. */
   public static final int FUNC_FOLD_RIGHT = 77;
+  
+  /** The 'for-each-pair()' id. */
+  public static final int FUNC_FOR_EACH_PAIR = 78;
 
   // Proprietary
 
@@ -314,7 +317,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 = 78;
+  private static final int NUM_BUILT_IN_FUNCS = 79;
 
   /**
    * Number of built-in functions that may be added.
@@ -411,7 +414,10 @@ public class FunctionTable
     m_functions[FUNC_IMPLICIT_TIMEZONE] = 
       org.apache.xpath.functions.FuncImplicitTimezone.class;
     m_functions[FUNC_INDEX_OF] = 
-      org.apache.xpath.functions.FuncIndexOf.class;
+      org.apache.xpath.functions.FuncIndexOf.class;        
+    m_functions[FUNC_DISTINCT_VALUES] = 
+      org.apache.xpath.functions.FuncDistinctValues.class;
+    
     m_functions[FUNC_FOR_EACH] = 
       org.apache.xpath.functions.FuncForEach.class;
     m_functions[FUNC_FILTER] = 
@@ -420,8 +426,8 @@ public class FunctionTable
       org.apache.xpath.functions.FuncFoldLeft.class;
     m_functions[FUNC_FOLD_RIGHT] = 
       org.apache.xpath.functions.FuncFoldRight.class;
-    m_functions[FUNC_DISTINCT_VALUES] = 
-      org.apache.xpath.functions.FuncDistinctValues.class;
+    m_functions[FUNC_FOR_EACH_PAIR] = 
+      org.apache.xpath.functions.FuncForEachPair.class;
     
     // XPath 3.1 functions configurations for the math functions 
     // namespace http://www.w3.org/2005/xpath-functions/math.
@@ -572,13 +578,20 @@ public class FunctionTable
           m_functionID.put(Keywords.FUNC_IMPLICIT_TIMEZONE,
                           new Integer(FunctionTable.FUNC_IMPLICIT_TIMEZONE));
           m_functionID.put(Keywords.FUNC_INDEX_OF,
-                          new Integer(FunctionTable.FUNC_INDEX_OF));
+                          new Integer(FunctionTable.FUNC_INDEX_OF));          
+          m_functionID.put(Keywords.FUNC_DISTINCT_VALUES,
+                          new Integer(FunctionTable.FUNC_DISTINCT_VALUES));
+          
           m_functionID.put(Keywords.FUNC_FOR_EACH,
                           new Integer(FunctionTable.FUNC_FOR_EACH));
           m_functionID.put(Keywords.FUNC_FILTER,
                           new Integer(FunctionTable.FUNC_FILTER));
-          m_functionID.put(Keywords.FUNC_DISTINCT_VALUES,
-                          new Integer(FunctionTable.FUNC_DISTINCT_VALUES));
+          m_functionID.put(Keywords.FUNC_FOLD_LEFT,
+                          new Integer(FunctionTable.FUNC_FOLD_LEFT));
+          m_functionID.put(Keywords.FUNC_FOLD_RIGHT,
+                          new Integer(FunctionTable.FUNC_FOLD_RIGHT));
+          m_functionID.put(Keywords.FUNC_FOR_EACH_PAIR,
+                          new Integer(FunctionTable.FUNC_FOR_EACH_PAIR));
           
           // XPath 3.1 functions configurations for the math functions 
           // namespace http://www.w3.org/2005/xpath-functions/math.
@@ -624,12 +637,7 @@ public class FunctionTable
          m_functionID.put(Keywords.FUNC_MINUTES_FROM_DURATION,
                          new Integer(FunctionTable.FUNC_MINUTES_FROM_DURATION));
          m_functionID.put(Keywords.FUNC_SECONDS_FROM_DURATION,
-                         new Integer(FunctionTable.FUNC_SECONDS_FROM_DURATION));
-         
-         m_functionID.put(Keywords.FUNC_FOLD_LEFT,
-                         new Integer(FunctionTable.FUNC_FOLD_LEFT));
-         m_functionID.put(Keywords.FUNC_FOLD_RIGHT,
-                         new Integer(FunctionTable.FUNC_FOLD_RIGHT));
+                         new Integer(FunctionTable.FUNC_SECONDS_FROM_DURATION));         
   }
   
   public FunctionTable(){
diff --git a/src/org/apache/xpath/compiler/Keywords.java b/src/org/apache/xpath/compiler/Keywords.java
index d5732a83..8b639a32 100644
--- a/src/org/apache/xpath/compiler/Keywords.java
+++ b/src/org/apache/xpath/compiler/Keywords.java
@@ -260,14 +260,23 @@ public class Keywords
   /** index-of function string. */
   public static final String FUNC_INDEX_OF = "index-of";
   
+  /** distinct-values function string. */
+  public static final String FUNC_DISTINCT_VALUES = "distinct-values";
+  
   /** for-each function string. */
   public static final String FUNC_FOR_EACH = "for-each";
   
   /** filter function string. */
   public static final String FUNC_FILTER = "filter";
   
-  /** distinct-values function string. */
-  public static final String FUNC_DISTINCT_VALUES = "distinct-values";
+  /** fold-left function string. */
+  public static final String FUNC_FOLD_LEFT = "fold-left";
+  
+  /** fold-right function string. */
+  public static final String FUNC_FOLD_RIGHT = "fold-right";
+  
+  /** for-each-pair function string. */
+  public static final String FUNC_FOR_EACH_PAIR = "for-each-pair";
   
   /** math:pi function string. */
   public static final String FUNC_MATH_PI = "pi";
@@ -329,12 +338,6 @@ public class Keywords
   /** seconds-from-duration function string. */
   public static final String FUNC_SECONDS_FROM_DURATION = "seconds-from-duration";
   
-  /** fold-left function string. */
-  public static final String FUNC_FOLD_LEFT = "fold-left";
-  
-  /** fold-right function string. */
-  public static final String FUNC_FOLD_RIGHT = "fold-right";
-  
   // XML Schema built-in data type name keywords
   
   /** xs:decimal data type string. */
diff --git a/src/org/apache/xpath/functions/FuncFoldLeft.java b/src/org/apache/xpath/functions/FuncFoldLeft.java
index f67ef65b..9c147dbf 100644
--- a/src/org/apache/xpath/functions/FuncFoldLeft.java
+++ b/src/org/apache/xpath/functions/FuncFoldLeft.java
@@ -24,21 +24,13 @@ import javax.xml.transform.SourceLocator;
 import org.apache.xalan.templates.ElemTemplateElement;
 import org.apache.xalan.templates.XMLNSDecl;
 import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
-import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMManager;
 import org.apache.xml.utils.QName;
 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.XNodeSet;
 import org.apache.xpath.objects.XObject;
-import org.apache.xpath.operations.Range;
 import org.apache.xpath.operations.Variable;
-import org.apache.xpath.xs.types.XSUntyped;
-import org.apache.xpath.xs.types.XSUntypedAtomic;
 
 /**
  * Implementation of the fold-left() function.
@@ -61,152 +53,92 @@ import org.apache.xpath.xs.types.XSUntypedAtomic;
  * applying the supplied function repeatedly to each item in turn, together
  * with an accumulated result value.
  */
-public class FuncFoldLeft extends Function3Args {
+public class FuncFoldLeft extends XPathHigherOrderBuiltinFunctionsSupport {
     
     private static final long serialVersionUID = -3772850377799360556L;
 
     public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
     {
-        XObject result = null;
+        XObject evalResult = new ResultSequence();
         
         SourceLocator srcLocator = xctxt.getSAXLocator();
         
         int contextNode = xctxt.getContextNode();
         
-        ResultSequence foldLeftFirstArgResultSeq = null;
+        ResultSequence foldLeftFirstArgResultSeq = constructXDMSequenceFromXPathExpression(m_arg0, xctxt);
         
-        if (m_arg0 instanceof Range) {
-           foldLeftFirstArgResultSeq = (ResultSequence)(((Range)m_arg0).execute(xctxt));    
-        }
-        else if (m_arg0 instanceof Variable) {
-           XObject xObj = ((Variable)m_arg0).execute(xctxt);
-           
-           if (xObj instanceof XNodeSet) {
-               foldLeftFirstArgResultSeq = new ResultSequence();
-               
-               DTMManager dtmMgr = (DTMManager)xctxt;
-               
-               XNodeSet xNodeSet = (XNodeSet)xObj;           
-               DTMIterator sourceNodes = xNodeSet.iter();
-               
-               int nextNodeDtmHandle;
-               
-               while ((nextNodeDtmHandle = sourceNodes.nextNode()) != DTM.NULL) {
-                  XNodeSet xNodeSetItem = new XNodeSet(nextNodeDtmHandle, dtmMgr);
-                  String nodeStrValue = xNodeSetItem.str();
-                  
-                  DTM dtm = dtmMgr.getDTM(nextNodeDtmHandle);
-                  
-                  if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
-                     XSUntyped xsUntyped = new XSUntyped(nodeStrValue);                 
-                     XslTransformEvaluationHelper.addItemToResultSequence(foldLeftFirstArgResultSeq, 
-                                                                                            xsUntyped, true);
-                  }
-                  else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
-                     XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                     XslTransformEvaluationHelper.addItemToResultSequence(foldLeftFirstArgResultSeq, 
-                                                                                            xsUntypedAtomic, true);
-                  }
-                  else {
-                     XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                     XslTransformEvaluationHelper.addItemToResultSequence(foldLeftFirstArgResultSeq, 
-                                                                                            xsUntypedAtomic, true);
-                  }
-               }       
-           }
-           else if (xObj instanceof ResultSequence) {
-              foldLeftFirstArgResultSeq = (ResultSequence)xObj; 
+        XObject foldLeftBaseVal = m_arg1.execute(xctxt);
+        
+        InlineFunction foldLeftThirdArg = null;
+        
+        if (m_arg2 instanceof Variable) {
+           XObject arg2XObj = m_arg2.execute(xctxt);
+           if (arg2XObj instanceof InlineFunction) {
+              foldLeftThirdArg = (InlineFunction)arg2XObj;
            }
            else {
-              // REVISIT
-              foldLeftFirstArgResultSeq = new ResultSequence();
-              foldLeftFirstArgResultSeq.add(xObj);
+               QName varQname = (((Variable)m_arg2).getElemVariable()).getName();
+               throw new javax.xml.transform.TransformerException("FORG0006 : The third argument to function call "
+                                                                        + "fn:fold-left is a variable reference '" + 
+                                                                           varQname.getLocalName() + "', that cannot be "
+                                                                        + "evaluated to a function item.", srcLocator);  
            }
+        }        
+        else if (m_arg2 instanceof InlineFunction) {
+           foldLeftThirdArg = (InlineFunction)m_arg2;                                           
         }
-        else if (m_arg0 instanceof LocPathIterator) {
-            foldLeftFirstArgResultSeq = new ResultSequence();
-            
-            DTMManager dtmMgr = (DTMManager)xctxt;        
-            DTMIterator arg0DtmIterator = m_arg0.asIterator(xctxt, contextNode);        
-            
-            int nextNodeDtmHandle;
-            
-            while ((nextNodeDtmHandle = arg0DtmIterator.nextNode()) != DTM.NULL) {
-                XNodeSet xNodeSetItem = new XNodeSet(nextNodeDtmHandle, dtmMgr);            
-                String nodeStrValue = xNodeSetItem.str();
-                
-                DTM dtm = dtmMgr.getDTM(nextNodeDtmHandle);
-                
-                if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
-                   XSUntyped xsUntyped = new XSUntyped(nodeStrValue);
-                   foldLeftFirstArgResultSeq.add(xsUntyped);
-                }
-                else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
-                   XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                   foldLeftFirstArgResultSeq.add(xsUntypedAtomic);
-                }
-                else {
-                   XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                   foldLeftFirstArgResultSeq.add(xsUntypedAtomic);
-                }                        
-            }
+        else {
+           throw new javax.xml.transform.TransformerException("FORG0006 : The third argument to function call "
+                                                                     + "fn:fold-left is not a function item, or cannot be "
+                                                                     + "coerced to a function item.", srcLocator);
         }
-        
-        XObject foldLeftBaseVal = m_arg1.execute(xctxt);
-        
-        InlineFunction foldLeftThirdArg = null;
-        
-        if (m_arg2 instanceof InlineFunction) {
-           foldLeftThirdArg = (InlineFunction)m_arg2;
            
-           String inlineFnXPathStr = foldLeftThirdArg.getFuncBodyXPathExprStr();
-           List<String> funcParamNameList = foldLeftThirdArg.getFuncParamNameList();
+        String inlineFnXPathStr = foldLeftThirdArg.getFuncBodyXPathExprStr();
+        List<String> funcParamNameList = foldLeftThirdArg.getFuncParamNameList();
            
-           if (funcParamNameList.size() == 2) {              
-              String funcItemFirstArgName = funcParamNameList.get(0);
-              String funcItemSecondArgName = funcParamNameList.get(1);
+        if (funcParamNameList.size() == 2) {              
+           String funcItemFirstArgName = funcParamNameList.get(0);
+           String funcItemSecondArgName = funcParamNameList.get(1);
               
-              ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();
-              List<XMLNSDecl> prefixTable = null;
-              if (elemTemplateElement != null) {
-                  prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
-              }
+           ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();
+           List<XMLNSDecl> prefixTable = null;
+           if (elemTemplateElement != null) {
+              prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
+           }
               
-              if (prefixTable != null) {
-                 inlineFnXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(
-                                                                                        inlineFnXPathStr, prefixTable);
-              }
+           if (prefixTable != null) {
+              inlineFnXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(
+                                                                                            inlineFnXPathStr, prefixTable);
+           }
               
-              XPath inlineFuncXPath = new XPath(inlineFnXPathStr, srcLocator, xctxt.getNamespaceContext(), 
+           XPath inlineFuncXPath = new XPath(inlineFnXPathStr, srcLocator, xctxt.getNamespaceContext(), 
                                                                                               XPath.SELECT, null);              
-              for (int idx = 0; idx < foldLeftFirstArgResultSeq.size(); idx++) {
-                 Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
+           for (int idx = 0; idx < foldLeftFirstArgResultSeq.size(); idx++) {
+              Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
                  
-                 inlineFunctionVarMap.put(new QName(funcItemSecondArgName), foldLeftFirstArgResultSeq.item(idx));
+              inlineFunctionVarMap.put(new QName(funcItemSecondArgName), foldLeftFirstArgResultSeq.item(idx));
               
-                 if (idx == 0) {                    
-                    inlineFunctionVarMap.put(new QName(funcItemFirstArgName), foldLeftBaseVal);
-                 }
-                 else {
-                    inlineFunctionVarMap.put(new QName(funcItemFirstArgName), result);                   
-                 }
+              if (idx == 0) {                    
+                 inlineFunctionVarMap.put(new QName(funcItemFirstArgName), foldLeftBaseVal);
+              }
+              else {
+                 inlineFunctionVarMap.put(new QName(funcItemFirstArgName), evalResult);                   
+              }
                  
-                 result = inlineFuncXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
+              evalResult = inlineFuncXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
                  
-                 // Reset the function item argument variables
-                 inlineFunctionVarMap.put(new QName(funcItemFirstArgName), null);
-                 inlineFunctionVarMap.put(new QName(funcItemSecondArgName), null);
-              }
-           }
-           else {
-              result = new ResultSequence();  
-           }
+              // Reset the function item argument variables
+              inlineFunctionVarMap.put(new QName(funcItemFirstArgName), null);
+              inlineFunctionVarMap.put(new QName(funcItemSecondArgName), null);
+            }
         }
         else {
-           result = new ResultSequence(); 
+           throw new javax.xml.transform.TransformerException("XPTY0004 : An inline function definition argument to "
+                                                                    + "function fn:fold-left has " + funcParamNameList.size() + " "
+                                                                    + "parameters. Expected 2.", srcLocator); 
         }
         
-        return result;
+        return evalResult;
     }
 
 }
diff --git a/src/org/apache/xpath/functions/FuncFoldRight.java b/src/org/apache/xpath/functions/FuncFoldRight.java
index 0242122c..3852ee83 100644
--- a/src/org/apache/xpath/functions/FuncFoldRight.java
+++ b/src/org/apache/xpath/functions/FuncFoldRight.java
@@ -24,21 +24,13 @@ import javax.xml.transform.SourceLocator;
 import org.apache.xalan.templates.ElemTemplateElement;
 import org.apache.xalan.templates.XMLNSDecl;
 import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
-import org.apache.xml.dtm.DTM;
-import org.apache.xml.dtm.DTMIterator;
-import org.apache.xml.dtm.DTMManager;
 import org.apache.xml.utils.QName;
 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.XNodeSet;
 import org.apache.xpath.objects.XObject;
-import org.apache.xpath.operations.Range;
 import org.apache.xpath.operations.Variable;
-import org.apache.xpath.xs.types.XSUntyped;
-import org.apache.xpath.xs.types.XSUntypedAtomic;
 
 /**
  * Implementation of the fold-right() function.
@@ -61,150 +53,89 @@ import org.apache.xpath.xs.types.XSUntypedAtomic;
  * applying the supplied function repeatedly to each item in turn, together with
  * an accumulated result value.
  */
-public class FuncFoldRight extends Function3Args {
+public class FuncFoldRight extends XPathHigherOrderBuiltinFunctionsSupport {
     
     private static final long serialVersionUID = 4675724832355053777L;
 
     public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
     {
-        XObject result = null;
+        XObject result = new ResultSequence();
         
         SourceLocator srcLocator = xctxt.getSAXLocator();
         
         int contextNode = xctxt.getContextNode();
         
-        ResultSequence foldRightFirstArgResultSeq = null;
+        ResultSequence foldRightFirstArgResultSeq = constructXDMSequenceFromXPathExpression(m_arg0, xctxt);
         
-        if (m_arg0 instanceof Range) {
-           foldRightFirstArgResultSeq = (ResultSequence)(((Range)m_arg0).execute(xctxt));    
-        }
-        else if (m_arg0 instanceof Variable) {
-           XObject xObj = ((Variable)m_arg0).execute(xctxt);
-           
-           if (xObj instanceof XNodeSet) {
-               foldRightFirstArgResultSeq = new ResultSequence();
-               
-               DTMManager dtmMgr = (DTMManager)xctxt;
-               
-               XNodeSet xNodeSet = (XNodeSet)xObj;           
-               DTMIterator sourceNodes = xNodeSet.iter();
-               
-               int nextNodeDtmHandle;
-               
-               while ((nextNodeDtmHandle = sourceNodes.nextNode()) != DTM.NULL) {
-                  XNodeSet xNodeSetItem = new XNodeSet(nextNodeDtmHandle, dtmMgr);
-                  String nodeStrValue = xNodeSetItem.str();
-                  
-                  DTM dtm = dtmMgr.getDTM(nextNodeDtmHandle);
-                  
-                  if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
-                     XSUntyped xsUntyped = new XSUntyped(nodeStrValue);                 
-                     XslTransformEvaluationHelper.addItemToResultSequence(foldRightFirstArgResultSeq, 
-                                                                                               xsUntyped, true);
-                  }
-                  else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
-                     XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                     XslTransformEvaluationHelper.addItemToResultSequence(foldRightFirstArgResultSeq, 
-                                                                                               xsUntypedAtomic, true);
-                  }
-                  else {
-                     XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                     XslTransformEvaluationHelper.addItemToResultSequence(foldRightFirstArgResultSeq, 
-                                                                                               xsUntypedAtomic, true);
-                  }
-               }       
-           }
-           else if (xObj instanceof ResultSequence) {
-              foldRightFirstArgResultSeq = (ResultSequence)xObj; 
+        XObject foldRightBaseVal = m_arg1.execute(xctxt);
+        
+        InlineFunction foldRightThirdArg = null;
+        
+        if (m_arg2 instanceof Variable) {
+           XObject arg2XObj = m_arg2.execute(xctxt);
+           if (arg2XObj instanceof InlineFunction) {
+              foldRightThirdArg = (InlineFunction)arg2XObj;
            }
            else {
-              // REVISIT
-              foldRightFirstArgResultSeq = new ResultSequence();
-              foldRightFirstArgResultSeq.add(xObj);               
+              QName varQname = (((Variable)m_arg2).getElemVariable()).getName();
+              throw new javax.xml.transform.TransformerException("FORG0006 : The third argument to function call "
+                                                                         + "fn:fold-right is a variable reference '" + 
+                                                                            varQname.getLocalName() + "', that cannot be "
+                                                                         + "evaluated to a function item.", srcLocator);  
            }
+        }        
+        else if (m_arg2 instanceof InlineFunction) {
+           foldRightThirdArg = (InlineFunction)m_arg2;                                           
         }
-        else if (m_arg0 instanceof LocPathIterator) {
-            foldRightFirstArgResultSeq = new ResultSequence();
-            
-            DTMManager dtmMgr = (DTMManager)xctxt;        
-            DTMIterator arg0DtmIterator = m_arg0.asIterator(xctxt, contextNode);        
-            
-            int nextNodeDtmHandle;
-            
-            while ((nextNodeDtmHandle = arg0DtmIterator.nextNode()) != DTM.NULL) {
-                XNodeSet xNodeSetItem = new XNodeSet(nextNodeDtmHandle, dtmMgr);            
-                String nodeStrValue = xNodeSetItem.str();
-                
-                DTM dtm = dtmMgr.getDTM(nextNodeDtmHandle);
-                
-                if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
-                   XSUntyped xsUntyped = new XSUntyped(nodeStrValue);
-                   foldRightFirstArgResultSeq.add(xsUntyped);
-                }
-                else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
-                   XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                   foldRightFirstArgResultSeq.add(xsUntypedAtomic);
-                }
-                else {
-                   XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                   foldRightFirstArgResultSeq.add(xsUntypedAtomic);
-                }                        
-            }
+        else {
+           throw new javax.xml.transform.TransformerException("FORG0006 : The third argument to function call "
+                                                                      + "fn:fold-right is not a function item, or cannot be "
+                                                                      + "coerced to a function item.", srcLocator);
         }
-        
-        XObject foldRightBaseVal = m_arg1.execute(xctxt);
-        
-        InlineFunction foldRightThirdArg = null;
-        
-        if (m_arg2 instanceof InlineFunction) {
-           foldRightThirdArg = (InlineFunction)m_arg2;
+                   
+        String inlineFnXPathStr = foldRightThirdArg.getFuncBodyXPathExprStr();
+        List<String> funcParamNameList = foldRightThirdArg.getFuncParamNameList();
            
-           String inlineFnXPathStr = foldRightThirdArg.getFuncBodyXPathExprStr();
-           List<String> funcParamNameList = foldRightThirdArg.getFuncParamNameList();
-           
-           if (funcParamNameList.size() == 2) {              
-              String funcItemFirstArgName = funcParamNameList.get(0);
-              String funcItemSecondArgName = funcParamNameList.get(1);
+        if (funcParamNameList.size() == 2) {              
+           String funcItemFirstArgName = funcParamNameList.get(0);
+           String funcItemSecondArgName = funcParamNameList.get(1);
               
-              ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();
-              List<XMLNSDecl> prefixTable = null;
-              if (elemTemplateElement != null) {
-                  prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
-              }
+           ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();
+           List<XMLNSDecl> prefixTable = null;
+           if (elemTemplateElement != null) {
+              prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
+           }
               
-              if (prefixTable != null) {
-                 inlineFnXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(
-                                                                                        inlineFnXPathStr, prefixTable);
-              }
+           if (prefixTable != null) {
+              inlineFnXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(
+                                                                                           inlineFnXPathStr, prefixTable);
+           }
               
-              XPath inlineFuncXPath = new XPath(inlineFnXPathStr, srcLocator, xctxt.getNamespaceContext(), 
+           XPath inlineFuncXPath = new XPath(inlineFnXPathStr, srcLocator, xctxt.getNamespaceContext(), 
                                                                                               XPath.SELECT, null);              
-              for (int idx = foldRightFirstArgResultSeq.size() - 1; idx >= 0; idx--) {
-                 Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
+           for (int idx = foldRightFirstArgResultSeq.size() - 1; idx >= 0; idx--) {
+              Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
                  
-                 inlineFunctionVarMap.put(new QName(funcItemFirstArgName), foldRightFirstArgResultSeq.item(idx));
+              inlineFunctionVarMap.put(new QName(funcItemFirstArgName), foldRightFirstArgResultSeq.item(idx));
               
-                 if (idx == (foldRightFirstArgResultSeq.size() - 1)) {                    
+              if (idx == (foldRightFirstArgResultSeq.size() - 1)) {                    
                     inlineFunctionVarMap.put(new QName(funcItemSecondArgName), foldRightBaseVal);
-                 }
-                 else {
+              }
+              else {
                     inlineFunctionVarMap.put(new QName(funcItemSecondArgName), result);                   
-                 }
-                 
-                 result = inlineFuncXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
-                 
-                 
-                 // Reset the function item argument variables
-                 inlineFunctionVarMap.put(new QName(funcItemFirstArgName), null);
-                 inlineFunctionVarMap.put(new QName(funcItemSecondArgName), null);
               }
-           }
-           else {
-              result = new ResultSequence();  
+                 
+              result = inlineFuncXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
+                                  
+              // Reset the function item argument variables
+              inlineFunctionVarMap.put(new QName(funcItemFirstArgName), null);
+              inlineFunctionVarMap.put(new QName(funcItemSecondArgName), null);
            }
         }
         else {
-           result = new ResultSequence(); 
+            throw new javax.xml.transform.TransformerException("XPTY0004 : An inline function definition argument to "
+                                                                     + "function fn:fold-right has " + funcParamNameList.size() + " "
+                                                                     + "parameters. Expected 2.", srcLocator); 
         }
         
         return result;
diff --git a/src/org/apache/xpath/functions/FuncForEachPair.java b/src/org/apache/xpath/functions/FuncForEachPair.java
new file mode 100644
index 00000000..885f173c
--- /dev/null
+++ b/src/org/apache/xpath/functions/FuncForEachPair.java
@@ -0,0 +1,173 @@
+/*
+ * 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 org.apache.xalan.templates.ElemTemplateElement;
+import org.apache.xalan.templates.XMLNSDecl;
+import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
+import org.apache.xml.utils.QName;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.InlineFunction;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.operations.Variable;
+
+/**
+ * Implementation of the for-each-pair() function.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+/*
+ * fn:for-each-pair 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-pair has following signature, and definition,
+ * 
+ * fn:for-each-pair($seq1 as item()*,
+                    $seq2 as item()*,
+                    $action as function(item(), item()) as item()*) as item()*
+                    
+ * The fn:for-each-pair function, applies the function item $action to successive 
+ * pairs of items taken one from $seq1 and one from $seq2, returning the 
+ * concatenation of the resulting sequences in order.
+ */
+public class FuncForEachPair extends XPathHigherOrderBuiltinFunctionsSupport {
+
+    private static final long serialVersionUID = 5864311267789581972L;
+
+    public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
+    {
+        XObject evalResult = new ResultSequence();
+        
+        SourceLocator srcLocator = xctxt.getSAXLocator();
+        
+        ResultSequence forEachPairFirstArgInpSeq = constructXDMSequenceFromXPathExpression(m_arg0, xctxt);        
+        ResultSequence forEachPairSecondArgInpSeq = constructXDMSequenceFromXPathExpression(m_arg1, xctxt);
+        
+        InlineFunction forEachPairThirdArg = null;
+        
+        if (m_arg2 instanceof Variable) {
+           XObject arg2XObj = m_arg2.execute(xctxt);
+           if (arg2XObj instanceof InlineFunction) {
+              forEachPairThirdArg = (InlineFunction)arg2XObj;
+           }
+           else {
+              QName varQname = (((Variable)m_arg2).getElemVariable()).getName();
+              throw new javax.xml.transform.TransformerException("FORG0006 : The third argument to function call "
+                                                                   + "fn:for-each-pair is a variable reference '" + 
+                                                                       varQname.getLocalName() + "', that cannot be "
+                                                                       + "evaluated to a function item.", srcLocator);  
+           }
+        }        
+        else if (m_arg2 instanceof InlineFunction) {
+           forEachPairThirdArg = (InlineFunction)m_arg2;                                           
+        }
+        else {
+           throw new javax.xml.transform.TransformerException("FORG0006 : The third argument to function call "
+                                                                    + "fn:for-each-pair is not a function item, or cannot be "
+                                                                    + "coerced to a function item.", srcLocator);
+        }
+        
+        evalResult = evaluateForEachPairInlineFunction(forEachPairThirdArg, xctxt, forEachPairFirstArgInpSeq, 
+                                                                                                  forEachPairSecondArgInpSeq);
+        
+        return evalResult;
+    }
+    
+    /**
+     * This method produces the result data, for an XPath fn:for-each-pair function call.
+     * 
+     * @param inlineFunc     an inline function that needs to be evaluated
+     * @param xctxt          the XPath expression context
+     * @param inpSeq1        the first xdm input sequence argument to function fn:for-each-pair     
+     * @param inpSeq2        the second xdm input sequence argument to function fn:for-each-pair
+     * 
+     * @return               the result of evaluation by this method, as an object of
+     *                       class ResultSequence.    
+     * 
+     * @throws javax.xml.transform.TransformerException
+     */
+    private ResultSequence evaluateForEachPairInlineFunction(InlineFunction inlineFunc, XPathContext xctxt, 
+                                                                    ResultSequence inpSeq1, ResultSequence inpSeq2) 
+                                                                                       throws javax.xml.transform.TransformerException {        
+        ResultSequence resultSeq = new ResultSequence();
+        
+        SourceLocator srcLocator = xctxt.getSAXLocator();
+        
+        int contextNode = xctxt.getContextNode();
+        
+        String inlineFnXPathStr = inlineFunc.getFuncBodyXPathExprStr();
+        List<String> funcParamNameList = inlineFunc.getFuncParamNameList();
+        
+        if (funcParamNameList.size() == 2) {                           
+            String funcItemFirstArgName = funcParamNameList.get(0);
+            String funcItemSecondArgName = funcParamNameList.get(1);
+            
+            ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();
+            List<XMLNSDecl> prefixTable = null;
+            if (elemTemplateElement != null) {
+                prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
+            }
+            
+            if (prefixTable != null) {
+               inlineFnXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(
+                                                                                      inlineFnXPathStr, prefixTable);
+            }
+            
+            XPath inlineFuncXPath = new XPath(inlineFnXPathStr, srcLocator, xctxt.getNamespaceContext(), 
+                                                                                            XPath.SELECT, null);
+            
+            int inpEffectiveIterationSize = 0;        
+            if (inpSeq1.size() <= inpSeq2.size()) {
+               inpEffectiveIterationSize = inpSeq1.size();    
+            }
+            else {
+               inpEffectiveIterationSize = inpSeq2.size(); 
+            }
+            
+            for (int idx = 0; idx < inpEffectiveIterationSize; idx++) {
+               Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
+               
+               inlineFunctionVarMap.put(new QName(funcItemFirstArgName), inpSeq1.item(idx));
+               inlineFunctionVarMap.put(new QName(funcItemSecondArgName), inpSeq2.item(idx));
+                
+               XObject iterResultVal = inlineFuncXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
+               resultSeq.add(iterResultVal);
+                
+               // Reset the function item argument variables
+               inlineFunctionVarMap.put(new QName(funcItemFirstArgName), null);
+               inlineFunctionVarMap.put(new QName(funcItemSecondArgName), null);
+            }
+        }
+        else {
+            throw new javax.xml.transform.TransformerException("XPTY0004 : An inline function definition argument to "
+                                                                     + "function fn:for-each-pair has " + funcParamNameList.size() + " "
+                                                                     + "parameters. Expected 2.", srcLocator); 
+        }
+        
+        return resultSeq;
+    }
+
+}
diff --git a/src/org/apache/xpath/functions/XPathHigherOrderBuiltinFunctionsSupport.java b/src/org/apache/xpath/functions/XPathHigherOrderBuiltinFunctionsSupport.java
new file mode 100644
index 00000000..a0a4fbae
--- /dev/null
+++ b/src/org/apache/xpath/functions/XPathHigherOrderBuiltinFunctionsSupport.java
@@ -0,0 +1,139 @@
+/*
+ * 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 org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.dtm.DTMManager;
+import org.apache.xpath.Expression;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.LocPathIterator;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XNodeSet;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.operations.Range;
+import org.apache.xpath.operations.Variable;
+import org.apache.xpath.xs.types.XSUntyped;
+import org.apache.xpath.xs.types.XSUntypedAtomic;
+
+/**
+ * This class provides few utility methods, to help with XPath 3.1 
+ * built-in higher order function evaluations.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class XPathHigherOrderBuiltinFunctionsSupport extends Function3Args {
+    
+    private static final long serialVersionUID = 5970365027214826130L;
+
+    /**
+     * This method, evaluates an XPath expression to produce an xdm sequence, that
+     * can be used as an argument to an XPath higher order function call.
+     *  
+     * @param xpathExpr      an XPath expression, that is evaluated by this method,
+     *                       to produce an xdm sequence that can be used as an
+     *                       argument to the call of an XPath higher order function.
+     * @param xctxt          an XPath context object
+     * 
+     * @return               an xdm sequence produced by this method.
+     * 
+     * @throws javax.xml.transform.TransformerException
+     */
+    protected ResultSequence constructXDMSequenceFromXPathExpression(Expression xpathExpr, XPathContext xctxt) 
+                                                                                       throws javax.xml.transform.TransformerException {        
+        ResultSequence resultSeq = new ResultSequence();
+        
+        int contextNode = xctxt.getContextNode();
+
+        if (xpathExpr instanceof Range) {
+            resultSeq = (ResultSequence)(((Range)xpathExpr).execute(xctxt));    
+        }
+        else if (xpathExpr instanceof Variable) {
+            XObject xObj = ((Variable)xpathExpr).execute(xctxt);
+
+            if (xObj instanceof XNodeSet) {               
+                DTMManager dtmMgr = (DTMManager)xctxt;
+
+                XNodeSet xNodeSet = (XNodeSet)xObj;           
+                DTMIterator sourceNodes = xNodeSet.iter();
+
+                int nextNodeDtmHandle;
+
+                while ((nextNodeDtmHandle = sourceNodes.nextNode()) != DTM.NULL) {
+                    XNodeSet xNodeSetItem = new XNodeSet(nextNodeDtmHandle, dtmMgr);
+                    String nodeStrValue = xNodeSetItem.str();
+
+                    DTM dtm = dtmMgr.getDTM(nextNodeDtmHandle);
+
+                    if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
+                        XSUntyped xsUntyped = new XSUntyped(nodeStrValue);                 
+                        XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                                  xsUntyped, true);
+                    }
+                    else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
+                        XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+                        XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                                  xsUntypedAtomic, true);
+                    }
+                    else {
+                        XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+                        XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                                  xsUntypedAtomic, true);
+                    }
+                }       
+            }
+            else if (xObj instanceof ResultSequence) {
+                resultSeq = (ResultSequence)xObj; 
+            }
+            else {
+                resultSeq.add(xObj);
+            }
+        }
+        else if (xpathExpr instanceof LocPathIterator) {            
+            DTMManager dtmMgr = (DTMManager)xctxt;        
+            DTMIterator arg0DtmIterator = xpathExpr.asIterator(xctxt, contextNode);        
+
+            int nextNodeDtmHandle;
+
+            while ((nextNodeDtmHandle = arg0DtmIterator.nextNode()) != DTM.NULL) {
+                XNodeSet xNodeSetItem = new XNodeSet(nextNodeDtmHandle, dtmMgr);            
+                String nodeStrValue = xNodeSetItem.str();
+
+                DTM dtm = dtmMgr.getDTM(nextNodeDtmHandle);
+
+                if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
+                    XSUntyped xsUntyped = new XSUntyped(nodeStrValue);
+                    resultSeq.add(xsUntyped);
+                }
+                else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
+                    XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+                    resultSeq.add(xsUntypedAtomic);
+                }
+                else {
+                    XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
+                    resultSeq.add(xsUntypedAtomic);
+                }                        
+            }
+        }
+
+        return resultSeq;
+   }
+
+}
diff --git a/src/org/apache/xpath/operations/Plus.java b/src/org/apache/xpath/operations/Plus.java
index 431bce64..0b7b8812 100644
--- a/src/org/apache/xpath/operations/Plus.java
+++ b/src/org/apache/xpath/operations/Plus.java
@@ -27,6 +27,8 @@ import org.apache.xpath.objects.XNodeSet;
 import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.xs.types.XSNumericType;
+import org.apache.xpath.xs.types.XSUntyped;
+import org.apache.xpath.xs.types.XSUntypedAtomic;
 import org.apache.xpath.xs.types.XSYearMonthDuration;
 
 /**
@@ -51,7 +53,43 @@ public class Plus extends Operation
                                            throws javax.xml.transform.TransformerException {
       XObject result = null;
    
-      if ((left instanceof XNumber) && (right instanceof XSNumericType)) {
+      if ((left instanceof XSUntyped) && (right instanceof XSUntyped)) {
+          java.lang.String lStrVal = ((XSUntyped)left).stringValue();
+          double lDouble = (Double.valueOf(lStrVal)).doubleValue();
+          
+          java.lang.String rStrVal = ((XSUntyped)right).stringValue();
+          double rDouble = (Double.valueOf(rStrVal)).doubleValue();
+          
+          result = new XNumber(lDouble + rDouble);
+      }
+      else if ((left instanceof XSUntypedAtomic) && (right instanceof XSUntypedAtomic)) {
+          java.lang.String lStrVal = ((XSUntypedAtomic)left).stringValue();
+          double lDouble = (Double.valueOf(lStrVal)).doubleValue();
+          
+          java.lang.String rStrVal = ((XSUntypedAtomic)right).stringValue();
+          double rDouble = (Double.valueOf(rStrVal)).doubleValue();
+          
+          result = new XNumber(lDouble + rDouble);
+      }
+      else if ((left instanceof XSUntyped) && (right instanceof XSUntypedAtomic)) {
+          java.lang.String lStrVal = ((XSUntyped)left).stringValue();
+          double lDouble = (Double.valueOf(lStrVal)).doubleValue();
+          
+          java.lang.String rStrVal = ((XSUntypedAtomic)right).stringValue();
+          double rDouble = (Double.valueOf(rStrVal)).doubleValue();
+          
+          result = new XNumber(lDouble + rDouble);
+      }
+      else if ((left instanceof XSUntypedAtomic) && (right instanceof XSUntyped)) {
+          java.lang.String lStrVal = ((XSUntypedAtomic)left).stringValue();
+          double lDouble = (Double.valueOf(lStrVal)).doubleValue();
+          
+          java.lang.String rStrVal = ((XSUntyped)right).stringValue();
+          double rDouble = (Double.valueOf(rStrVal)).doubleValue();
+          
+          result = new XNumber(lDouble + rDouble);
+      }
+      else if ((left instanceof XNumber) && (right instanceof XSNumericType)) {
           double lDouble = ((XNumber)left).num();
           
           java.lang.String rStrVal = ((XSNumericType)right).stringValue();
diff --git a/tests/fn_fold_left/gold/test1.out b/tests/fn_fold_left/gold/test1.out
index f6cf66a0..ac967084 100644
--- a/tests/fn_fold_left/gold/test1.out
+++ b/tests/fn_fold_left/gold/test1.out
@@ -8,4 +8,5 @@
   <val7>false</val7>
   <val8>5 4 3 2 1</val8>
   <val9>zabc</val9>
+  <val10>28</val10>
 </result>
diff --git a/tests/fn_fold_left/test1.xsl b/tests/fn_fold_left/test1.xsl
index 5fa07459..92b53aef 100644
--- a/tests/fn_fold_left/test1.xsl
+++ b/tests/fn_fold_left/test1.xsl
@@ -12,44 +12,46 @@
 
    <xsl:output method="xml" indent="yes"/>
    
-   <!-- The XPath evaluation of select expression of this variable,
+   <xsl:variable name="fnAdd" select="function($arg1, $arg2) { $arg1 + $arg2 }"/>
+   
+   <!-- the XPath evaluation of select expression of this variable,
         produces an empty sequence. -->
    <xsl:variable name="emptySeq" select="1 to 0"/>
       
    <xsl:template match="/">      
       <result>
-        <!-- With this fold-left function call example, the inline function adds '$arg1' to 
-	         '$arg2' with a base value of 0. i.e. the following evaluation is performed : 
+        <!-- with this fold-left function call example, the inline function adds '$arg1' to 
+	         '$arg2' with a base value of 0. i.e, the following evaluation is performed : 
              (((((0 + 1) + 2) + 3) + 4) + 5) -->
         <val1><xsl:value-of select="fold-left(1 to 5, 0, function($a, $b) { $a + $b })"/></val1>
         
-        <!-- With this fold-left function call example, the inline function multiplies '$arg1' 
-             by '$arg2' with a base value of 1. i.e. the following evaluation is performed : 
+        <!-- with this fold-left function call example, the inline function multiplies '$arg1' 
+             by '$arg2' with a base value of 1. i.e, the following evaluation is performed : 
              (((((1 * 1) * 2) * 3) * 4) * 5) -->
         <val2><xsl:value-of select="fold-left(1 to 5, 1, function($arg1, $arg2) { $arg1 * $arg2 })"/></val2>
         
-        <!-- With this fold-left function call example, the inline function multiplies '$arg1' 
-	         by '$arg2' with a base value of 0. i.e. the following evaluation is performed : 
+        <!-- with this fold-left function call example, the inline function multiplies '$arg1' 
+	         by '$arg2' with a base value of 0. i.e, the following evaluation is performed : 
              (((((0 * 1) * 2) * 3) * 4) * 5) -->
         <val3><xsl:value-of select="fold-left(1 to 5, 0, function($arg1, $arg2) { $arg1 * $arg2 })"/></val3>
         
-        <!-- With this fold-left function call example, the inline function subtracts '$arg2' from '$arg1' 
-             with a base value of 0. i.e. the following evaluation is performed : 
+        <!-- with this fold-left function call example, the inline function subtracts '$arg2' from '$arg1' 
+             with a base value of 0. i.e, the following evaluation is performed : 
              (((((0 - 1) - 2) - 3) - 4) - 5) -->
         <val4><xsl:value-of select="fold-left(1 to 5, 0, function($arg1, $arg2) { $arg1 - $arg2 })"/></val4>
         
-        <!-- With this fold-left function call example, the result is product of the numeric values 
+        <!-- with this fold-left function call example, the result is product of the numeric values 
              present within an input sequence.-->
         <xsl:variable name="seq1" select="(2, 3, 5, 7)"/>        
         <val5><xsl:value-of select="fold-left($seq1, 1, function($a, $b) { $a * $b })"/></val5>
         
         <xsl:variable name="seq2" select="(true(), false(), false())"/>
         
-        <!-- With this fold-left function call example, the boolean result 'true' is returned if any 
+        <!-- with this fold-left function call example, the boolean result 'true' is returned if any 
              xdm item within an input sequence has an effective boolean value of 'true'. -->
         <val6><xsl:value-of select="fold-left($seq2, false(), function($a, $b) { $a or $b })"/></val6>
         
-        <!-- With this fold-left function call example, the boolean result 'true' is returned if every 
+        <!-- with this fold-left function call example, the boolean result 'true' is returned if every 
              xdm item within an input sequence has an effective boolean value of 'true'. -->
         <val7><xsl:value-of select="fold-left($seq2, false(), function($a, $b) { $a and $b })"/></val7>
         
@@ -57,12 +59,16 @@
              sequence. -->
         <val8><xsl:value-of select="fold-left(1 to 5, $emptySeq, function($a, $b) { ($b, $a) })"/></val8>
         
-        <!-- With this fold-left function call example, the inline function concatenates '$arg1' with 
-             '$arg2', with a base value of 'z'. i.e. the following evaluation is performed :
+        <!-- with this fold-left function call example, an inline function concatenates '$arg1' with 
+             '$arg2', with a base value of 'z'. i.e, the following evaluation is performed :
              concat(concat(concat('z','a'), 'b'), 'c') -->
         <xsl:variable name="charListSeq" select="('a', 'b', 'c')"/>
         <val9><xsl:value-of select="fold-left($charListSeq, 'z' , function($arg1, $arg2) 
                                                                         { concat($arg1, $arg2) })"/></val9>
+                                                                        
+        <!-- the following fn:fold-left function call example, refers an inline function, 
+             via a variable reference. -->
+         <val10><xsl:value-of select="fold-left(1 to 7, 0, $fnAdd)"/></val10>                                                                        
       </result>
    </xsl:template>
    
diff --git a/tests/fn_fold_right/gold/test1.out b/tests/fn_fold_right/gold/test1.out
index c22ff00b..bf7aa7fa 100644
--- a/tests/fn_fold_right/gold/test1.out
+++ b/tests/fn_fold_right/gold/test1.out
@@ -2,4 +2,5 @@
   <val1>15</val1>
   <val2>3</val2>
   <val3>abcz</val3>
+  <val4>abcdez</val4>
 </result>
diff --git a/tests/fn_fold_right/test1.xsl b/tests/fn_fold_right/test1.xsl
index edb86ec7..523a7331 100644
--- a/tests/fn_fold_right/test1.xsl
+++ b/tests/fn_fold_right/test1.xsl
@@ -11,6 +11,8 @@
         XPath 3.1 spec, and https://www.altova.com/. -->                 
 
    <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="fnStrConcat" select="function($arg1, $arg2) { concat($arg1, $arg2) }"/>
       
    <xsl:template match="/">      
       <result>
@@ -18,8 +20,13 @@
         
         <val2><xsl:value-of select="fold-right(1 to 5, 0, function($arg1, $arg2) { $arg1 - $arg2 })"/></val2>
         
-        <xsl:variable name="charListSeq" select="('a', 'b', 'c')"/>
-        <val3><xsl:value-of select="fold-right($charListSeq, 'z' , function($arg1, $arg2) { concat($arg1, $arg2) })"/></val3>
+        <xsl:variable name="charListSeq1" select="('a', 'b', 'c')"/>
+        <val3><xsl:value-of select="fold-right($charListSeq1, 'z' , function($arg1, $arg2) { concat($arg1, $arg2) })"/></val3>
+        
+        <!-- the following fn:fold-right function call example, refers an inline function, 
+             via a variable reference. -->
+        <xsl:variable name="charListSeq2" select="('a', 'b', 'c', 'd', 'e')"/>
+        <val4><xsl:value-of select="fold-right($charListSeq2, 'z' , $fnStrConcat)"/></val4>
       </result>
    </xsl:template>
    
diff --git a/tests/fn_for_each_pair/gold/test1.out b/tests/fn_for_each_pair/gold/test1.out
new file mode 100644
index 00000000..50b03a77
--- /dev/null
+++ b/tests/fn_for_each_pair/gold/test1.out
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>ax by cz</one>
+  <two>11 22 33 44 55</two>
+  <three>2 50 1000</three>
+  <four>2 50</four>
+  <five>2 50</five>
+</result>
diff --git a/tests/fn_for_each_pair/gold/test2.out b/tests/fn_for_each_pair/gold/test2.out
new file mode 100644
index 00000000..7b177de8
--- /dev/null
+++ b/tests/fn_for_each_pair/gold/test2.out
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>7 9 11 13</one>
+  <two>3 5 7 9</two>
+  <three>3 5 7 9</three>
+  <four>3 5 7 9</four>
+</result>
diff --git a/tests/fn_fold_right/test1.xsl b/tests/fn_for_each_pair/test1.xsl
similarity index 51%
copy from tests/fn_fold_right/test1.xsl
copy to tests/fn_for_each_pair/test1.xsl
index edb86ec7..1b391c13 100644
--- a/tests/fn_fold_right/test1.xsl
+++ b/tests/fn_for_each_pair/test1.xsl
@@ -4,22 +4,36 @@
                 
    <!-- Author: mukulg@apache.org -->
    
-   <!-- Test for the XPath 3.1 fn:fold-right() function.
+   <!-- Test for the XPath 3.1 fn:for-each-pair() function.
    
-        The XPath fn:fold-right() function usage examples, as
+        The XPath fn:for-each-pair() function usage examples, as
         illustrated within this stylesheet are borrowed from
         XPath 3.1 spec, and https://www.altova.com/. -->                 
 
    <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="fnMult" select="function($arg1, $arg2) { $arg1 * $arg2 }"/>
       
    <xsl:template match="/">      
       <result>
-        <val1><xsl:value-of select="fold-right(1 to 5, 0, function($a, $b) { $a + $b })"/></val1>
-        
-        <val2><xsl:value-of select="fold-right(1 to 5, 0, function($arg1, $arg2) { $arg1 - $arg2 })"/></val2>
-        
-        <xsl:variable name="charListSeq" select="('a', 'b', 'c')"/>
-        <val3><xsl:value-of select="fold-right($charListSeq, 'z' , function($arg1, $arg2) { concat($arg1, $arg2) })"/></val3>
+         <xsl:variable name="seq1" select="('a', 'b', 'c')"/>
+         <xsl:variable name="seq2" select="('x', 'y', 'z')"/>
+         
+         <one><xsl:value-of select="for-each-pair($seq1, $seq2, function($a, $b) { $a || $b })"/></one>
+         
+         <two><xsl:value-of select="for-each-pair(1 to 5, 1 to 5, function($a, $b){ 10*$a + $b })"/></two>
+         
+         <xsl:variable name="seq3" select="(1, 10, 100)"/>
+         <xsl:variable name="seq4" select="(2, 5, 10)"/>         
+         
+         <three><xsl:value-of select="for-each-pair($seq3, $seq4, function($arg1, $arg2) { $arg1 * $arg2 })"/></three>
+         
+         <xsl:variable name="seq5" select="(2, 5)"/>
+         <four><xsl:value-of select="for-each-pair($seq3, $seq5, function($arg1, $arg2) { $arg1 * $arg2 })"/></four>
+         
+         <!-- the following fn:for-each-pair function call example, refers an inline function, 
+              via a variable reference. -->
+         <five><xsl:value-of select="for-each-pair($seq3, $seq5, $fnMult)"/></five>
       </result>
    </xsl:template>
    
diff --git a/tests/fn_for_each_pair/test1_a.xml b/tests/fn_for_each_pair/test1_a.xml
new file mode 100644
index 00000000..68faf758
--- /dev/null
+++ b/tests/fn_for_each_pair/test1_a.xml
@@ -0,0 +1,16 @@
+<temp>
+  <data1>
+    <val>2</val>
+    <val>3</val>
+    <val>4</val>
+    <val>5</val>
+  </data1>
+  <data2>
+    <val>5</val>
+    <val>6</val>
+    <val>7</val>
+    <val>8</val>
+  </data2>
+  <data3 val1="1" val2="2" val3="3" val4="4"/>
+  <data4 val1="2" val2="3" val3="4" val4="5"/>
+</temp>
\ No newline at end of file
diff --git a/tests/fn_fold_right/test1.xsl b/tests/fn_for_each_pair/test2.xsl
similarity index 61%
copy from tests/fn_fold_right/test1.xsl
copy to tests/fn_for_each_pair/test2.xsl
index edb86ec7..e430794a 100644
--- a/tests/fn_fold_right/test1.xsl
+++ b/tests/fn_for_each_pair/test2.xsl
@@ -4,22 +4,20 @@
                 
    <!-- Author: mukulg@apache.org -->
    
-   <!-- Test for the XPath 3.1 fn:fold-right() function.
+   <!-- use with test1_a.xml -->
    
-        The XPath fn:fold-right() function usage examples, as
-        illustrated within this stylesheet are borrowed from
-        XPath 3.1 spec, and https://www.altova.com/. -->                 
+   <!-- Test for the XPath 3.1 fn:for-each-pair() function. -->                
 
    <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="fnAdd" select="function($arg1, $arg2) { $arg1 + $arg2 }"/>
       
-   <xsl:template match="/">      
+   <xsl:template match="/temp">      
       <result>
-        <val1><xsl:value-of select="fold-right(1 to 5, 0, function($a, $b) { $a + $b })"/></val1>
-        
-        <val2><xsl:value-of select="fold-right(1 to 5, 0, function($arg1, $arg2) { $arg1 - $arg2 })"/></val2>
-        
-        <xsl:variable name="charListSeq" select="('a', 'b', 'c')"/>
-        <val3><xsl:value-of select="fold-right($charListSeq, 'z' , function($arg1, $arg2) { concat($arg1, $arg2) })"/></val3>
+         <one><xsl:value-of select="for-each-pair(data1/val, data2/val, $fnAdd)"/></one>
+         <two><xsl:value-of select="for-each-pair(data3/@*, data4/@*, $fnAdd)"/></two>
+         <three><xsl:value-of select="for-each-pair(data1/val, data3/@*, $fnAdd)"/></three>
+         <four><xsl:value-of select="for-each-pair(data3/@*, data1/val, $fnAdd)"/></four>
       </result>
    </xsl:template>
    
diff --git a/tests/org/apache/xalan/xpath3/FnForEachPairTests.java b/tests/org/apache/xalan/xpath3/FnForEachPairTests.java
new file mode 100644
index 00000000..6fcc02cb
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/FnForEachPairTests.java
@@ -0,0 +1,72 @@
+/*
+ * 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-pair test cases.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class FnForEachPairTests extends XslTransformTestsUtil {        
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + 
+                                                                                                    "fn_for_each_pair/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + 
+                                                                                                    "fn_for_each_pair/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 xslFnForEachPairTest1() {
+        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 xslFnForEachPairTest2() {
+        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);
+    }
+
+}
diff --git a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
index b2904159..0cd26d09 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -24,6 +24,7 @@ import org.apache.xalan.xpath3.FnDistinctValuesTests;
 import org.apache.xalan.xpath3.FnFilterTests;
 import org.apache.xalan.xpath3.FnFoldLeftTests;
 import org.apache.xalan.xpath3.FnFoldRightTests;
+import org.apache.xalan.xpath3.FnForEachPairTests;
 import org.apache.xalan.xpath3.FnForEachTests;
 import org.apache.xalan.xpath3.FnIndexOfTests;
 import org.apache.xalan.xpath3.FnStringJoinTests;
@@ -75,7 +76,7 @@ import org.junit.runners.Suite.SuiteClasses;
                 SequenceConstructorTests.class, StringConcatExprTests.class, 
                 XsDurationComponentExtractionFunctionTests.class, XPathArithmeticOnDurationValuesTests.class,
                 NodeComparisonTests.class, SimpleMapOperatorTests.class, FnFoldLeftTests.class,
-                FnFoldRightTests.class })
+                FnFoldRightTests.class, FnForEachPairTests.class })
 public class AllXsl3Tests {
 
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org