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/07/13 13:58:58 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xpath 3.1 'for' expression, and few new related working test cases as well. also modifications and refactoring to, few other parts of xalanj xslt 3.0 implementation that were affected by xpath 3.1 'for' expression implementation.

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 0919fddf committing implementation of xpath 3.1 'for' expression, and few new related working test cases as well. also modifications and refactoring to, few other parts of xalanj xslt 3.0 implementation that were affected by xpath 3.1 'for' expression implementation.
     new b5001280 Merge pull request #26 from mukulga/xalan-j_xslt3.0_mukul
0919fddf is described below

commit 0919fddfe4fee8ae35f89b6fb2682df28c8610ca
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Thu Jul 13 19:21:34 2023 +0530

    committing implementation of xpath 3.1 'for' expression, and few new related working test cases as well. also modifications and refactoring to, few other parts of xalanj xslt 3.0 implementation that were affected by xpath 3.1 'for' expression implementation.
---
 src/org/apache/xalan/templates/ElemForEach.java    |  17 +-
 src/org/apache/xpath/Expression.java               |  19 +-
 src/org/apache/xpath/XPathContext.java             |  46 +++--
 src/org/apache/xpath/compiler/Compiler.java        |   7 +
 src/org/apache/xpath/compiler/OpCodes.java         |   6 +-
 src/org/apache/xpath/compiler/XPathParser.java     | 104 +++++++++-
 src/org/apache/xpath/composite/ForExpr.java        | 213 +++++++++++++++++++++
 .../apache/xpath/composite/ForExprVarBinding.java  |  52 +++++
 src/org/apache/xpath/composite/IfExpr.java         |  17 +-
 .../xpath/functions/DynamicFunctionCall.java       |   4 +-
 src/org/apache/xpath/functions/FuncCount.java      |  11 +-
 src/org/apache/xpath/functions/FuncFilter.java     |  15 +-
 src/org/apache/xpath/functions/FuncForEach.java    |  17 +-
 src/org/apache/xpath/functions/FuncSum.java        |  64 +++++--
 src/org/apache/xpath/operations/Variable.java      |  24 +--
 tests/for_expr/gold/test1.out                      |   3 +
 tests/for_expr/gold/test2.out                      |   3 +
 tests/for_expr/gold/test3.out                      |   3 +
 tests/for_expr/gold/test4.out                      |   1 +
 tests/for_expr/gold/test5.out                      |  10 +
 tests/for_expr/test1.xsl                           |  41 ++++
 tests/for_expr/test1_a.xml                         |  10 +
 tests/for_expr/test2.xsl                           |  45 +++++
 tests/for_expr/test3.xsl                           |  45 +++++
 tests/for_expr/test4.xsl                           |  36 ++++
 tests/for_expr/test5.xsl                           |  38 ++++
 tests/org/apache/xalan/xpath3/ForExprTests.java    | 100 ++++++++++
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java     |   4 +-
 28 files changed, 854 insertions(+), 101 deletions(-)

diff --git a/src/org/apache/xalan/templates/ElemForEach.java b/src/org/apache/xalan/templates/ElemForEach.java
index 27d007b0..ca67254d 100644
--- a/src/org/apache/xalan/templates/ElemForEach.java
+++ b/src/org/apache/xalan/templates/ElemForEach.java
@@ -37,6 +37,7 @@ import org.apache.xpath.Expression;
 import org.apache.xpath.ExpressionOwner;
 import org.apache.xpath.XPath;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.composite.ForExpr;
 import org.apache.xpath.functions.Function;
 import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XObject;
@@ -46,10 +47,10 @@ import org.apache.xpath.operations.Variable;
 /**
  * XSLT 3.0 for-each element.
  * 
-   <xsl:for-each 
-             select = expression>
-       <!-- Content: (xsl:sort*, sequence-constructor) -->
-   </xsl:for-each>
+ * <xsl:for-each 
+ *           select = expression>
+ *     <!-- Content: (xsl:sort*, sequence-constructor) -->
+ * </xsl:for-each>
  * 
  * @xsl.usage advanced
  */
@@ -370,6 +371,14 @@ public class ElemForEach extends ElemTemplateElement implements ExpressionOwner
         }
     }
     
+    if (m_selectExpression instanceof ForExpr) {
+        ForExpr forExpr = (ForExpr)m_selectExpression;
+        XObject  evalResult = forExpr.execute(xctxt);
+        processResultSequence(transformer, xctxt, evalResult);
+        transformer.setXPathContext(xctxtOriginal);
+        return;
+    }
+    
     // process the node-set, with body of xsl:for-each element as usual 
     final int sourceNode = xctxt.getCurrentNode();
     DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
diff --git a/src/org/apache/xpath/Expression.java b/src/org/apache/xpath/Expression.java
index e13d63ca..5b580a52 100644
--- a/src/org/apache/xpath/Expression.java
+++ b/src/org/apache/xpath/Expression.java
@@ -20,6 +20,9 @@
  */
 package org.apache.xpath;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.xml.transform.ErrorListener;
 import javax.xml.transform.TransformerException;
 
@@ -47,15 +50,19 @@ public abstract class Expression implements java.io.Serializable, ExpressionNode
   static final long serialVersionUID = 565665869777906902L;
   
   /**
-   * The location where this expression was built from.  Need for diagnostic
-   *  messages. May be null.
-   *  @serial
+   * The location where this expression was built from. Needed for diagnostic
+   * messages. May be null.
    */
   private ExpressionNode m_parent;
   
-  // to support, XPath.fixupVariables(..) action when done for XPath
-  // function item "inline function" body's XPath expression.
-  protected static QName m_inlineFnVariableName = null;
+  /** 
+   * XPath 3.1 support for, XPath.fixupVariables(..) action for
+   * feature implementations like XPath function item, "for" expression.
+   * 
+   * XPath variable references, within these XPath 3.1 features are not 
+   * stored within XPath context's variable stack.
+   */
+  protected static List<QName> m_xpathVarList = new ArrayList<QName>();
 
   /**
    * Tell if this expression or it's subexpressions can traverse outside
diff --git a/src/org/apache/xpath/XPathContext.java b/src/org/apache/xpath/XPathContext.java
index ef617fad..9221b7e0 100644
--- a/src/org/apache/xpath/XPathContext.java
+++ b/src/org/apache/xpath/XPathContext.java
@@ -100,28 +100,28 @@ public class XPathContext extends DTMManager // implements ExpressionContext
    */
   private boolean m_isSecureProcessing = false;
   
-  /*
-   *  data value, representing the XPath 3.1's current 
-   *  evaluation context item.
+  /**
+   *  This data value, represents the XPath 3.1's current evaluation 
+   *  context item.
    */
   private XObject m_xpath3ContextItem = null;
   
-  /*
-   *  data value, representing the XPath 3.1's current 
-   *  evaluation context position.
+  /**
+   *  This data value, represents the XPath 3.1's current evaluation 
+   *  context position.
    */
   private int m_xpath3ContextPosition = -1;
   
-  /*
-   *  data value, representing the XPath 3.1's current 
-   *  evaluation context size.
+  /**
+   *  This data value, represents the XPath 3.1's current evaluation 
+   *  context size.
    */
   private int m_xpath3ContextSize = -1; 
   
-  /*
-   * this data value, can be used to store custom data 
-   * (represented as a java.util.Map object) within the 
-   * current XPath evaluation context.
+  /**
+   * This data value, represents certain custom data (represented 
+   * as a java.util.Map object) within the current XPath 3.1 evaluation 
+   * context.
    */
   private Map<String, String> m_customDataMap = new HashMap<String, String>();
   
@@ -129,10 +129,14 @@ public class XPathContext extends DTMManager // implements ExpressionContext
   
   private XSDuration m_timezone;
   
-  // we use this java.util.Map object, to store for XPath 3.1 function item 
-  // "inline function", the parameter names and their values. we don't use,
-  // XalanJ XPath context's variable stack for this purpose. 
-  private Map<QName, XObject> inlineFunctionVarMap = new HashMap<QName, XObject>();
+  /**
+   * We use this java.util.Map object, to store XPath 3.1 variable binding
+   * information (i.e, a mapping from variable name to its run-time value). 
+   * These variable bindings, are used for XPath feature implementations 
+   * like function item, 'for' expression.
+   * We don't use, XalanJ XPath context's variable stack for this purpose.
+   */
+  private Map<QName, XObject> xpathVarMap = new HashMap<QName, XObject>();
 	
   /**
    * Though XPathContext context extends 
@@ -1457,12 +1461,12 @@ public class XPathContext extends DTMManager // implements ExpressionContext
      this.m_timezone = timezone;
  }
 
- public Map<QName, XObject> getInlineFunctionVarMap() {
-     return inlineFunctionVarMap;
+ public Map<QName, XObject> getXPathVarMap() {
+     return xpathVarMap;
  }
 
- public void setInlineFunctionVarMap(Map<QName, XObject> inlineFunctionVarMap) {
-     this.inlineFunctionVarMap = inlineFunctionVarMap;
+ public void setXPathVarMap(Map<QName, XObject> xpathVarMap) {
+     this.xpathVarMap = xpathVarMap;
  }
   
 }
diff --git a/src/org/apache/xpath/compiler/Compiler.java b/src/org/apache/xpath/compiler/Compiler.java
index b67d3c51..f45b6a1c 100644
--- a/src/org/apache/xpath/compiler/Compiler.java
+++ b/src/org/apache/xpath/compiler/Compiler.java
@@ -129,6 +129,8 @@ public class Compiler extends OpMap
     {
     case OpCodes.OP_XPATH :
       expr = compile(opPos + 2); break;
+    case OpCodes.OP_FOR_EXPR :
+      expr = forExpr(opPos); break;
     case OpCodes.OP_IF_EXPR :
       expr = ifExpr(opPos); break;
     case OpCodes.OP_OR :
@@ -1173,6 +1175,11 @@ private static final boolean DEBUG = false;
       return XPathParser.fDynamicFunctionCall;
   }
   
+  Expression forExpr(int opPos) throws TransformerException
+  {
+      return XPathParser.fForExpr;
+  }
+  
   Expression ifExpr(int opPos) throws TransformerException
   {
       return XPathParser.fIfExpr;
diff --git a/src/org/apache/xpath/compiler/OpCodes.java b/src/org/apache/xpath/compiler/OpCodes.java
index 92fb38f5..81e096f2 100644
--- a/src/org/apache/xpath/compiler/OpCodes.java
+++ b/src/org/apache/xpath/compiler/OpCodes.java
@@ -680,9 +680,11 @@ public class OpCodes
   
   public static final int OP_DYNAMIC_FUNCTION_CALL = 62;
   
-  public static final int OP_IF_EXPR = 63;
+  public static final int OP_FOR_EXPR = 63;
+  
+  public static final int OP_IF_EXPR = 64;
 
   /** The next free ID. Please keep this up to date. */
-  private static final int NEXT_FREE_ID = 64;
+  private static final int NEXT_FREE_ID = 65;
   
 }
diff --git a/src/org/apache/xpath/compiler/XPathParser.java b/src/org/apache/xpath/compiler/XPathParser.java
index 3fdbfd37..e657f779 100644
--- a/src/org/apache/xpath/compiler/XPathParser.java
+++ b/src/org/apache/xpath/compiler/XPathParser.java
@@ -30,6 +30,8 @@ import javax.xml.transform.TransformerException;
 import org.apache.xalan.res.XSLMessages;
 import org.apache.xml.utils.PrefixResolver;
 import org.apache.xpath.XPathProcessorException;
+import org.apache.xpath.composite.ForExpr;
+import org.apache.xpath.composite.ForExprVarBinding;
 import org.apache.xpath.composite.IfExpr;
 import org.apache.xpath.domapi.XPathStylesheetDOM3Exception;
 import org.apache.xpath.functions.DynamicFunctionCall;
@@ -82,13 +84,14 @@ public class XPathParser
   /*
    * While parsing certain XPath 3.1 expressions, we use this constant string 
    * array to make parse decisions. The elements of this array are certain 
-   * XPath 'operator names' and 'key words' that need this support.
+   * XPath 'operator names', 'key words' and symbols that need this support.
    */
   private static final String[] XPATH_OP_ARR = new String[] {"div", "or", "and", "mod", "to", 
                                                               "eq", "ne", "lt", "gt", "le", "ge", 
-                                                              "if", "then", "else"};
+                                                              "for", "in", "return", "if", "then", 
+                                                              "else", "-"};
   
-  private List<String> fXpathOpArrTokensList = null;
+  private static final List<String> fXpathOpArrTokensList = Arrays.asList(XPATH_OP_ARR);
   
   private boolean fDynamicFunctionCallArgumentMarker = false;
   
@@ -98,6 +101,8 @@ public class XPathParser
   
   static DynamicFunctionCall fDynamicFunctionCall = null;
   
+  static ForExpr fForExpr = null;
+  
   static IfExpr fIfExpr = null;
   
   /**
@@ -107,7 +112,6 @@ public class XPathParser
   {
     m_errorListener = errorListener;
     m_sourceLocator = sourceLocator;
-    fXpathOpArrTokensList = Arrays.asList(XPATH_OP_ARR);
   }
 
   /**
@@ -885,14 +889,23 @@ public class XPathParser
   /**
    *
    *
-   * Expr  ::=  IfExpr 
+   * Expr  ::=  ForExpr
+   *   | IfExpr 
    *   | OrExpr
    *
    * @throws javax.xml.transform.TransformerException
    */
   protected void Expr() throws javax.xml.transform.TransformerException
   {
-      if (tokenIs("if")) {         
+      if (tokenIs("for")) {
+         // to check, whether xpath 'for' expression is a sub expression of another 
+         // xpath expression (for e.g, a 'for' expression could be a function 
+         // argument).
+         String prevTokenStr = getTokenRelative(-2);
+         
+         fForExpr = ForExpr(prevTokenStr);
+      }
+      else if (tokenIs("if")) {         
          fIfExpr = IfExpr();
       }
       else {
@@ -900,6 +913,85 @@ public class XPathParser
       }
   }
   
+  protected ForExpr ForExpr(String prevTokenStrBeforeFor) throws javax.xml.transform.TransformerException
+  {
+      int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH);
+      
+      nextToken();
+      
+      insertOp(opPos, 2, OpCodes.OP_FOR_EXPR);
+      
+      ForExpr forExpr = new ForExpr();
+      
+      List<ForExprVarBinding> forExprVarBindingList = new  ArrayList<ForExprVarBinding>();
+      
+      while (!tokenIs("return") && m_token != null)
+      {
+          String bindingVarName = null;
+          
+          if (forExprVarBindingList.size() > 0 && tokenIs(',')) {
+             nextToken();    
+          }
+          
+          if (tokenIs('$')) {
+              nextToken();              
+              bindingVarName = m_token;              
+              nextToken();              
+              consumeExpected("in");                            
+          }
+          
+          List<String> bindingXPathExprStrPartsList = new ArrayList<String>();
+          
+          while (!(tokenIs(',') || tokenIs("return")) && m_token != null) {
+             bindingXPathExprStrPartsList.add(m_token);
+             nextToken();
+          }
+          
+          String varBindingXpathStr = getXPathStrFromComponentParts(
+                                                                bindingXPathExprStrPartsList);
+          
+          ForExprVarBinding forExprVarBinding = new ForExprVarBinding();
+          forExprVarBinding.setVarName(bindingVarName);
+          forExprVarBinding.setXpathExprStr(varBindingXpathStr);
+          
+          forExprVarBindingList.add(forExprVarBinding);
+          
+          if (tokenIs("return")) {
+             break; 
+          }
+      }      
+      
+      consumeExpected("return");
+      
+      List<String> xPathReturnExprStrPartsList = new ArrayList<String>();
+      
+      while (m_token != null) {
+         if (tokenIs(')')) {            
+            if ((getTokenRelative(0) == null) && "(".equals(prevTokenStrBeforeFor)) {
+               break;    
+            }
+            else {
+               xPathReturnExprStrPartsList.add(m_token);
+               nextToken();
+            }
+         }
+         else {
+            xPathReturnExprStrPartsList.add(m_token);
+            nextToken();
+         }
+      }
+      
+      String xPathReturnExprStr = getXPathStrFromComponentParts(xPathReturnExprStrPartsList);
+      
+      forExpr.setForExprVarBindingList(forExprVarBindingList);
+      forExpr.setReturnExprXPathStr(xPathReturnExprStr);
+      
+      m_ops.setOp(opPos + OpMap.MAPINDEX_LENGTH,
+                                            m_ops.getOp(OpMap.MAPINDEX_LENGTH) - opPos);
+      
+      return forExpr;
+  }
+  
   protected IfExpr IfExpr() throws javax.xml.transform.TransformerException
   {
       int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH);
diff --git a/src/org/apache/xpath/composite/ForExpr.java b/src/org/apache/xpath/composite/ForExpr.java
new file mode 100644
index 00000000..23f07c49
--- /dev/null
+++ b/src/org/apache/xpath/composite/ForExpr.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.composite;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.utils.QName;
+import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionOwner;
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.XPathVisitor;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XNodeSet;
+import org.apache.xpath.objects.XObject;
+
+/*
+ * The XalanJ xpath parser, creates and populates an object of this class, 
+ * as a representation of XPath 3.1 "for" expression.
+ * 
+ * The XPath 3.1 spec, defines "for" expression with following grammar,
+ * 
+ *  ForExpr               ::=      SimpleForClause "return" ExprSingle 
+ *  SimpleForClause       ::=      "for" SimpleForBinding ("," SimpleForBinding)*  
+ *  SimpleForBinding      ::=      "$" VarName "in" ExprSingle
+ *    
+ *  Ref : https://www.w3.org/TR/xpath-31/#id-for-expressions
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class ForExpr extends Expression {
+    
+    private static final long serialVersionUID = -7289739978026057248L;
+
+    private List<ForExprVarBinding> fForExprVarBindingList = new 
+                                                    ArrayList<ForExprVarBinding>();
+    
+    private String fReturnExprXPathStr = null;
+    
+    // the following two fields of this class, are used during 
+    // XPath.fixupVariables(..) action as performed within object of 
+    // this class.    
+    private Vector fVars;    
+    private int fGlobalsSize;
+
+    @Override
+    public void callVisitors(ExpressionOwner owner, XPathVisitor visitor) {
+       // no op
+    }
+    
+    @Override
+    public XObject execute(XPathContext xctxt) throws TransformerException {
+       ResultSequence resultSeq = new ResultSequence();
+       
+       SourceLocator srcLocator = xctxt.getSAXLocator();
+       
+       XPath returnExprXpath = new XPath(fReturnExprXPathStr, srcLocator, null, XPath.SELECT, null);
+       
+       resultSeq = getForExpressionEvalResult(fForExprVarBindingList.listIterator(), 
+                                                                            returnExprXpath, xctxt);
+       m_xpathVarList.clear();
+       
+       return resultSeq;
+    }
+
+    @Override
+    public void fixupVariables(Vector vars, int globalsSize) {
+       fVars = (Vector)(vars.clone());
+       fGlobalsSize = globalsSize; 
+    }
+
+    @Override
+    public boolean deepEquals(Expression expr) {        
+       return false;
+    }
+
+    public List<ForExprVarBinding> getForExprVarBindingList() {
+        return fForExprVarBindingList;
+    }
+
+    public void setForExprVarBindingList(List<ForExprVarBinding> forExprVarBindingList) {
+        this.fForExprVarBindingList = forExprVarBindingList;
+    }
+
+    public String getReturnExprXPathStr() {
+        return fReturnExprXPathStr;
+    }
+
+    public void setReturnExprXPathStr(String returnExprXPathStr) {
+        this.fReturnExprXPathStr = returnExprXPathStr;
+    }
+    
+    /*
+     * This method, does all the evaluations needed to determine the final evaluation result 
+     * of the XPath 'for' expression, returned as a 'ResultSequence' object.
+     */
+    private ResultSequence getForExpressionEvalResult(ListIterator listIter, 
+                                                                     XPath returnExprXpath, 
+                                                                     XPathContext xctxt) throws TransformerException {
+        ResultSequence resultSeq = new ResultSequence();
+        
+        SourceLocator srcLocator = xctxt.getSAXLocator();
+        
+        int contextNode = xctxt.getContextNode();
+        
+        Map<QName, XObject> forExprVarBindingMap = xctxt.getXPathVarMap();
+        
+        if (listIter.hasNext()) {           
+           ForExprVarBinding forExprVarBinding = (ForExprVarBinding)listIter.next();            
+            
+           // evaluate the current, variable binding xpath expression
+           
+           String varName = forExprVarBinding.getVarName();
+           String varBindingXPathStr = forExprVarBinding.getXpathExprStr();
+           
+           XPath varBindingXpath = new XPath(varBindingXPathStr, srcLocator, null, XPath.SELECT, null);
+           if (fVars != null) {
+              if (!m_xpathVarList.contains(new QName(varName))) {
+                 m_xpathVarList.add(new QName(varName));
+              }
+              varBindingXpath.fixupVariables(fVars, fGlobalsSize);
+           }
+           
+           XObject xsObj = varBindingXpath.execute(xctxt, contextNode, null);
+           
+           ResultSequence xsObjResultSeq = new ResultSequence(); 
+           
+           if (xsObj instanceof XNodeSet) {
+               XNodeSet xsObjNodeSet = (XNodeSet)xsObj;
+               DTMIterator dtmIter = xsObjNodeSet.iterRaw();
+               
+               int nextNodeDtmHandle;
+                      
+               while ((nextNodeDtmHandle = dtmIter.nextNode()) != DTM.NULL) {       
+                  XNodeSet singletonXPathNode = new XNodeSet(nextNodeDtmHandle, xctxt);
+                  xsObjResultSeq.add(singletonXPathNode);
+               }
+           }
+           else if (xsObj instanceof ResultSequence) {               
+               xsObjResultSeq = (ResultSequence)xsObj;
+           }
+           else {
+              // assuming here that, 'for' expression's variable binding XPath expression 
+              // evaluation, returned a singleton value.
+              xsObjResultSeq.add(xsObj);
+           }
+           
+           if (xsObjResultSeq.size() == 0) {
+               listIter.previous();
+               
+               return resultSeq;    
+           }
+           
+           // for each xdm item within sequence object 'xsObjResultSeq' (which is the 
+           // result of variable binding xpath expression's evaluation), bind the 'for' 
+           // expression range variable in turn to that item.
+           for (int idx = 0; idx < xsObjResultSeq.size(); idx++) {
+               XObject xdmItem = xsObjResultSeq.item(idx);
+                             
+               forExprVarBindingMap.put(new QName(varName), xdmItem);
+               
+               ResultSequence res = getForExpressionEvalResult(listIter, returnExprXpath, xctxt);
+               // append xdm items of sequence 'res', to the final sequence object 'resultSeq'   
+               for (int idx1 = 0; idx1 < res.size(); idx1++) {
+                  resultSeq.add(res.item(idx1));    
+               }
+           }
+           
+           listIter.previous();
+           
+           return resultSeq;
+        }
+        else {
+            // this else clause, actually evaluates the current XPath 'for' expression's 
+            // 'return' expression.
+            
+            if (fVars != null) {              
+               returnExprXpath.fixupVariables(fVars, fGlobalsSize);
+            }
+            
+            XObject retExprValue = returnExprXpath.execute(xctxt, contextNode, null);
+            resultSeq.add(retExprValue);
+            
+            return resultSeq; 
+        }
+    }
+
+}
diff --git a/src/org/apache/xpath/composite/ForExprVarBinding.java b/src/org/apache/xpath/composite/ForExprVarBinding.java
new file mode 100644
index 00000000..5b83c297
--- /dev/null
+++ b/src/org/apache/xpath/composite/ForExprVarBinding.java
@@ -0,0 +1,52 @@
+/*
+ * 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.composite;
+
+/*
+ * An object of this class, is used to store information about
+ * XPath 3.1 "for" expression's single variable binding (i.e, run-time
+ * information details related to the grammar fragment 
+ * "$" VarName "in" ExprSingle for a particular XPath "for" expression
+ * that's currently being evaluated). 
+ *  
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class ForExprVarBinding {
+    
+    private String fVarName = null;
+    
+    private String fXpathExprStr = null;
+
+    public String getVarName() {
+        return fVarName;
+    }
+
+    public void setVarName(String varName) {
+        this.fVarName = varName;
+    }
+
+    public String getXpathExprStr() {
+        return fXpathExprStr;
+    }
+
+    public void setXpathExprStr(String xpathExprStr) {
+        this.fXpathExprStr = xpathExprStr;
+    }
+
+}
diff --git a/src/org/apache/xpath/composite/IfExpr.java b/src/org/apache/xpath/composite/IfExpr.java
index 8fa4a6f0..e096d490 100644
--- a/src/org/apache/xpath/composite/IfExpr.java
+++ b/src/org/apache/xpath/composite/IfExpr.java
@@ -30,24 +30,13 @@ import org.apache.xpath.objects.XObject;
 
 /*
  * The XalanJ xpath parser, creates and populates an object of this class, 
- * as a representation of XPath 3.1 "if" conditional expressions.
+ * as a representation of XPath 3.1 "if" conditional expression.
  * 
- * XPath 3.1 spec, provides following definitions of conditional expressions.
+ * The XPath 3.1 spec, defines "if" expression with following grammar,
  * 
- * Grammar fragment,
  * IfExpr   ::=   "if" "(" Expr ")" "then" ExprSingle "else" ExprSingle
  * 
- * The expression following the if keyword is called the test expression, and 
- * the expressions following the then and else keywords are called the 
- * then-expression and else-expression, respectively.
- * 
- * The first step in processing a conditional expression is to find the 
- * effective boolean value of the test expression.
- * 
- * The value of a conditional expression is defined as follows: If the 
- * effective boolean value of the test expression is true, the value of 
- * the then-expression is returned. If the effective boolean value of the 
- * test expression is false, the value of the else-expression is returned.
+ * Ref : https://www.w3.org/TR/xpath-31/#id-conditionals
  * 
  * @author Mukul Gandhi <mu...@apache.org>
  * 
diff --git a/src/org/apache/xpath/functions/DynamicFunctionCall.java b/src/org/apache/xpath/functions/DynamicFunctionCall.java
index 6ebc6451..208204a3 100644
--- a/src/org/apache/xpath/functions/DynamicFunctionCall.java
+++ b/src/org/apache/xpath/functions/DynamicFunctionCall.java
@@ -104,7 +104,7 @@ public class DynamicFunctionCall extends Expression {
                                                        + "Number of arguments provided " + argList.size() + ".", xctxt.getSAXLocator());    
            }
            
-           Map<QName, XObject> inlineFunctionVarMap = xctxt.getInlineFunctionVarMap();
+           Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
            
            for (int idx = 0; idx < funcParamNameList.size(); idx++) {              
               String funcParamName = funcParamNameList.get(idx);
@@ -123,7 +123,7 @@ public class DynamicFunctionCall extends Expression {
            XPath inlineFnXpath = new XPath(inlineFnXpathStr, srcLocator, null, XPath.SELECT, null);
            evalResult = inlineFnXpath.execute(xctxt, contextNode, null);
            
-           inlineFunctionVarMap.clear();
+           inlineFunctionVarMap.clear();           
        }
         
        return evalResult;
diff --git a/src/org/apache/xpath/functions/FuncCount.java b/src/org/apache/xpath/functions/FuncCount.java
index 074c33d0..c81f2b54 100644
--- a/src/org/apache/xpath/functions/FuncCount.java
+++ b/src/org/apache/xpath/functions/FuncCount.java
@@ -23,6 +23,7 @@ package org.apache.xpath.functions;
 import org.apache.xml.dtm.DTMIterator;
 import org.apache.xpath.Expression;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.composite.ForExpr;
 import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XNodeSet;
 import org.apache.xpath.objects.XNumber;
@@ -74,10 +75,14 @@ public class FuncCount extends FunctionOneArg
                 ResultSequence resultSeq = (ResultSequence)(((Range)m_arg0).execute(xctxt));
                 count = resultSeq.size();
             }
+            else if (m_arg0 instanceof ForExpr) {
+                ResultSequence resultSeq = (ResultSequence)(((ForExpr)m_arg0).execute(xctxt));
+                count = resultSeq.size();   
+            }
             else {
-               DTMIterator nl = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
-               count = nl.getLength();	
-               nl.detach();
+                DTMIterator nl = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
+                count = nl.getLength();	
+                nl.detach();
             }
         }
     
diff --git a/src/org/apache/xpath/functions/FuncFilter.java b/src/org/apache/xpath/functions/FuncFilter.java
index c3152d3b..0aefe020 100644
--- a/src/org/apache/xpath/functions/FuncFilter.java
+++ b/src/org/apache/xpath/functions/FuncFilter.java
@@ -203,7 +203,7 @@ public class FuncFilter extends Function2Args {
         
         if (arg0XsObject instanceof ResultSequence) {
            XPathContext xpathContextNew = new XPathContext(false);
-           Map<QName, XObject> inlineFunctionVarMap = xpathContextNew.getInlineFunctionVarMap();
+           Map<QName, XObject> inlineFunctionVarMap = xpathContextNew.getXPathVarMap();
         
            ResultSequence inpResultSeq = (ResultSequence)arg0XsObject;
            for (int idx = 0; idx < inpResultSeq.size(); idx++) {
@@ -227,7 +227,7 @@ public class FuncFilter extends Function2Args {
            inlineFunctionVarMap.clear();
         }
         else if (arg0DtmIterator != null) {
-           Map<QName, XObject> inlineFunctionVarMap = xctxt.getInlineFunctionVarMap();
+           Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
         
            final int contextNode = xctxt.getCurrentNode();           
            
@@ -241,12 +241,11 @@ public class FuncFilter extends Function2Args {
                }
                
                if (fVars != null) {
-                  // this is used so that, 'fixupVariables' action performed below
-                  // shall work fine for function item parameter references within 
-                  // XPath expression denoted by 'inlineFnXpath'.
-                  m_inlineFnVariableName = varQname;               
-                  inlineFnXpath.fixupVariables(fVars, fGlobalsSize);               
-                  m_inlineFnVariableName = null;
+                  if (!m_xpathVarList.contains(varQname)) {
+                     m_xpathVarList.add(varQname);
+                  }
+                  inlineFnXpath.fixupVariables(fVars, fGlobalsSize);
+                  m_xpathVarList.remove(varQname);
                }
                
                XObject resultObj = inlineFnXpath.execute(xctxt, contextNode, null);
diff --git a/src/org/apache/xpath/functions/FuncForEach.java b/src/org/apache/xpath/functions/FuncForEach.java
index 72dda086..1c9ad874 100644
--- a/src/org/apache/xpath/functions/FuncForEach.java
+++ b/src/org/apache/xpath/functions/FuncForEach.java
@@ -206,7 +206,7 @@ public class FuncForEach extends Function2Args {
         
         if (arg0XsObject instanceof ResultSequence) {
            XPathContext xpathContextNew = new XPathContext(false);
-           Map<QName, XObject> inlineFunctionVarMap = xpathContextNew.getInlineFunctionVarMap();
+           Map<QName, XObject> inlineFunctionVarMap = xpathContextNew.getXPathVarMap();
         
            ResultSequence inpResultSeq = (ResultSequence)arg0XsObject;
            for (int idx = 0; idx < inpResultSeq.size(); idx++) {
@@ -222,7 +222,7 @@ public class FuncForEach extends Function2Args {
            inlineFunctionVarMap.clear();
         }
         else if (arg0DtmIterator != null) {                  
-           Map<QName, XObject> inlineFunctionVarMap = xctxt.getInlineFunctionVarMap();
+           Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();
             
            final int contextNode = xctxt.getCurrentNode();           
             
@@ -234,13 +234,12 @@ public class FuncForEach extends Function2Args {
                   inlineFunctionVarMap.put(varQname, inpSeqItem);
                }
                
-               if (fVars != null) {
-                  // this is used so that, 'fixupVariables' action performed below
-                  // shall work fine for function item parameter references within 
-                  // XPath expression denoted by 'inlineFnXpath'.
-                  m_inlineFnVariableName = varQname;
-                  inlineFnXpath.fixupVariables(fVars, fGlobalsSize);               
-                  m_inlineFnVariableName = null;
+               if (fVars != null) {                  
+                  if (!m_xpathVarList.contains(varQname)) {
+                     m_xpathVarList.add(varQname);
+                  }
+                  inlineFnXpath.fixupVariables(fVars, fGlobalsSize);
+                  m_xpathVarList.remove(varQname);
                }
                
                XObject resultObj = inlineFnXpath.execute(xctxt, contextNode, null);
diff --git a/src/org/apache/xpath/functions/FuncSum.java b/src/org/apache/xpath/functions/FuncSum.java
index c9bf252c..15d3ff5f 100644
--- a/src/org/apache/xpath/functions/FuncSum.java
+++ b/src/org/apache/xpath/functions/FuncSum.java
@@ -24,8 +24,13 @@ import org.apache.xml.dtm.DTM;
 import org.apache.xml.dtm.DTMIterator;
 import org.apache.xml.utils.XMLString;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.composite.ForExpr;
+import org.apache.xpath.objects.ResultSequence;
 import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XString;
+import org.apache.xpath.operations.Variable;
+import org.apache.xpath.xs.types.XSAnyType;
 
 /**
  * Execute the Sum() function.
@@ -45,20 +50,57 @@ public class FuncSum extends FunctionOneArg
    */
   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
   {
+    
+    double sum = 0.0;    
+    
+    if (m_arg0 instanceof Variable) {
+       Variable xslVariable = (Variable)m_arg0;
+       XObject resultObj = xslVariable.execute(xctxt);
+       if (resultObj instanceof ResultSequence) {
+          ResultSequence resultSeq = (ResultSequence)resultObj;
+          for (int idx = 0; idx < resultSeq.size(); idx++) {
+              XObject xObj = resultSeq.item(idx);
+              String str = xObj.str();
+              if (str != null) {
+                 XString xStr = new XString(str);
+                 sum +=  xStr.toDouble();
+              }
+          }
+       }
+    }
+    else if (m_arg0 instanceof ForExpr) {
+       ForExpr forExpr = (ForExpr)m_arg0;
+       ResultSequence forExprResult = (ResultSequence)(forExpr.execute(xctxt));
+       for (int idx = 0; idx < forExprResult.size(); idx++) {
+          XObject xObj = forExprResult.item(idx);
+          String str = null;
+          if (xObj instanceof XSAnyType) {
+             str = ((XSAnyType)xObj).stringValue();     
+          }
+          else {
+             str = xObj.str();
+          }
+          if (str != null) {
+             XString xStr = new XString(str);
+             sum +=  xStr.toDouble();
+          }
+       }
+    }
+    else {
+       int pos;
+        
+       DTMIterator nodes = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
 
-    DTMIterator nodes = m_arg0.asIterator(xctxt, xctxt.getCurrentNode());
-    double sum = 0.0;
-    int pos;
-
-    while (DTM.NULL != (pos = nodes.nextNode()))
-    {
-      DTM dtm = nodes.getDTM(pos);
-      XMLString s = dtm.getStringValue(pos);
+       while (DTM.NULL != (pos = nodes.nextNode())) {
+          DTM dtm = nodes.getDTM(pos);
+          XMLString xmlStr = dtm.getStringValue(pos);
 
-      if (null != s)
-        sum += s.toDouble();
+          if (xmlStr != null) {
+             sum += xmlStr.toDouble();
+          }
+       }
+       nodes.detach();
     }
-    nodes.detach();
 
     return new XNumber(sum);
   }
diff --git a/src/org/apache/xpath/operations/Variable.java b/src/org/apache/xpath/operations/Variable.java
index 248c5f0c..41f13ceb 100644
--- a/src/org/apache/xpath/operations/Variable.java
+++ b/src/org/apache/xpath/operations/Variable.java
@@ -142,12 +142,9 @@ public class Variable extends Expression implements PathComponent
       }
     }
     
-    if (m_qname.equals(m_inlineFnVariableName)) {
-       // the variable reference denoted by m_qname within XPath expression,
-       // when it refers to the function item's parameter name, is not stored
-       // within XPath context's variable stack, but this action still needs
-       // to be done so that, function item's parameter reference within XPath
-       // expression is not treated as unrecognized variable. 
+    if (m_xpathVarList.contains(m_qname)) {
+       // this takes care of, variable references within, XPath 3.1 feature implementations
+       // like function item, "for" expression.
        return;    
     }
     
@@ -218,17 +215,16 @@ public class Variable extends Expression implements PathComponent
 
     XObject result;
     
-    Map<QName, XObject> inlineFunctionVarMap = xctxt.getInlineFunctionVarMap();
-    XObject inlineFuncVarValue = inlineFunctionVarMap.get(m_qname);
+    Map<QName, XObject> xpathVarMap = xctxt.getXPathVarMap();
+    XObject varValue = xpathVarMap.get(m_qname);
     
-    if (inlineFuncVarValue != null) {
-        // dereference, XPath 3.1 function item "inline function" 
-        // parameter reference within "inline function" body.
-        if (inlineFuncVarValue instanceof XNodeSet) {
-           result = ((XNodeSet)inlineFuncVarValue).getFresh();    
+    if (varValue != null) {
+        // dereference, XPath 3.1 variable reference
+        if (varValue instanceof XNodeSet) {
+           result = ((XNodeSet)varValue).getFresh();    
         }
         else {
-           result = inlineFuncVarValue;
+           result = varValue;
         }
         
         return result;
diff --git a/tests/for_expr/gold/test1.out b/tests/for_expr/gold/test1.out
new file mode 100644
index 00000000..12ca45d2
--- /dev/null
+++ b/tests/for_expr/gold/test1.out
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <totalPrice>48</totalPrice>
+</result>
diff --git a/tests/for_expr/gold/test2.out b/tests/for_expr/gold/test2.out
new file mode 100644
index 00000000..e957aa40
--- /dev/null
+++ b/tests/for_expr/gold/test2.out
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <totalPrice discounted="yes">25.5</totalPrice>
+</result>
diff --git a/tests/for_expr/gold/test3.out b/tests/for_expr/gold/test3.out
new file mode 100644
index 00000000..a162cfb2
--- /dev/null
+++ b/tests/for_expr/gold/test3.out
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <totalPrice discounted="no">48</totalPrice>
+</result>
diff --git a/tests/for_expr/gold/test4.out b/tests/for_expr/gold/test4.out
new file mode 100644
index 00000000..49ca3126
--- /dev/null
+++ b/tests/for_expr/gold/test4.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>3 4 4 5</result>
diff --git a/tests/for_expr/gold/test5.out b/tests/for_expr/gold/test5.out
new file mode 100644
index 00000000..e93fe315
--- /dev/null
+++ b/tests/for_expr/gold/test5.out
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val>9</val>
+  <val>11</val>
+  <val>13</val>
+  <val>16</val>
+  <val>10</val>
+  <val>12</val>
+  <val>14</val>
+  <val>17</val>
+</result>
diff --git a/tests/for_expr/test1.xsl b/tests/for_expr/test1.xsl
new file mode 100644
index 00000000..c5c4de8a
--- /dev/null
+++ b/tests/for_expr/test1.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 -->
+   
+   <!-- This XSLT test, borrows an XPath "for" expression example
+        from XPath 3.1 spec. -->
+   
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/list">
+      <result>
+	     <totalPrice>
+	         <xsl:value-of select="sum(for $ordItem in order-item return 
+	                                                       $ordItem/@price * $ordItem/@qty)"/>
+	     </totalPrice>
+      </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/for_expr/test1_a.xml b/tests/for_expr/test1_a.xml
new file mode 100644
index 00000000..dd09cea8
--- /dev/null
+++ b/tests/for_expr/test1_a.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<list>
+   <order-item id="1" price="5" qty="2"/>
+   <order-item id="2" price="2" qty="3"/>
+   <order-item id="3" price="5" qty="2"/>
+   <order-item id="4" price="2" qty="3"/>
+   <order-item id="5" price="5" qty="2"/>
+   <order-item id="6" price="2" qty="3"/>
+</list>
+ 
\ No newline at end of file
diff --git a/tests/for_expr/test2.xsl b/tests/for_expr/test2.xsl
new file mode 100644
index 00000000..ada42d73
--- /dev/null
+++ b/tests/for_expr/test2.xsl
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+
+   <!-- Author: mukulg@apache.org -->                
+                
+   <!-- use with test1_a.xml -->
+   
+   <!-- This XSLT test, borrows an XPath "for" expression example
+        from XPath 3.1 spec, and introduces a slight modification
+        (using an XSLT stylesheet global variable 'discount', that 
+        is also used within the XPath "for" expression). -->
+   
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="discount" select="1.5"/>
+
+   <xsl:template match="/list">
+      <result>
+	     <totalPrice discounted="{if ($discount gt 0) then 'yes' else 'no'}">
+	         <xsl:value-of select="sum(for $ordItem in order-item return 
+	                                                       ($ordItem/@price - $discount) * $ordItem/@qty)"/>
+	     </totalPrice>
+      </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/for_expr/test3.xsl b/tests/for_expr/test3.xsl
new file mode 100644
index 00000000..8d607e11
--- /dev/null
+++ b/tests/for_expr/test3.xsl
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+
+   <!-- Author: mukulg@apache.org -->                
+                
+   <!-- use with test1_a.xml -->
+   
+   <!-- This XSLT test, borrows an XPath "for" expression example
+        from XPath 3.1 spec, and introduces a slight modification
+        (using an XSLT stylesheet global variable 'discount', that 
+        is also used within the XPath "for" expression). -->
+   
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="discount" select="0"/>
+
+   <xsl:template match="/list">
+      <result>
+	     <totalPrice discounted="{if ($discount gt 0) then 'yes' else 'no'}">
+	         <xsl:value-of select="sum(for $ordItem in order-item return 
+	                                                       ($ordItem/@price - $discount) * $ordItem/@qty)"/>
+	     </totalPrice>
+      </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/for_expr/test4.xsl b/tests/for_expr/test4.xsl
new file mode 100644
index 00000000..2bd6108a
--- /dev/null
+++ b/tests/for_expr/test4.xsl
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+
+   <!-- Author: mukulg@apache.org -->
+   
+   <!-- This XSLT test, illustrates an XPath 3.1 "for" expression
+        example using two "for" expression binding variables. -->
+   
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/">
+      <result>
+	     <xsl:value-of select="for $x in (1 to 2), $y in (2 to 3) return ($x + $y)"/>
+      </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/for_expr/test5.xsl b/tests/for_expr/test5.xsl
new file mode 100644
index 00000000..961a1b6d
--- /dev/null
+++ b/tests/for_expr/test5.xsl
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+
+   <!-- Author: mukulg@apache.org -->
+   
+   <!-- This XSLT test, illustrates an XPath 3.1 "for" expression
+        example using three "for" expression binding variables. -->
+   
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/">
+      <result>
+   	     <xsl:for-each select="for $x in (1 to 2), $y in (2 to 3), $z in (4 to 5) return ($x + ($y * $z))">
+   	        <val><xsl:value-of select="."/></val>
+   	     </xsl:for-each>
+      </result>
+   </xsl:template>
+   
+   <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+   -->
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/org/apache/xalan/xpath3/ForExprTests.java b/tests/org/apache/xalan/xpath3/ForExprTests.java
new file mode 100644
index 00000000..e1e747b8
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/ForExprTests.java
@@ -0,0 +1,100 @@
+/*
+ * 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 test cases, for the "for" expression.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class ForExprTests extends XslTransformTestsUtil {        
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "for_expr/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "for_expr/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 xslForExprTest1() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test1.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslForExprTest2() {
+        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 xslForExprTest3() {
+        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);
+    }
+    
+    @Test
+    public void xslForExprTest4() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test4.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslForExprTest5() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test5.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 e5176c6b..4681d382 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.FnIndexOfTests;
 import org.apache.xalan.xpath3.FnStringJoinTests;
 import org.apache.xalan.xpath3.FnTokenizeTests;
 import org.apache.xalan.xpath3.FnUnparsedTextTests;
+import org.apache.xalan.xpath3.ForExprTests;
 import org.apache.xalan.xpath3.IfExprTests;
 import org.apache.xalan.xpath3.InlineFunctionItemExprTests;
 import org.apache.xalan.xpath3.RangeExprTests;
@@ -55,7 +56,8 @@ import org.junit.runners.Suite.SuiteClasses;
                 FnIndexOfTests.class, SequenceTests.class, RangeExprTests.class, 
                 W3c_xslt30_IterateTests.class, W3c_xslt30_AxesTests.class, XslIterateTests.class,
                 ValueComparisonTests.class, InlineFunctionItemExprTests.class, FnForEachTests.class, 
-                FnFilterTests.class, DynamicFunctionCallTests.class, IfExprTests.class })
+                FnFilterTests.class, DynamicFunctionCallTests.class, IfExprTests.class, 
+                ForExprTests.class })
 public class AllXsl3Tests {
 
 }


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