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/10 23:34:01 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xpath 3.1 functions fn:fold-left, fn:fold-right and few new related working test cases as well. also doing bit of, codebase refactoring and minor changes to src code comments on this xalanj dev implementation 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 32667291 committing implementation of xpath 3.1 functions fn:fold-left, fn:fold-right and few new related working test cases as well. also doing bit of, codebase refactoring and minor changes to src code comments on this xalanj dev implementation branch.
     new 00e05447 Merge pull request #47 from mukulga/xalan-j_xslt3.0_mukul
32667291 is described below

commit 3266729186635242623d54209fcf47ddbe23bb6a
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Fri Aug 11 04:56:54 2023 +0530

    committing implementation of xpath 3.1 functions fn:fold-left, fn:fold-right and few new related working test cases as well. also doing bit of, codebase refactoring and minor changes to src code comments on this xalanj dev implementation branch.
---
 src/org/apache/xalan/templates/ElemVariable.java   |   6 +
 .../xslt/util/XslTransformEvaluationHelper.java    |  75 ++++++++
 src/org/apache/xpath/compiler/Compiler.java        |  92 ++++++++-
 src/org/apache/xpath/compiler/FunctionTable.java   |  17 +-
 src/org/apache/xpath/compiler/Keywords.java        |   6 +
 .../apache/xpath/functions/FuncDistinctValues.java |  96 ++--------
 src/org/apache/xpath/functions/FuncFoldLeft.java   | 212 ++++++++++++++++++++
 src/org/apache/xpath/functions/FuncFoldRight.java  | 213 +++++++++++++++++++++
 src/org/apache/xpath/operations/Mult.java          |  34 ++++
 tests/fn_fold_left/gold/test1.out                  |  11 ++
 tests/fn_fold_left/gold/test2.out                  |   5 +
 tests/fn_fold_left/gold/test3.out                  |   4 +
 tests/fn_fold_left/test1.xsl                       |  87 +++++++++
 tests/fn_fold_left/test1_a.xml                     |   7 +
 tests/fn_fold_left/test2.xsl                       |  41 ++++
 tests/fn_fold_left/test3.xsl                       |  41 ++++
 tests/fn_fold_right/gold/test1.out                 |   5 +
 tests/fn_fold_right/gold/test2.out                 |   5 +
 tests/fn_fold_right/gold/test3.out                 |   4 +
 tests/fn_fold_right/test1.xsl                      |  44 +++++
 tests/fn_fold_right/test1_a.xml                    |   7 +
 tests/fn_fold_right/test2.xsl                      |  41 ++++
 tests/fn_fold_right/test3.xsl                      |  41 ++++
 tests/org/apache/xalan/xpath3/FnFoldLeftTests.java |  82 ++++++++
 .../org/apache/xalan/xpath3/FnFoldRightTests.java  |  82 ++++++++
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java     |   5 +-
 26 files changed, 1178 insertions(+), 85 deletions(-)

diff --git a/src/org/apache/xalan/templates/ElemVariable.java b/src/org/apache/xalan/templates/ElemVariable.java
index 87403c4a..201dde3d 100644
--- a/src/org/apache/xalan/templates/ElemVariable.java
+++ b/src/org/apache/xalan/templates/ElemVariable.java
@@ -46,6 +46,7 @@ import org.apache.xpath.objects.XRTreeFrag;
 import org.apache.xpath.objects.XRTreeFragSelectWrapper;
 import org.apache.xpath.objects.XString;
 import org.apache.xpath.operations.Operation;
+import org.apache.xpath.operations.Range;
 import org.apache.xpath.operations.SimpleMapOperator;
 import org.apache.xpath.xs.types.XSAnyType;
 import org.apache.xpath.xs.types.XSNumericType;
@@ -340,6 +341,11 @@ public class ElemVariable extends ElemTemplateElement
             
             return evalResult;
         }
+        else if (selectExpression instanceof Range) {
+            XObject evalResult = ((Range)selectExpression).execute(xctxt);
+            
+            return evalResult; 
+        }
         else if (selectExpression instanceof Operation) {
             Operation opn = (Operation)selectExpression;
             XObject leftOperand = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
diff --git a/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java b/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java
index e1e6073f..1c7fdc32 100644
--- a/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java
+++ b/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java
@@ -19,6 +19,8 @@ package org.apache.xalan.xslt.util;
 import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.xs.types.XSAnyType;
+import org.apache.xpath.xs.types.XSUntyped;
+import org.apache.xpath.xs.types.XSUntypedAtomic;
 
 import java.util.List;
 
@@ -90,5 +92,78 @@ public class XslTransformEvaluationHelper {
        
        return strVal;
     }
+    
+    /**
+     * Add an xdm input item to result sequence, if that already doesn't exist within
+     * the result sequence. 
+     */
+    public static void addItemToResultSequence(ResultSequence resultSeq, XObject inpItem, 
+                                                                       boolean cardinalityCheck) {
+        if (cardinalityCheck) {
+            if (resultSeq.size() == 0) {                     
+                resultSeq.add(inpItem);    
+            }
+            else if (!contains(resultSeq, inpItem)) {
+                resultSeq.add(inpItem);
+            }   
+        }
+        else {
+            resultSeq.add(inpItem);   
+        }
+    }
+    
+    /**
+     * Check whether a 'ResultSequence' object, contains a specific xdm item.
+     */
+    private static boolean contains(ResultSequence resultSeq, XObject srch) {
+       
+       boolean isSeqContains = false;
+       
+       for (int idx = 0; idx < resultSeq.size(); idx++) {
+          XObject existingItemWithinResultSeq = resultSeq.item(idx);
+          if ((existingItemWithinResultSeq instanceof XSUntyped) && 
+                                                            (srch instanceof XSUntyped)) {
+             if (((XSUntyped)existingItemWithinResultSeq).equals((XSUntyped)srch)) {
+                 isSeqContains = true;
+                 break;    
+             }
+          }
+          else if ((existingItemWithinResultSeq instanceof XSUntypedAtomic) && 
+                                                                  (srch instanceof XSUntypedAtomic)) {
+              if (((XSUntypedAtomic)existingItemWithinResultSeq).equals((XSUntypedAtomic)srch)) {
+                 isSeqContains = true;
+                 break;    
+              } 
+          }
+          else if ((existingItemWithinResultSeq instanceof XSUntyped) && 
+                                                                (srch instanceof XSUntypedAtomic)) {
+              if (((XSUntyped)existingItemWithinResultSeq).equals((XSUntypedAtomic)srch)) {
+                 isSeqContains = true;
+                 break;    
+              } 
+          }
+          else if ((existingItemWithinResultSeq instanceof XSUntypedAtomic) && 
+                                                                (srch instanceof XSUntyped)) {
+              if (((XSUntypedAtomic)existingItemWithinResultSeq).equals((XSUntyped)srch)) {
+                 isSeqContains = true;
+                 break;    
+              }
+          }
+          else if ((existingItemWithinResultSeq instanceof XSAnyType) && 
+                                                                 (srch instanceof XSAnyType)) {
+              if (((XSAnyType)existingItemWithinResultSeq).equals((XSAnyType)srch)) {
+                  isSeqContains = true;
+                  break;    
+              }   
+          }
+          else if (existingItemWithinResultSeq.equals(srch)) {
+              isSeqContains = true;
+              break;    
+          }
+       }
+       
+       return isSeqContains;
+       
+    }
 
 }
diff --git a/src/org/apache/xpath/compiler/Compiler.java b/src/org/apache/xpath/compiler/Compiler.java
index 03465d72..20b8da3d 100644
--- a/src/org/apache/xpath/compiler/Compiler.java
+++ b/src/org/apache/xpath/compiler/Compiler.java
@@ -221,7 +221,7 @@ public class Compiler extends OpMap
     case OpCodes.OP_FUNCTION :
       expr = compileFunction(opPos); break;
     case OpCodes.OP_INLINE_FUNCTION :
-      expr = compileInlineFunction(opPos); break;
+      expr = compileInlineFunctionDefinition(opPos); break;
     case OpCodes.OP_DYNAMIC_FUNCTION_CALL :
       expr = compileDynamicFunctionCall(opPos); break;
     case OpCodes.OP_LOCATIONPATH :
@@ -1292,36 +1292,124 @@ private static final boolean DEBUG = false;
     }
   }
   
-  Expression compileInlineFunction(int opPos) throws TransformerException
+  /**
+   * Compile an XPath function item inline function definition, expression.
+   * 
+   * @param opPos The current position in the m_opMap array.
+   *
+   * @return the compiled inline function definition expression returned
+   *         as an object of class InlineFunction. An object of class
+   *         InlineFunction has already been created and populated by XPath 
+   *         expression parser, and this function just returns that object
+   *         to the caller of this method.
+   *
+   * @throws TransformerException if a error occurs creating the Expression.
+   */
+  Expression compileInlineFunctionDefinition(int opPos) throws TransformerException
   {
       return XPathParser.fInlineFunction;
   }
   
+  /**
+   * Compile an XPath dynamic function call, expression.
+   * 
+   * @param opPos The current position in the m_opMap array.
+   *
+   * @return the compiled dynamic function call expression returned
+   *         as an object of class DynamicFunctionCall. An object of class
+   *         DynamicFunctionCall has already been created and populated by 
+   *         XPath expression parser, and this function just returns that
+   *         object to the caller of this method.
+   *
+   * @throws TransformerException if a error occurs creating the Expression.
+   */
   Expression compileDynamicFunctionCall(int opPos) throws TransformerException
   {
       return XPathParser.fDynamicFunctionCall;
   }
   
+  /**
+   * Compile an XPath "for", expression.
+   * 
+   * @param opPos The current position in the m_opMap array.
+   *
+   * @return the compiled "for" expression returned as an object of class
+   *         ForExpr. An object of class ForExpr has already been created and
+   *         populated by XPath expression parser, and this function just 
+   *         returns that object to the caller of this method.
+   *
+   * @throws TransformerException if a error occurs creating the Expression.
+   */
   Expression forExpr(int opPos) throws TransformerException
   {
       return XPathParser.fForExpr;
   }
   
+  /**
+   * Compile an XPath "let", expression.
+   * 
+   * @param opPos The current position in the m_opMap array.
+   *
+   * @return the compiled "let" expression returned as an object of class
+   *         LetExpr. An object of class LetExpr has already been created
+   *         and populated by XPath expression parser, and this function 
+   *         just returns that object to the caller of this method.
+   *
+   * @throws TransformerException if a error occurs creating the Expression.
+   */
   Expression letExpr(int opPos) throws TransformerException
   {
       return XPathParser.fLetExpr;
   }
   
+  /**
+   * Compile an XPath quantified, expression (either 'some' or 'every').
+   * 
+   * @param opPos The current position in the m_opMap array.
+   *
+   * @return the compiled quantified expression returned as an object of class
+   *         QuantifiedExpr. An object of class QuantifiedExpr has already
+   *         been created and populated by XPath expression parser, and 
+   *         this function just returns that object to the caller of this
+   *         method.
+   *
+   * @throws TransformerException if a error occurs creating the Expression.
+   */
   Expression quantifiedExpr(int opPos) throws TransformerException
   {
       return XPathParser.fQuantifiedExpr;
   }
   
+  /**
+   * Compile an XPath "if", expression.
+   * 
+   * @param opPos The current position in the m_opMap array.
+   *
+   * @return the compiled "if" expression returned as an object of class
+   *         IfExpr. An object of class IfExpr has already been created and
+   *         populated by XPath expression parser, and this function just 
+   *         returns that object to the caller of this method.       
+   *
+   * @throws TransformerException if a error occurs creating the Expression.
+   */
   Expression ifExpr(int opPos) throws TransformerException
   {
       return XPathParser.fIfExpr;
   }
   
+  /**
+   * Compile an XPath sequence constructor, expression.
+   * 
+   * @param opPos The current position in the m_opMap array.
+   *
+   * @return the compiled sequence constructor expression returned as an object
+   *         of class SimpleSequenceConstructor. An object of class
+   *         SimpleSequenceConstructor has already been created and populated by
+   *         XPath expression parser, and this function just returns that object 
+   *         to the caller of this method.       
+   *
+   * @throws TransformerException if a error occurs creating the Expression.
+   */
   Expression sequenceConstructorExpr(int opPos) throws TransformerException
   {
       return XPathParser.fSimpleSequenceConstructor;
diff --git a/src/org/apache/xpath/compiler/FunctionTable.java b/src/org/apache/xpath/compiler/FunctionTable.java
index 4b7cd76e..9e26f9e2 100644
--- a/src/org/apache/xpath/compiler/FunctionTable.java
+++ b/src/org/apache/xpath/compiler/FunctionTable.java
@@ -251,6 +251,12 @@ public class FunctionTable
   
   /** The 'seconds-from-duration()' id. */
   public static final int FUNC_SECONDS_FROM_DURATION = 75;
+  
+  /** The 'fold-left()' id. */
+  public static final int FUNC_FOLD_LEFT = 76;
+  
+  /** The 'fold-right()' id. */
+  public static final int FUNC_FOLD_RIGHT = 77;
 
   // Proprietary
 
@@ -308,7 +314,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 = 76;
+  private static final int NUM_BUILT_IN_FUNCS = 78;
 
   /**
    * Number of built-in functions that may be added.
@@ -410,6 +416,10 @@ public class FunctionTable
       org.apache.xpath.functions.FuncForEach.class;
     m_functions[FUNC_FILTER] = 
       org.apache.xpath.functions.FuncFilter.class;
+    m_functions[FUNC_FOLD_LEFT] = 
+      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;
     
@@ -615,6 +625,11 @@ public class FunctionTable
                          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));
   }
   
   public FunctionTable(){
diff --git a/src/org/apache/xpath/compiler/Keywords.java b/src/org/apache/xpath/compiler/Keywords.java
index 6ea12a24..d5732a83 100644
--- a/src/org/apache/xpath/compiler/Keywords.java
+++ b/src/org/apache/xpath/compiler/Keywords.java
@@ -329,6 +329,12 @@ 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/FuncDistinctValues.java b/src/org/apache/xpath/functions/FuncDistinctValues.java
index 03b0232c..7dc9701e 100644
--- a/src/org/apache/xpath/functions/FuncDistinctValues.java
+++ b/src/org/apache/xpath/functions/FuncDistinctValues.java
@@ -20,6 +20,7 @@ package org.apache.xpath.functions;
 import javax.xml.transform.SourceLocator;
 
 import org.apache.xalan.res.XSLMessages;
+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;
@@ -94,15 +95,18 @@ public class FuncDistinctValues extends Function2Args {
               
               if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ELEMENT_NODE) {
                  XSUntyped xsUntyped = new XSUntyped(nodeStrValue);                 
-                 addItemToResultSequence(resultSeq, xsUntyped, true);
+                 XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                           xsUntyped, true);
               }
               else if (dtm.getNodeType(nextNodeDtmHandle) == DTM.ATTRIBUTE_NODE) {
                  XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                 addItemToResultSequence(resultSeq, xsUntypedAtomic, true);
+                 XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                           xsUntypedAtomic, true);
               }
               else {
                  XSUntypedAtomic xsUntypedAtomic = new XSUntypedAtomic(nodeStrValue);
-                 addItemToResultSequence(resultSeq, xsUntypedAtomic, true);
+                 XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                           xsUntypedAtomic, true);
               }
            }
         }
@@ -112,10 +116,12 @@ public class FuncDistinctValues extends Function2Args {
               XObject xObj = inpResultSeq.item(idx);
               if (xObj instanceof XSAnyType) {
                  XSAnyType xsAnyType = (XSAnyType)xObj;
-                 addItemToResultSequence(resultSeq, xsAnyType, true);
+                 XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                             xsAnyType, true);
               }
               else {
-                 addItemToResultSequence(resultSeq, xObj, true);
+                  XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                             xObj, true);
               }
            }
         }
@@ -124,12 +130,13 @@ public class FuncDistinctValues extends Function2Args {
            // xdm singleton item.            
            if (arg0Obj instanceof XSAnyType) {
               XSAnyType xsAnyType = (XSAnyType)arg0Obj;
-              addItemToResultSequence(resultSeq, xsAnyType, false);
+              XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                          xsAnyType, false);
            }
            else {
               String seqItemStrValue = arg0Obj.str();
-              addItemToResultSequence(resultSeq, new XString(seqItemStrValue),
-                                                                         false);
+              XslTransformEvaluationHelper.addItemToResultSequence(resultSeq, 
+                                                                        new XString(seqItemStrValue), false);
            }
         }
             
@@ -160,78 +167,5 @@ public class FuncDistinctValues extends Function2Args {
       throw new WrongNumberArgsException(XSLMessages.createXPATHMessage(
                                               XPATHErrorResources.ER_ONE_OR_TWO, null)); //"1 or 2"
   }
-  
-  /**
-   * Add an xdm input item to result sequence, if that already doesn't exist within
-   * the result sequence. 
-   */
-  private void addItemToResultSequence(ResultSequence resultSeq, XObject inpItem, 
-                                                                     boolean cardinalityCheck) {
-      if (cardinalityCheck) {
-          if (resultSeq.size() == 0) {                     
-              resultSeq.add(inpItem);    
-          }
-          else if (!contains(resultSeq, inpItem)) {
-              resultSeq.add(inpItem);
-          }   
-      }
-      else {
-          resultSeq.add(inpItem);   
-      }
-  }
-  
-  /**
-   * Check whether a 'ResultSequence' object, contains a specific xdm item.
-   */
-  private boolean contains(ResultSequence resultSeq, XObject srch) {
-     
-     boolean isSeqContains = false;
-     
-     for (int idx = 0; idx < resultSeq.size(); idx++) {
-        XObject existingItemWithinResultSeq = resultSeq.item(idx);
-        if ((existingItemWithinResultSeq instanceof XSUntyped) && 
-                                                          (srch instanceof XSUntyped)) {
-           if (((XSUntyped)existingItemWithinResultSeq).equals((XSUntyped)srch)) {
-               isSeqContains = true;
-               break;    
-           }
-        }
-        else if ((existingItemWithinResultSeq instanceof XSUntypedAtomic) && 
-                                                                (srch instanceof XSUntypedAtomic)) {
-            if (((XSUntypedAtomic)existingItemWithinResultSeq).equals((XSUntypedAtomic)srch)) {
-               isSeqContains = true;
-               break;    
-            } 
-        }
-        else if ((existingItemWithinResultSeq instanceof XSUntyped) && 
-                                                              (srch instanceof XSUntypedAtomic)) {
-            if (((XSUntyped)existingItemWithinResultSeq).equals((XSUntypedAtomic)srch)) {
-               isSeqContains = true;
-               break;    
-            } 
-        }
-        else if ((existingItemWithinResultSeq instanceof XSUntypedAtomic) && 
-                                                              (srch instanceof XSUntyped)) {
-            if (((XSUntypedAtomic)existingItemWithinResultSeq).equals((XSUntyped)srch)) {
-               isSeqContains = true;
-               break;    
-            }
-        }
-        else if ((existingItemWithinResultSeq instanceof XSAnyType) && 
-                                                               (srch instanceof XSAnyType)) {
-            if (((XSAnyType)existingItemWithinResultSeq).equals((XSAnyType)srch)) {
-                isSeqContains = true;
-                break;    
-            }   
-        }
-        else if (existingItemWithinResultSeq.equals(srch)) {
-            isSeqContains = true;
-            break;    
-        }
-     }
-     
-     return isSeqContains;
-     
-  }
 
 }
diff --git a/src/org/apache/xpath/functions/FuncFoldLeft.java b/src/org/apache/xpath/functions/FuncFoldLeft.java
new file mode 100644
index 00000000..f67ef65b
--- /dev/null
+++ b/src/org/apache/xpath/functions/FuncFoldLeft.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 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.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+/*
+ * fn:fold-left 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:fold-left has following signature, and definition,
+ * 
+ * fn:fold-left($seq as item()*,
+                $zero as item()*,
+                $f as function(item()*, item()) as item()*) as item()*
+   
+ * The fn:fold-left function, processes the supplied sequence from left to right, 
+ * applying the supplied function repeatedly to each item in turn, together
+ * with an accumulated result value.
+ */
+public class FuncFoldLeft extends Function3Args {
+    
+    private static final long serialVersionUID = -3772850377799360556L;
+
+    public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
+    {
+        XObject result = null;
+        
+        SourceLocator srcLocator = xctxt.getSAXLocator();
+        
+        int contextNode = xctxt.getContextNode();
+        
+        ResultSequence foldLeftFirstArgResultSeq = null;
+        
+        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; 
+           }
+           else {
+              // REVISIT
+              foldLeftFirstArgResultSeq = new ResultSequence();
+              foldLeftFirstArgResultSeq.add(xObj);
+           }
+        }
+        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);
+                }                        
+            }
+        }
+        
+        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();
+           
+           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);              
+              for (int idx = 0; idx < foldLeftFirstArgResultSeq.size(); idx++) {
+                 Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
+                 
+                 inlineFunctionVarMap.put(new QName(funcItemSecondArgName), foldLeftFirstArgResultSeq.item(idx));
+              
+                 if (idx == 0) {                    
+                    inlineFunctionVarMap.put(new QName(funcItemFirstArgName), foldLeftBaseVal);
+                 }
+                 else {
+                    inlineFunctionVarMap.put(new QName(funcItemFirstArgName), 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();  
+           }
+        }
+        else {
+           result = new ResultSequence(); 
+        }
+        
+        return result;
+    }
+
+}
diff --git a/src/org/apache/xpath/functions/FuncFoldRight.java b/src/org/apache/xpath/functions/FuncFoldRight.java
new file mode 100644
index 00000000..0242122c
--- /dev/null
+++ b/src/org/apache/xpath/functions/FuncFoldRight.java
@@ -0,0 +1,213 @@
+/*
+ * 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.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.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+/*
+ * fn:fold-right 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:fold-right has following signature, and definition,
+ * 
+ * fn:fold-right($seq as item()*,
+                 $zero as item()*,
+                 $f as function(item(), item()*) as item()*) as item()*
+
+ * The fn:fold-right function, processes the supplied sequence from right to left, 
+ * applying the supplied function repeatedly to each item in turn, together with
+ * an accumulated result value.
+ */
+public class FuncFoldRight extends Function3Args {
+    
+    private static final long serialVersionUID = 4675724832355053777L;
+
+    public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
+    {
+        XObject result = null;
+        
+        SourceLocator srcLocator = xctxt.getSAXLocator();
+        
+        int contextNode = xctxt.getContextNode();
+        
+        ResultSequence foldRightFirstArgResultSeq = null;
+        
+        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; 
+           }
+           else {
+              // REVISIT
+              foldRightFirstArgResultSeq = new ResultSequence();
+              foldRightFirstArgResultSeq.add(xObj);               
+           }
+        }
+        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);
+                }                        
+            }
+        }
+        
+        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();
+           
+           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);              
+              for (int idx = foldRightFirstArgResultSeq.size() - 1; idx >= 0; idx--) {
+                 Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
+                 
+                 inlineFunctionVarMap.put(new QName(funcItemFirstArgName), foldRightFirstArgResultSeq.item(idx));
+              
+                 if (idx == (foldRightFirstArgResultSeq.size() - 1)) {                    
+                    inlineFunctionVarMap.put(new QName(funcItemSecondArgName), foldRightBaseVal);
+                 }
+                 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();  
+           }
+        }
+        else {
+           result = new ResultSequence(); 
+        }
+        
+        return result;
+    }
+
+}
diff --git a/src/org/apache/xpath/operations/Mult.java b/src/org/apache/xpath/operations/Mult.java
index e6c0bbbf..dcae69ad 100644
--- a/src/org/apache/xpath/operations/Mult.java
+++ b/src/org/apache/xpath/operations/Mult.java
@@ -29,6 +29,8 @@ import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.xs.types.XSDouble;
 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;
 
 /**
@@ -85,6 +87,38 @@ public class Mult extends Operation
           
           result = new XNumber(lDouble * rDouble);
       }
+      else if ((left instanceof XNumber) && (right instanceof XSUntyped)) {
+          double lDouble = ((XNumber)left).num();
+          
+          java.lang.String rStrVal = ((XSUntyped)right).stringValue();
+          double rDouble = (Double.valueOf(rStrVal)).doubleValue();
+          
+          result = new XNumber(lDouble * rDouble);
+      }
+      else if ((left instanceof XSUntyped) && (right instanceof XNumber)) {                    
+          java.lang.String lStrVal = ((XSUntyped)left).stringValue();
+          double lDouble = (Double.valueOf(lStrVal)).doubleValue();
+          
+          double rDouble = ((XNumber)right).num();
+          
+          result = new XNumber(lDouble * rDouble);
+      }
+      else if ((left instanceof XNumber) && (right instanceof XSUntypedAtomic)) {
+          double lDouble = ((XNumber)left).num();
+          
+          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 XNumber)) {                    
+          java.lang.String lStrVal = ((XSUntypedAtomic)left).stringValue();
+          double lDouble = (Double.valueOf(lStrVal)).doubleValue();
+          
+          double rDouble = ((XNumber)right).num();
+          
+          result = new XNumber(lDouble * rDouble);
+      }
       else if ((left instanceof XNumber) && (right instanceof XNodeSet)) {
           double lDouble = ((XNumber)left).num();
           
diff --git a/tests/fn_fold_left/gold/test1.out b/tests/fn_fold_left/gold/test1.out
new file mode 100644
index 00000000..f6cf66a0
--- /dev/null
+++ b/tests/fn_fold_left/gold/test1.out
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val1>15</val1>
+  <val2>120</val2>
+  <val3>0</val3>
+  <val4>-15</val4>
+  <val5>210</val5>
+  <val6>true</val6>
+  <val7>false</val7>
+  <val8>5 4 3 2 1</val8>
+  <val9>zabc</val9>
+</result>
diff --git a/tests/fn_fold_left/gold/test2.out b/tests/fn_fold_left/gold/test2.out
new file mode 100644
index 00000000..6293ebe4
--- /dev/null
+++ b/tests/fn_fold_left/gold/test2.out
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val1>-15</val1>
+  <val2>210</val2>
+  <val3>210</val3>
+</result>
diff --git a/tests/fn_fold_left/gold/test3.out b/tests/fn_fold_left/gold/test3.out
new file mode 100644
index 00000000..a9b215ba
--- /dev/null
+++ b/tests/fn_fold_left/gold/test3.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val1>210</val1>
+  <val2>210</val2>
+</result>
diff --git a/tests/fn_fold_left/test1.xsl b/tests/fn_fold_left/test1.xsl
new file mode 100644
index 00000000..5fa07459
--- /dev/null
+++ b/tests/fn_fold_left/test1.xsl
@@ -0,0 +1,87 @@
+<?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:fold-left() function.
+   
+        The XPath fn:fold-left() 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"/>
+   
+   <!-- 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 : 
+             (((((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 : 
+             (((((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 : 
+             (((((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 : 
+             (((((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 
+             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 
+             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 
+             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>
+        
+        <!-- The fold-left function call below, reverses the order of xdm items within an input 
+             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 :
+             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>
+      </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_fold_left/test1_a.xml b/tests/fn_fold_left/test1_a.xml
new file mode 100644
index 00000000..b6df0232
--- /dev/null
+++ b/tests/fn_fold_left/test1_a.xml
@@ -0,0 +1,7 @@
+<temp from="1" to="5">
+  <val>2</val>
+  <val>3</val>
+  <val>5</val>
+  <val>7</val>
+  <data val1="2" val2="3" val3="5" val4="7"/>
+</temp>
\ No newline at end of file
diff --git a/tests/fn_fold_left/test2.xsl b/tests/fn_fold_left/test2.xsl
new file mode 100644
index 00000000..c802a402
--- /dev/null
+++ b/tests/fn_fold_left/test2.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_a.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:fold-left() function -->                
+
+   <xsl:output method="xml" indent="yes"/>
+      
+   <xsl:template match="/temp">      
+      <result>
+        <val1><xsl:value-of select="fold-left(@from to @to, 0, function($arg1, $arg2) { $arg1 - $arg2 })"/></val1>
+        
+        <val2><xsl:value-of select="fold-left(val, 1, function($a, $b) { $a * $b })"/></val2>
+        
+        <val3><xsl:value-of select="fold-left(data/@*, 1, function($a, $b) { $a * $b })"/></val3>
+      </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_fold_left/test3.xsl b/tests/fn_fold_left/test3.xsl
new file mode 100644
index 00000000..f87e6b5e
--- /dev/null
+++ b/tests/fn_fold_left/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_a.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:fold-left() function -->                   
+
+   <xsl:output method="xml" indent="yes"/>
+      
+   <xsl:template match="/temp">      
+      <result>
+        <xsl:variable name="valList1" select="val"/>
+        <val1><xsl:value-of select="fold-left($valList1, 1, function($a, $b) { $a * $b })"/></val1>
+        
+        <xsl:variable name="valList2" select="data/@*"/>
+        <val2><xsl:value-of select="fold-left($valList2, 1, function($a, $b) { $a * $b })"/></val2>
+      </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_fold_right/gold/test1.out b/tests/fn_fold_right/gold/test1.out
new file mode 100644
index 00000000..c22ff00b
--- /dev/null
+++ b/tests/fn_fold_right/gold/test1.out
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val1>15</val1>
+  <val2>3</val2>
+  <val3>abcz</val3>
+</result>
diff --git a/tests/fn_fold_right/gold/test2.out b/tests/fn_fold_right/gold/test2.out
new file mode 100644
index 00000000..76e4b5c3
--- /dev/null
+++ b/tests/fn_fold_right/gold/test2.out
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val1>3</val1>
+  <val2>210</val2>
+  <val3>210</val3>
+</result>
diff --git a/tests/fn_fold_right/gold/test3.out b/tests/fn_fold_right/gold/test3.out
new file mode 100644
index 00000000..a9b215ba
--- /dev/null
+++ b/tests/fn_fold_right/gold/test3.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val1>210</val1>
+  <val2>210</val2>
+</result>
diff --git a/tests/fn_fold_right/test1.xsl b/tests/fn_fold_right/test1.xsl
new file mode 100644
index 00000000..edb86ec7
--- /dev/null
+++ b/tests/fn_fold_right/test1.xsl
@@ -0,0 +1,44 @@
+<?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:fold-right() function.
+   
+        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/. -->                 
+
+   <xsl:output method="xml" indent="yes"/>
+      
+   <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>
+      </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_fold_right/test1_a.xml b/tests/fn_fold_right/test1_a.xml
new file mode 100644
index 00000000..b6df0232
--- /dev/null
+++ b/tests/fn_fold_right/test1_a.xml
@@ -0,0 +1,7 @@
+<temp from="1" to="5">
+  <val>2</val>
+  <val>3</val>
+  <val>5</val>
+  <val>7</val>
+  <data val1="2" val2="3" val3="5" val4="7"/>
+</temp>
\ No newline at end of file
diff --git a/tests/fn_fold_right/test2.xsl b/tests/fn_fold_right/test2.xsl
new file mode 100644
index 00000000..297a7d8e
--- /dev/null
+++ b/tests/fn_fold_right/test2.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_a.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:fold-right() function -->                
+
+   <xsl:output method="xml" indent="yes"/>
+      
+   <xsl:template match="/temp">      
+      <result>
+        <val1><xsl:value-of select="fold-right(@from to @to, 0, function($arg1, $arg2) { $arg1 - $arg2 })"/></val1>
+        
+        <val2><xsl:value-of select="fold-right(val, 1, function($a, $b) { $a * $b })"/></val2>
+        
+        <val3><xsl:value-of select="fold-right(data/@*, 1, function($a, $b) { $a * $b })"/></val3>
+      </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_fold_right/test3.xsl b/tests/fn_fold_right/test3.xsl
new file mode 100644
index 00000000..39e7d104
--- /dev/null
+++ b/tests/fn_fold_right/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_a.xml -->
+   
+   <!-- Test for the XPath 3.1 fn:fold-right() function -->                   
+
+   <xsl:output method="xml" indent="yes"/>
+      
+   <xsl:template match="/temp">      
+      <result>
+        <xsl:variable name="valList1" select="val"/>
+        <val1><xsl:value-of select="fold-right($valList1, 1, function($a, $b) { $a * $b })"/></val1>
+        
+        <xsl:variable name="valList2" select="data/@*"/>
+        <val2><xsl:value-of select="fold-right($valList2, 1, function($a, $b) { $a * $b })"/></val2>
+      </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/org/apache/xalan/xpath3/FnFoldLeftTests.java b/tests/org/apache/xalan/xpath3/FnFoldLeftTests.java
new file mode 100644
index 00000000..8cd730d2
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/FnFoldLeftTests.java
@@ -0,0 +1,82 @@
+/*
+ * 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:fold-left test cases.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class FnFoldLeftTests extends XslTransformTestsUtil {        
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + 
+                                                                                                     "fn_fold_left/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + 
+                                                                                                     "fn_fold_left/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 xslFnFoldLeftTest1() {
+        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 xslFnFoldLeftTest2() {
+        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 xslFnFoldLeftTest3() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.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/FnFoldRightTests.java b/tests/org/apache/xalan/xpath3/FnFoldRightTests.java
new file mode 100644
index 00000000..7c9fa461
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/FnFoldRightTests.java
@@ -0,0 +1,82 @@
+/*
+ * 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:fold-right test cases.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class FnFoldRightTests extends XslTransformTestsUtil {        
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + 
+                                                                                                         "fn_fold_right/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + 
+                                                                                                         "fn_fold_right/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 xslFnFoldRightTest1() {
+        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 xslFnFoldRightTest2() {
+        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 xslFnFoldRightTest3() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.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/xslt3/AllXsl3Tests.java b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
index 6227f74e..b2904159 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -22,6 +22,8 @@ import org.apache.xalan.xpath3.DynamicFunctionCallTests;
 import org.apache.xalan.xpath3.FnAbsTests;
 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.FnForEachTests;
 import org.apache.xalan.xpath3.FnIndexOfTests;
 import org.apache.xalan.xpath3.FnStringJoinTests;
@@ -72,7 +74,8 @@ import org.junit.runners.Suite.SuiteClasses;
                 TrignometricAndExponentialFunctionTests.class, BuiltinFunctionsNamespceTests.class,
                 SequenceConstructorTests.class, StringConcatExprTests.class, 
                 XsDurationComponentExtractionFunctionTests.class, XPathArithmeticOnDurationValuesTests.class,
-                NodeComparisonTests.class, SimpleMapOperatorTests.class })
+                NodeComparisonTests.class, SimpleMapOperatorTests.class, FnFoldLeftTests.class,
+                FnFoldRightTests.class })
 public class AllXsl3Tests {
 
 }


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