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/09/11 12:25:47 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xslt 3.0 xsl:function element, which define stylesheet functions that may be called from within xpath expressions. committing few related working new test cases as well. also committing related minor improvements and codebase refactoring, on this xalanj dev repos 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 29f3f221 committing implementation of xslt 3.0 xsl:function element, which define stylesheet functions that may be called from within xpath expressions. committing few related working new test cases as well. also committing related minor improvements and codebase refactoring, on this xalanj dev repos branch.
     new d6a6b50c Merge pull request #82 from mukulga/xalan-j_xslt3.0_mukul
29f3f221 is described below

commit 29f3f221b24a3ea6aae498ef9b457c8bb3885641
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Mon Sep 11 17:47:21 2023 +0530

    committing implementation of xslt 3.0 xsl:function element, which define stylesheet functions that may be called from within xpath expressions. committing few related working new test cases as well. also committing related minor improvements and codebase refactoring, on this xalanj dev repos branch.
---
 .../apache/xalan/extensions/ExtensionHandler.java  |   2 +-
 .../extensions/ExtensionHandlerExsltFunction.java  |   4 +-
 .../xalan/extensions/ExtensionHandlerGeneral.java  |   3 +-
 .../extensions/ExtensionHandlerJavaClass.java      |   3 +-
 .../extensions/ExtensionHandlerJavaPackage.java    |   5 +-
 .../apache/xalan/extensions/ExtensionsTable.java   |   5 +-
 src/org/apache/xalan/processor/XSLTSchema.java     |  20 +-
 src/org/apache/xalan/templates/Constants.java      |   9 +-
 .../apache/xalan/templates/ElemApplyTemplates.java |   2 +-
 src/org/apache/xalan/templates/ElemForEach.java    | 133 +++++++----
 src/org/apache/xalan/templates/ElemFunction.java   | 255 +++++++++++++++++++++
 src/org/apache/xalan/templates/ElemTemplate.java   |   2 +-
 src/org/apache/xalan/templates/ElemValueOf.java    |   2 +-
 src/org/apache/xalan/templates/ElemVariable.java   |   6 +-
 .../xalan/templates/XSConstructorFunctionUtil.java |  69 ++++--
 src/org/apache/xalan/transformer/StackGuard.java   |   2 +-
 .../apache/xalan/transformer/TransformerImpl.java  |   2 +-
 .../xslt/util/XslTransformEvaluationHelper.java    |  33 +++
 .../apache/xpath/functions/FuncExtFunction.java    |   2 +-
 src/org/apache/xpath/functions/FuncNot.java        |   2 +-
 src/org/apache/xpath/operations/Operation.java     |   4 +-
 src/org/apache/xpath/operations/Range.java         |   4 +-
 .../apache/xpath/operations/SimpleMapOperator.java |   2 +-
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java     |   3 +-
 tests/org/apache/xalan/xslt3/XslFunctionTests.java | 121 ++++++++++
 tests/xsl_function/gold/test1.out                  |   1 +
 tests/xsl_function/gold/test2.out                  |   1 +
 tests/xsl_function/gold/test3.out                  |   1 +
 tests/xsl_function/gold/test4.out                  |  12 +
 tests/xsl_function/gold/test5.out                  |  11 +
 tests/xsl_function/gold/test6.out                  |   4 +
 tests/xsl_function/gold/test7.out                  |   4 +
 tests/xsl_function/test1.xsl                       |  48 ++++
 tests/xsl_function/test1_a.xml                     |  17 ++
 tests/xsl_function/test1_b.xml                     |  17 ++
 tests/xsl_function/test2.xsl                       |  46 ++++
 tests/xsl_function/test3.xsl                       |  51 +++++
 tests/xsl_function/test4.xsl                       |  51 +++++
 tests/xsl_function/test5.xsl                       |  50 ++++
 tests/xsl_function/test6.xsl                       |  71 ++++++
 tests/xsl_function/test7.xsl                       |  71 ++++++
 41 files changed, 1052 insertions(+), 99 deletions(-)

diff --git a/src/org/apache/xalan/extensions/ExtensionHandler.java b/src/org/apache/xalan/extensions/ExtensionHandler.java
index 8c6d12cc..e91e8047 100644
--- a/src/org/apache/xalan/extensions/ExtensionHandler.java
+++ b/src/org/apache/xalan/extensions/ExtensionHandler.java
@@ -122,7 +122,7 @@ public abstract class ExtensionHandler
    */
   public abstract Object callFunction(
     FuncExtFunction extFunction, Vector args,
-      ExpressionContext exprContext) throws TransformerException;
+      ExpressionContext exprContext, TransformerImpl transformer) throws TransformerException;
 
   /**
    * Process a call to this extension namespace via an element. As a side
diff --git a/src/org/apache/xalan/extensions/ExtensionHandlerExsltFunction.java b/src/org/apache/xalan/extensions/ExtensionHandlerExsltFunction.java
index 7e4b15ec..62268230 100644
--- a/src/org/apache/xalan/extensions/ExtensionHandlerExsltFunction.java
+++ b/src/org/apache/xalan/extensions/ExtensionHandlerExsltFunction.java
@@ -178,7 +178,8 @@ public class ExtensionHandlerExsltFunction extends ExtensionHandler
    */
   public Object callFunction(FuncExtFunction extFunction,
                              Vector args,
-                             ExpressionContext exprContext)
+                             ExpressionContext exprContext,
+                             TransformerImpl transformer)
       throws TransformerException
   {
     // Find the template which invokes this EXSLT function.
@@ -203,7 +204,6 @@ public class ExtensionHandlerExsltFunction extends ExtensionHandler
       
       if (null != elemFunc) {
         XPathContext context = exprContext.getXPathContext();
-        TransformerImpl transformer = (TransformerImpl)context.getOwnerObject();
         transformer.pushCurrentFuncResult(null);
 
         elemFunc.execute(transformer, methodArgs);
diff --git a/src/org/apache/xalan/extensions/ExtensionHandlerGeneral.java b/src/org/apache/xalan/extensions/ExtensionHandlerGeneral.java
index f29d4ba6..114f3747 100644
--- a/src/org/apache/xalan/extensions/ExtensionHandlerGeneral.java
+++ b/src/org/apache/xalan/extensions/ExtensionHandlerGeneral.java
@@ -339,7 +339,8 @@ public class ExtensionHandlerGeneral extends ExtensionHandler
    */
   public Object callFunction(FuncExtFunction extFunction,
                              Vector args,
-                             ExpressionContext exprContext)
+                             ExpressionContext exprContext,
+                             TransformerImpl transformer)
       throws TransformerException
   {
     return callFunction(extFunction.getFunctionName(), args, 
diff --git a/src/org/apache/xalan/extensions/ExtensionHandlerJavaClass.java b/src/org/apache/xalan/extensions/ExtensionHandlerJavaClass.java
index c132d626..784579fb 100644
--- a/src/org/apache/xalan/extensions/ExtensionHandlerJavaClass.java
+++ b/src/org/apache/xalan/extensions/ExtensionHandlerJavaClass.java
@@ -434,7 +434,8 @@ public class ExtensionHandlerJavaClass extends ExtensionHandlerJava
    */
   public Object callFunction(FuncExtFunction extFunction,
                              Vector args,
-                             ExpressionContext exprContext)
+                             ExpressionContext exprContext,
+                             TransformerImpl transformer)
       throws TransformerException
   {
     return callFunction(extFunction.getFunctionName(), args, 
diff --git a/src/org/apache/xalan/extensions/ExtensionHandlerJavaPackage.java b/src/org/apache/xalan/extensions/ExtensionHandlerJavaPackage.java
index f7d09744..d1ada0ad 100644
--- a/src/org/apache/xalan/extensions/ExtensionHandlerJavaPackage.java
+++ b/src/org/apache/xalan/extensions/ExtensionHandlerJavaPackage.java
@@ -434,14 +434,15 @@ public class ExtensionHandlerJavaPackage extends ExtensionHandlerJava
    */
   public Object callFunction(FuncExtFunction extFunction,
                              Vector args,
-                             ExpressionContext exprContext) throws TransformerException
+                             ExpressionContext exprContext,
+                             TransformerImpl transformer) throws TransformerException
   {
       
       Object funcEvalResult = null;
       
       try {
           XObject evalResult = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn
-                                                                           (exprContext.getXPathContext(), extFunction);
+                                                                          (exprContext.getXPathContext(), extFunction, transformer);
           if (evalResult != null) {
              funcEvalResult = evalResult;
           }
diff --git a/src/org/apache/xalan/extensions/ExtensionsTable.java b/src/org/apache/xalan/extensions/ExtensionsTable.java
index d2e3446b..76e5804a 100644
--- a/src/org/apache/xalan/extensions/ExtensionsTable.java
+++ b/src/org/apache/xalan/extensions/ExtensionsTable.java
@@ -26,6 +26,7 @@ import java.util.Vector;
 import org.apache.xalan.res.XSLMessages;
 import org.apache.xalan.res.XSLTErrorResources;
 import org.apache.xalan.templates.StylesheetRoot;
+import org.apache.xalan.transformer.TransformerImpl;
 import org.apache.xpath.XPathProcessorException;
 import org.apache.xpath.functions.FuncExtFunction;
 
@@ -206,7 +207,7 @@ public class ExtensionsTable
    * @throws javax.xml.transform.TransformerException
    */
   public Object extFunction(FuncExtFunction extFunction, Vector argVec, 
-                            ExpressionContext exprContext)
+                            ExpressionContext exprContext, TransformerImpl transformer)
          throws javax.xml.transform.TransformerException
   {
     Object result = null;
@@ -219,7 +220,7 @@ public class ExtensionsTable
       {
         try
         {
-          result = extNS.callFunction(extFunction, argVec, exprContext);
+          result = extNS.callFunction(extFunction, argVec, exprContext, transformer);
         }
         catch (javax.xml.transform.TransformerException e)
         {
diff --git a/src/org/apache/xalan/processor/XSLTSchema.java b/src/org/apache/xalan/processor/XSLTSchema.java
index c6d86632..8e3a9816 100644
--- a/src/org/apache/xalan/processor/XSLTSchema.java
+++ b/src/org/apache/xalan/processor/XSLTSchema.java
@@ -40,6 +40,7 @@ import org.apache.xalan.templates.ElemExtensionScript;
 import org.apache.xalan.templates.ElemFallback;
 import org.apache.xalan.templates.ElemForEach;
 import org.apache.xalan.templates.ElemForEachGroup;
+import org.apache.xalan.templates.ElemFunction;
 import org.apache.xalan.templates.ElemIf;
 import org.apache.xalan.templates.ElemIterate;
 import org.apache.xalan.templates.ElemIterateBreak;
@@ -130,8 +131,9 @@ public class XSLTSchema extends XSLTElementDef
                                        
                   
     // Required.
-    // It is an error if the name attribute is invalid on any of these elements
-    // xsl:key, xsl:attribute-set, xsl:call-template, xsl:with-param, xsl:variable, xsl:param
+    // It is an error if the name attribute is not present on any of these elements
+    // xsl:key, xsl:attribute-set, xsl:call-template, xsl:with-param, xsl:variable, xsl:param, 
+    // xsl:function
     XSLTAttributeDef nameAttrRequired = new XSLTAttributeDef(null, "name",
                                           XSLTAttributeDef.T_QNAME, true, false,XSLTAttributeDef.ERROR);
 	// Required.
@@ -247,7 +249,7 @@ public class XSLTSchema extends XSLTElementDef
                                        XSLTAttributeDef.T_EXPR, false, false, XSLTAttributeDef.ERROR);
     
     // Optional.
-    // xsl:variable, xsl:param, xsl:with-param, xsl:template 
+    // xsl:variable, xsl:param, xsl:with-param, xsl:template, xsl:function 
     XSLTAttributeDef asAttrOpt = new XSLTAttributeDef(null, "as",
                                        XSLTAttributeDef.T_STRING, false, false, XSLTAttributeDef.ERROR);
 
@@ -904,7 +906,17 @@ public class XSLTSchema extends XSLTElementDef
                                                    modeAttr,
                                                    asAttrOpt,
                                                    spaceAttr }, 
-                                           new ProcessorTemplate(), ElemTemplate.class /* class object */, true, 20, true), 
+                                           new ProcessorTemplate(), ElemTemplate.class /* class object */, true, 20, true),
+                                  new XSLTElementDef(
+                                          this,
+                                          Constants.S_XSLNAMESPACEURL,
+                                          "function",
+                                          null /*alias */,
+                                          templateElementsAndParams /* elements */,
+                                          new XSLTAttributeDef[] {
+                                                  nameAttrRequired,
+                                                  asAttrOpt }, 
+                                          new ProcessorTemplate(), ElemFunction.class /* class object */, true, 20, true),
                                   new XSLTElementDef(
                                            this,
                                            Constants.S_XSLNAMESPACEURL,
diff --git a/src/org/apache/xalan/templates/Constants.java b/src/org/apache/xalan/templates/Constants.java
index 47ed4261..eccca64a 100644
--- a/src/org/apache/xalan/templates/Constants.java
+++ b/src/org/apache/xalan/templates/Constants.java
@@ -102,9 +102,11 @@ public class Constants extends org.apache.xml.utils.Constants
   
   ELEMNAME_ITERATE_NEXTITERATION = 96,
   
-  ELEMNAME_ITERATE_BREAK = 97;
+  ELEMNAME_ITERATE_BREAK = 97,
   
-  // next available number : 98
+  ELEMNAME_FUNCTION = 98;
+  
+  // next available number : 99
 
   /**
    * Literals for XSL element names. Note that there are more
@@ -185,7 +187,8 @@ public class Constants extends org.apache.xml.utils.Constants
       ELEMNAME_VALUEOF_STRING = "value-of",
       ELEMNAME_VARIABLE_STRING = "variable",
       ELEMNAME_WHEN_STRING = "when",
-      ELEMNAME_WITHPARAM_STRING = "with-param";
+      ELEMNAME_WITHPARAM_STRING = "with-param",
+      ELEMNAME_FUNCTION_STRING = "function";
   
   /**
    * Literals for EXSLT function elements.
diff --git a/src/org/apache/xalan/templates/ElemApplyTemplates.java b/src/org/apache/xalan/templates/ElemApplyTemplates.java
index ef1a57b1..884c8536 100644
--- a/src/org/apache/xalan/templates/ElemApplyTemplates.java
+++ b/src/org/apache/xalan/templates/ElemApplyTemplates.java
@@ -346,7 +346,7 @@ public class ElemApplyTemplates extends ElemCallTemplate
                 
         transformer.pushPairCurrentMatched(template, child);
         if (check)
-	        guard.checkForInfinateLoop();
+	        guard.checkForInfiniteLoop();
 
         int currentFrameBottom;  // See comment with unlink, below
         if(template.m_frameSize > 0)
diff --git a/src/org/apache/xalan/templates/ElemForEach.java b/src/org/apache/xalan/templates/ElemForEach.java
index 2195a04f..03378d16 100644
--- a/src/org/apache/xalan/templates/ElemForEach.java
+++ b/src/org/apache/xalan/templates/ElemForEach.java
@@ -29,6 +29,7 @@ import javax.xml.transform.TransformerException;
 
 import org.apache.xalan.transformer.NodeSorter;
 import org.apache.xalan.transformer.TransformerImpl;
+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;
@@ -55,6 +56,8 @@ import org.apache.xpath.operations.Variable;
  *     <!-- Content: (xsl:sort*, sequence-constructor) -->
  * </xsl:for-each>
  * 
+ * Ref : https://www.w3.org/TR/xslt-30/#for-each
+ * 
  * @xsl.usage advanced
  */
 /*
@@ -169,25 +172,6 @@ public class ElemForEach extends ElemTemplateElement implements ExpressionOwner
     super.endCompose(sroot);
   }
 
-
-  //  /**
-  //   * This function is called after everything else has been
-  //   * recomposed, and allows the template to set remaining
-  //   * values that may be based on some other property that
-  //   * depends on recomposition.
-  //   *
-  //   * @throws TransformerException
-  //   */
-  //  public void compose() throws TransformerException
-  //  {
-  //
-  //    if (null == m_selectExpression)
-  //    {
-  //      m_selectExpression =
-  //        getStylesheetRoot().m_selectDefault.getExpression();
-  //    }
-  //  }
-
   /**
    * Vector containing the xsl:sort elements associated with this element.
    *  @serial
@@ -340,72 +324,121 @@ public class ElemForEach extends ElemTemplateElement implements ExpressionOwner
     
     XPathContext xctxt = transformer.getXPathContext();
     
+    DTMIterator resultSeqDtmIterator = null;
+    
     if (m_selectExpression instanceof Function) {
-        // evaluate an xslt/xpath function reference.
-        // for example,
-        // <xsl:for-each select="tokenize(..)"> ...
         XObject evalResult = ((Function)m_selectExpression).execute(xctxt);
+        
         if (evalResult instanceof ResultSequence) {
-            processResultSequence(transformer, xctxt, evalResult);
-            transformer.setXPathContext(xctxtOriginal);
-            
-            return;
+            XNodeSet nodeSet = XslTransformEvaluationHelper.getXNodeSetFromResultSequence((ResultSequence)evalResult, 
+                                                                                                                  (DTMManager)xctxt);             
+            if (nodeSet == null) {
+               processResultSequence(transformer, xctxt, evalResult);
+               transformer.setXPathContext(xctxtOriginal);
+               
+               return;
+            }
+            else {
+               resultSeqDtmIterator = nodeSet.iter(); 
+            }
         }                
     }    
     else if (m_selectExpression instanceof Variable) {
-        // evaluate an xslt variable reference.
-        // for example,
-        // <xsl:variable name="tokens" select="tokenize(..)"/>
-        // <xsl:for-each select="$tokens"> ...
         XObject evalResult = ((Variable)m_selectExpression).execute(xctxt);
+        
         if (evalResult instanceof ResultSequence) {
-            processResultSequence(transformer, xctxt, evalResult);
-            transformer.setXPathContext(xctxtOriginal);
-            
-            return;
+            XNodeSet nodeSet = XslTransformEvaluationHelper.getXNodeSetFromResultSequence((ResultSequence)evalResult, 
+                                                                                                                  (DTMManager)xctxt);             
+            if (nodeSet == null) {
+                processResultSequence(transformer, xctxt, evalResult);
+                transformer.setXPathContext(xctxtOriginal);
+
+                return;
+            }
+            else {
+                resultSeqDtmIterator = nodeSet.iter(); 
+            }
         }
     }    
     else if (m_selectExpression instanceof Operation) {
         XObject  evalResult = m_selectExpression.execute(xctxt);
+        
         if (evalResult instanceof ResultSequence) {
-            processResultSequence(transformer, xctxt, evalResult);
-            transformer.setXPathContext(xctxtOriginal);
-            
-            return;
+            XNodeSet nodeSet = XslTransformEvaluationHelper.getXNodeSetFromResultSequence((ResultSequence)evalResult, 
+                                                                                                                  (DTMManager)xctxt);             
+            if (nodeSet == null) {
+                processResultSequence(transformer, xctxt, evalResult);
+                transformer.setXPathContext(xctxtOriginal);
+
+                return;
+            }
+            else {
+                resultSeqDtmIterator = nodeSet.iter(); 
+            }
         }
     }    
     else if (m_selectExpression instanceof ForExpr) {
         ForExpr forExpr = (ForExpr)m_selectExpression;
         XObject  evalResult = forExpr.execute(xctxt);
-        processResultSequence(transformer, xctxt, evalResult);
-        transformer.setXPathContext(xctxtOriginal);
         
-        return;
+        XNodeSet nodeSet = XslTransformEvaluationHelper.getXNodeSetFromResultSequence((ResultSequence)evalResult, 
+                                                                                                              (DTMManager)xctxt);             
+        if (nodeSet == null) {
+            processResultSequence(transformer, xctxt, evalResult);
+            transformer.setXPathContext(xctxtOriginal);
+
+            return;
+        }
+        else {
+            resultSeqDtmIterator = nodeSet.iter(); 
+        }
     }    
     else if (m_selectExpression instanceof SimpleSequenceConstructor) {
         SimpleSequenceConstructor seqCtrExpr = (SimpleSequenceConstructor)
                                                                      m_selectExpression;
         XObject  evalResult = seqCtrExpr.execute(xctxt);
-        processResultSequence(transformer, xctxt, evalResult);
-        transformer.setXPathContext(xctxtOriginal);
         
-        return;
+        XNodeSet nodeSet = XslTransformEvaluationHelper.getXNodeSetFromResultSequence((ResultSequence)evalResult, 
+                                                                                                              (DTMManager)xctxt);             
+        if (nodeSet == null) {
+            processResultSequence(transformer, xctxt, evalResult);
+            transformer.setXPathContext(xctxtOriginal);
+
+            return;
+        }
+        else {
+            resultSeqDtmIterator = nodeSet.iter(); 
+        }
     }
     else if (m_selectExpression instanceof DynamicFunctionCall) {
         DynamicFunctionCall dfc = (DynamicFunctionCall)m_selectExpression;
         XObject evalResult = dfc.execute(xctxt);
         
         if (evalResult instanceof ResultSequence) {
-           processResultSequence(transformer, xctxt, evalResult);
-           transformer.setXPathContext(xctxtOriginal);
-            
-           return;
+            XNodeSet nodeSet = XslTransformEvaluationHelper.getXNodeSetFromResultSequence((ResultSequence)evalResult, 
+                                                                                                                  (DTMManager)xctxt);             
+            if (nodeSet == null) {
+                processResultSequence(transformer, xctxt, evalResult);
+                transformer.setXPathContext(xctxtOriginal);
+
+                return;
+            }
+            else {
+                resultSeqDtmIterator = nodeSet.iter(); 
+            }
         }
     }
     
-    // process the node-set, with body of xsl:for-each element as usual 
+    DTMIterator sourceNodes = null;
+    
     final int sourceNode = xctxt.getCurrentNode();
-    DTMIterator sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
+    
+    if (resultSeqDtmIterator != null) {
+       sourceNodes = resultSeqDtmIterator;
+    }
+    else {       
+       sourceNodes = m_selectExpression.asIterator(xctxt, sourceNode);
+    }
 
     try
     {
diff --git a/src/org/apache/xalan/templates/ElemFunction.java b/src/org/apache/xalan/templates/ElemFunction.java
new file mode 100644
index 00000000..8b297702
--- /dev/null
+++ b/src/org/apache/xalan/templates/ElemFunction.java
@@ -0,0 +1,255 @@
+/*
+ * 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.templates;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+
+import org.apache.xalan.transformer.TransformerImpl;
+import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
+import org.apache.xml.utils.QName;
+import org.apache.xpath.VariableStack;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.composite.SequenceTypeSupport;
+import org.apache.xpath.objects.ResultSequence;
+import org.apache.xpath.objects.XNodeSet;
+import org.apache.xpath.objects.XNodeSetForDOM;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XRTreeFrag;
+import org.w3c.dom.NodeList;
+
+/**
+ * Implementation of XSLT xsl:function element.
+ * 
+ * Ref : https://www.w3.org/TR/xslt-30/#stylesheet-functions
+ *
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class ElemFunction extends ElemTemplate
+{
+
+  private static final long serialVersionUID = 4973132678982467288L;
+
+  /**
+   * Class constructor.
+   */
+  public ElemFunction() {}
+
+  /**
+   * The value of the "name" attribute.
+   */
+  protected QName m_qname;
+
+  public void setName(QName qName)
+  {
+      m_qname = qName;
+  }
+
+  public QName getName()
+  {
+      return m_qname;
+  }
+
+  /**
+   * Get an integer representation of the element type.
+   *
+   * @return An integer representation of the element, defined in the
+   *     Constants class.
+   * @see org.apache.xalan.templates.Constants
+   */
+  public int getXSLToken()
+  {
+     return Constants.ELEMNAME_FUNCTION;
+  }
+
+  /**
+   * Return the node name.
+   *
+   * @return The node name
+   */
+  public String getNodeName()
+  {
+     return Constants.ELEMNAME_FUNCTION_STRING;
+  }
+  
+  /**
+   * The stack frame size for this xsl:function definition, which is equal
+   * to the maximum number of params and variables that can be declared 
+   * in the function at one time.
+   */
+  public int m_frameSize;
+  
+  /**
+   * The size of the portion of the stack frame that can hold parameter 
+   * arguments.
+   */
+  int m_inArgsSize;
+
+  /**
+   * This method evaluates the xsl:function call, and returns the result
+   * to the caller of this function.
+   */
+  public XObject executeXslFunction(TransformerImpl transformer, 
+                                                             ResultSequence argSequence) throws TransformerException {
+      XObject result = null;
+      
+      XPathContext xctxt = transformer.getXPathContext();
+      
+      SourceLocator srcLocator = xctxt.getSAXLocator(); 
+      
+      VariableStack varStack = xctxt.getVarStack();
+      
+      int thisframe = varStack.getStackFrame();
+      int nextFrame = varStack.link(m_frameSize);
+      
+      varStack.setStackFrame(thisframe);
+      
+      String funcLocalName = m_qname.getLocalName();
+      String funcNameSpaceUri = m_qname.getNamespaceURI(); 
+      
+      int paramCount = 0;
+      for (ElemTemplateElement elem = getFirstChildElem(); elem != null; 
+                                                              elem = elem.getNextSiblingElem()) {
+          if(elem.getXSLToken() == Constants.ELEMNAME_PARAMVARIABLE) {
+             if (argSequence.size() < (paramCount + 1)) {
+                 throw new TransformerException("XPST0017 : Cannot find a " + argSequence.size() + " argument function named "
+                                                                            + "{" + funcNameSpaceUri + "}" + funcLocalName + "() within a stylesheet scope. "
+                                                                            + "The function name was recognized, but number of arguments is wrong.", srcLocator); 
+             }
+             XObject argValue = argSequence.item(paramCount);
+             XObject argConvertedVal = argValue;
+             String paramAsAttrStrVal = ((ElemParam)elem).getAs();              
+             if (paramAsAttrStrVal != null) {
+                try {
+                   argConvertedVal = SequenceTypeSupport.convertXDMValueToAnotherType(argValue, paramAsAttrStrVal, null, xctxt);
+                   if (argConvertedVal == null) {
+                      throw new TransformerException("XPTY0004 : Function call argument at position " + (paramCount + 1) + " for "
+                                                                        + "function {" + funcNameSpaceUri + "}" + funcLocalName + "(), doesn't "
+                                                                        + "match the declared parameter type " + paramAsAttrStrVal + ".", srcLocator); 
+                   }
+                }
+                catch (TransformerException ex) {
+                   throw new TransformerException("XPTY0004 : Function call argument at position " + (paramCount + 1) + " for "
+                                                                     + "function {" + funcNameSpaceUri + "}" + funcLocalName + "(), doesn't "
+                                                                     + "match the declared parameter type " + paramAsAttrStrVal + ".", srcLocator); 
+                }
+             }
+             
+             if (argConvertedVal instanceof ResultSequence) {                
+                XNodeSet nodeSet = XslTransformEvaluationHelper.getXNodeSetFromResultSequence((ResultSequence)argConvertedVal, 
+                                                                                                                            xctxt);
+                if (nodeSet != null) {
+                   argConvertedVal = nodeSet;  
+                }
+             }
+             
+             varStack.setLocalVariable(paramCount, argConvertedVal, nextFrame);
+             paramCount++;
+          }
+          else {
+             break; 
+          }
+      }
+      
+      varStack.setStackFrame(nextFrame);
+      
+      int df = transformer.transformToGlobalRTF(this);
+      
+      NodeList nodeList = (new XRTreeFrag(df, xctxt, this)).convertToNodeset();     
+      
+      result = new XNodeSetForDOM(nodeList, xctxt);
+            
+      XObject funcResultConvertedVal = result;
+      
+      String funcAsAttrStrVal = getAs();
+      
+      if (funcAsAttrStrVal != null) {
+         try {
+            funcResultConvertedVal = SequenceTypeSupport.convertXDMValueToAnotherType(result, funcAsAttrStrVal, null, xctxt);
+            if (funcResultConvertedVal == null) {
+               throw new TransformerException("XPTY0004 : The function call result for function {" + funcNameSpaceUri + "}" + funcLocalName + 
+                                                                                "(), doesn't match the declared function result type " + 
+                                                                                                                       funcAsAttrStrVal + ".", srcLocator);   
+            }
+         }
+         catch (TransformerException ex) {
+            throw new TransformerException("XPTY0004 : The function call result for function {" + funcNameSpaceUri + "}" + funcLocalName + 
+                                                                                           "(), doesn't match the declared function result type " + 
+                                                                                                                       funcAsAttrStrVal + ".", srcLocator); 
+         }
+      }
+      
+      if (funcResultConvertedVal instanceof ResultSequence) {
+         ResultSequence resultSeq = (ResultSequence)funcResultConvertedVal;
+         int resultSeqSize = resultSeq.size();
+         if ((resultSeqSize == 1) && (resultSeq.item(0) instanceof XNodeSet)) {
+            funcResultConvertedVal = resultSeq.item(0);   
+         }
+      }
+      
+      return funcResultConvertedVal;
+  }
+  
+  /**
+   * This function is called after everything else has been
+   * recomposed, and allows an xsl:function to set remaining
+   * values that may be based on some other property that
+   * depends on recomposition.
+   */
+  public void compose(StylesheetRoot sroot) throws TransformerException
+  {
+      super.compose(sroot);
+      StylesheetRoot.ComposeState cstate = sroot.getComposeState();
+      java.util.Vector vnames = cstate.getVariableNames();        
+      cstate.resetStackFrameSize();
+      m_inArgsSize = 0;
+  }
+  
+  /**
+   * This function is called, after xsl:function's children have been composed. 
+   * We have to get the count of how many variables have been declared, so we
+   * can do a link and unlink.
+   */
+  public void endCompose(StylesheetRoot sroot) throws TransformerException
+  {
+      StylesheetRoot.ComposeState cstate = sroot.getComposeState();
+      super.endCompose(sroot);
+      m_frameSize = cstate.getFrameSize();
+      
+      cstate.resetStackFrameSize();
+  }
+  
+  /**
+   * Set the parent as an ElemTemplateElement.
+   *
+   * @param p This node's parent as an ElemTemplateElement
+   */
+  public void setParentElem(ElemTemplateElement p)
+  {
+      super.setParentElem(p);
+      p.m_hasVariableDecl = true;
+  }
+  
+  public void recompose(StylesheetRoot root)
+  {
+      root.recomposeTemplates(this);
+  }
+
+}
diff --git a/src/org/apache/xalan/templates/ElemTemplate.java b/src/org/apache/xalan/templates/ElemTemplate.java
index 29a8114c..31c63ccb 100644
--- a/src/org/apache/xalan/templates/ElemTemplate.java
+++ b/src/org/apache/xalan/templates/ElemTemplate.java
@@ -400,7 +400,7 @@ public class ElemTemplate extends ElemTemplateElement
     
     SourceLocator srcLocator = xctxt.getSAXLocator();
     
-    transformer.getStackGuard().checkForInfinateLoop();
+    transformer.getStackGuard().checkForInfiniteLoop();
     
     xctxt.pushRTFContext();
 
diff --git a/src/org/apache/xalan/templates/ElemValueOf.java b/src/org/apache/xalan/templates/ElemValueOf.java
index cd878bc3..10e56f1b 100644
--- a/src/org/apache/xalan/templates/ElemValueOf.java
+++ b/src/org/apache/xalan/templates/ElemValueOf.java
@@ -310,7 +310,7 @@ public class ElemValueOf extends ElemTemplateElement {
               else {
                   if (expr instanceof FuncExtFunction) {                      
                       XObject evalResult = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn
-                                                                                              (xctxt, expr);
+                                                                                          (xctxt, expr, transformer);
                       if (evalResult != null) {
                           String strValue = null;
                           
diff --git a/src/org/apache/xalan/templates/ElemVariable.java b/src/org/apache/xalan/templates/ElemVariable.java
index a23d480f..8ebf0c31 100644
--- a/src/org/apache/xalan/templates/ElemVariable.java
+++ b/src/org/apache/xalan/templates/ElemVariable.java
@@ -335,7 +335,7 @@ public class ElemVariable extends ElemTemplateElement
         selectExpression = m_selectPattern.getExpression();
         if (selectExpression instanceof FuncExtFunction) {
             XObject evalResult = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, 
-                                                                                        selectExpression);
+                                                                                      selectExpression, transformer);
             if (evalResult != null) {
                 if (m_asAttr != null) {
                    evalResult = SequenceTypeSupport.convertXDMValueToAnotherType(evalResult, m_asAttr, null, xctxt);  
@@ -379,9 +379,9 @@ public class ElemVariable extends ElemTemplateElement
         else if (selectExpression instanceof Operation) {
             Operation opn = (Operation)selectExpression;
             XObject leftOperand = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
-                                                                                         xctxt, opn.getLeftOperand());
+                                                                                 xctxt, opn.getLeftOperand(), transformer);
             XObject rightOperand = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
-                                                                                         xctxt, opn.getRightOperand());
+                                                                                 xctxt, opn.getRightOperand(), transformer);
             XObject evalResult = opn.operate(leftOperand, rightOperand);
             
             if (m_asAttr != null) {
diff --git a/src/org/apache/xalan/templates/XSConstructorFunctionUtil.java b/src/org/apache/xalan/templates/XSConstructorFunctionUtil.java
index 39fcf50c..24a30f04 100644
--- a/src/org/apache/xalan/templates/XSConstructorFunctionUtil.java
+++ b/src/org/apache/xalan/templates/XSConstructorFunctionUtil.java
@@ -20,8 +20,11 @@ import javax.xml.XMLConstants;
 import javax.xml.transform.SourceLocator;
 import javax.xml.transform.TransformerException;
 
+import org.apache.xalan.transformer.TransformerImpl;
 import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
+import org.apache.xml.utils.QName;
 import org.apache.xpath.Expression;
+import org.apache.xpath.ExpressionNode;
 import org.apache.xpath.XPathContext;
 import org.apache.xpath.compiler.Keywords;
 import org.apache.xpath.functions.FuncExtFunction;
@@ -42,9 +45,9 @@ import org.apache.xpath.xs.types.XSYearMonthDuration;
 import org.xml.sax.SAXException;
 
 /**
- * An utility class, to support evaluation of XPath 3.1 constructor 
- * functions (ref, https://www.w3.org/TR/xpath-functions-31/#constructor-functions), 
- * and few other XPath expression evaluations.
+ * A utility class that primarily supports, evaluations of XSLT stylesheet
+ * function calls (for the stylesheet functions, defined with syntax 
+ * xsl:function), and XPath 3.1 constructor function calls.  
  * 
  * @author Mukul Gandhi <mu...@apache.org>
  * 
@@ -53,27 +56,58 @@ import org.xml.sax.SAXException;
 public class XSConstructorFunctionUtil {
     
     /**
-     * Evaluate an XPath expression of type FuncExtFunction, and also few 
-     * other kinds of XPath expressions.
+     * We use this method, primarily to evaluate XSLT stylesheet function calls (for the
+     * stylesheet functions, defined with syntax xsl:function), and XPath 3.1 constructor
+     * function calls (having syntax with form xs:type_name(..)).
+     * 
+     *  XalanJ's extension function handling mechanism, treats at a syntactic level,
+     *  function calls belonging to non-null XML namespaces as calls to extension functions.
+     *  
+     *  Currently, XPath function calls having XML namespaces
+     *  http://www.w3.org/2005/xpath-functions, http://www.w3.org/2005/xpath-functions/math
+     *  within function names, are treated as XPath built-in functions by XalanJ. All other
+     *  XPath function calls having other non-null XML namespaces are handling by XalanJ's
+     *  extension function handling mechanism. 
      */
-    public static XObject processFuncExtFunctionOrXPathOpn(XPathContext xctxt, Expression expr)
-                                                                    throws TransformerException, SAXException {        
+    public static XObject processFuncExtFunctionOrXPathOpn(XPathContext xctxt, Expression expr, TransformerImpl transformer)
+                                                                                                              throws TransformerException, SAXException {        
         XObject evalResult = null;
         
         SourceLocator srcLocator = xctxt.getSAXLocator();
-
-        // XalanJ's extension function handler mechanism, treats at a syntactic level,
-        // XPath 3.1 constructor function calls like xs:type_name(..) as calls to XalanJ 
-        // extension functions. If the XML namespace of these function calls is an XML Schema
-        // namespace, then we use this fact to treat such function calls as XPath 3.1 constructor 
-        // function calls, as has been implemented within code below.
         
         if (expr instanceof FuncExtFunction) {
             FuncExtFunction funcExtFunction = (FuncExtFunction)expr;
             
-            if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(funcExtFunction.getNamespace())) {
-                // Handle as an XPath 3.1 constructor function call
+            String funcName = funcExtFunction.getFunctionName();
+            String funcNamespace = funcExtFunction.getNamespace();
+            
+            ExpressionNode expressionNode = expr.getExpressionOwner();
+            ExpressionNode stylesheetRootNode = null;
+            while (expressionNode != null) {
+                stylesheetRootNode = expressionNode;
+                expressionNode = expressionNode.exprGetParent();                     
+            }
+            
+            StylesheetRoot stylesheetRoot = (StylesheetRoot)stylesheetRootNode;
+            
+            TemplateList templateList = stylesheetRoot.getTemplateListComposed();
+            
+            ElemTemplate elemTemplate = templateList.getTemplate(new QName(funcNamespace, funcName));
+                        
+            if ((elemTemplate != null) && (elemTemplate instanceof ElemFunction)) {
+                // Handle call to XSLT stylesheet function definition, specified with syntax 
+                // xsl:function.                
+                ResultSequence argSequence = new ResultSequence();
+                for (int idx = 0; idx < funcExtFunction.getArgCount(); idx++) {
+                    XObject argVal = (funcExtFunction.getArg(idx)).execute(xctxt);
+                    argSequence.add(argVal);
+                }
                 
+                evalResult = ((ElemFunction)elemTemplate).executeXslFunction(transformer, argSequence);
+            }            
+            else if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(funcExtFunction.getNamespace())) {                
+                // Handle call to XPath 3.1 constructor function, having syntax with form
+                // xs:type_name(..). 
                 ResultSequence argSequence = new ResultSequence();
                 ResultSequence evalResultSequence = null;
                 
@@ -151,8 +185,9 @@ public class XSConstructorFunctionUtil {
                     case Keywords.FUNC_BOOLEAN_STRING :
                         for (int idx = 0; idx < funcExtFunction.getArgCount(); idx++) {
                             XObject argVal = (funcExtFunction.getArg(idx)).execute(xctxt);
-                            Boolean boolVal = Boolean.valueOf("0".equals(XslTransformEvaluationHelper.getStrVal(argVal)) ? 
-                                                                                     "false" : "true");
+                            String argStrVal = XslTransformEvaluationHelper.getStrVal(argVal);
+                            Boolean boolVal = Boolean.valueOf(("0".equals(argStrVal) || "false".equals(argStrVal)) ? 
+                                                                                                     "false" : "true");
                             argSequence.add(new XSBoolean(boolVal));
                         }
     
diff --git a/src/org/apache/xalan/transformer/StackGuard.java b/src/org/apache/xalan/transformer/StackGuard.java
index 07e95507..b653b7f2 100644
--- a/src/org/apache/xalan/transformer/StackGuard.java
+++ b/src/org/apache/xalan/transformer/StackGuard.java
@@ -137,7 +137,7 @@ public class StackGuard
    *
    * @throws TransformerException
    */
-  public void checkForInfinateLoop() throws TransformerException
+  public void checkForInfiniteLoop() throws TransformerException
   {
     int nTemplates = m_transformer.getCurrentTemplateElementsCount();
     if(nTemplates < m_recursionLimit)
diff --git a/src/org/apache/xalan/transformer/TransformerImpl.java b/src/org/apache/xalan/transformer/TransformerImpl.java
index b83e20b9..7c35fdd8 100644
--- a/src/org/apache/xalan/transformer/TransformerImpl.java
+++ b/src/org/apache/xalan/transformer/TransformerImpl.java
@@ -475,7 +475,7 @@ public class TransformerImpl extends Transformer
             throws javax.xml.transform.TransformerException
   {
     return getExtensionsTable().extFunction(extFunction, argVec,
-                                            getXPathContext().getExpressionContext());   
+                                            getXPathContext().getExpressionContext(), this);   
   }
   
   //=========================
diff --git a/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java b/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java
index d73bf38a..a63f1086 100644
--- a/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java
+++ b/src/org/apache/xalan/xslt/util/XslTransformEvaluationHelper.java
@@ -16,11 +16,13 @@
  */
 package org.apache.xalan.xslt.util;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.xalan.templates.XMLNSDecl;
 import org.apache.xml.dtm.DTM;
 import org.apache.xml.dtm.DTMIterator;
+import org.apache.xml.dtm.DTMManager;
 import org.apache.xml.utils.XMLString;
 import org.apache.xpath.Expression;
 import org.apache.xpath.XPathContext;
@@ -156,6 +158,37 @@ public class XslTransformEvaluationHelper {
         return resultSeq;
     }
     
+    /**
+     * Given a ResultSequence object instance, return a corresponding XNodeSet object if
+     * all the items within the supplied ResultSequence are xdm nodes.    
+     *
+     * If all the items within the supplied ResultSequence object instance are not xdm nodes,
+     * then this method returns a null value.  
+     */
+    public static XNodeSet getXNodeSetFromResultSequence(ResultSequence resultSeq, DTMManager dtmMgr) {
+        
+        XNodeSet nodeSet = null;
+        
+        List<Integer> dtmNodeHandleList = new ArrayList<Integer>();
+        
+        for (int idx = 0; idx < resultSeq.size(); idx++) {
+           XObject nodeSetItem = resultSeq.item(idx);
+           if (nodeSetItem instanceof XNodeSet) {
+              int nodeDtmHandle = (((XNodeSet)nodeSetItem).iter()).nextNode();
+              dtmNodeHandleList.add(nodeDtmHandle);
+           }
+           else {
+              break; 
+           }
+        }
+        
+        if (dtmNodeHandleList.size() == resultSeq.size()) {
+           nodeSet = new XNodeSet(dtmNodeHandleList, dtmMgr);
+        }
+        
+        return nodeSet; 
+    }
+    
     /**
      * Given a compiled XPath expression and an XPath context object, find
      * the sum of values of xdm items represented by the provided compiled 
diff --git a/src/org/apache/xpath/functions/FuncExtFunction.java b/src/org/apache/xpath/functions/FuncExtFunction.java
index e0b1ff63..0f41796a 100644
--- a/src/org/apache/xpath/functions/FuncExtFunction.java
+++ b/src/org/apache/xpath/functions/FuncExtFunction.java
@@ -203,7 +203,7 @@ public class FuncExtFunction extends Function
        // as an XPath 3.1 constructor function call within this section of code.
        try {
           result = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
-                                                                        xctxt, this);
+                                                                        xctxt, this, null);
        } 
        catch (TransformerException ex) {        
           throw new TransformerException(ex.getMessage(), xctxt.getSAXLocator());
diff --git a/src/org/apache/xpath/functions/FuncNot.java b/src/org/apache/xpath/functions/FuncNot.java
index eff2f33d..c115edd1 100644
--- a/src/org/apache/xpath/functions/FuncNot.java
+++ b/src/org/apache/xpath/functions/FuncNot.java
@@ -50,7 +50,7 @@ public class FuncNot extends FunctionOneArg
       if (m_arg0 instanceof Operation) {
           try {
              XObject result = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
-                                                                                    xctxt, m_arg0);
+                                                                                    xctxt, m_arg0, null);
              return result.bool() ? XBoolean.S_FALSE : XBoolean.S_TRUE; 
           }
           catch(SAXException ex) {
diff --git a/src/org/apache/xpath/operations/Operation.java b/src/org/apache/xpath/operations/Operation.java
index d4880bc1..8af5d6b0 100644
--- a/src/org/apache/xpath/operations/Operation.java
+++ b/src/org/apache/xpath/operations/Operation.java
@@ -124,7 +124,7 @@ public class Operation extends Expression implements ExpressionOwner
            FuncExtFunction extFunction = (FuncExtFunction)m_left;
            if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(extFunction.getNamespace())) {
               left = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
-                                                                             xctxt, m_left); 
+                                                                             xctxt, m_left, null); 
            }
            else {
               left = m_left.execute(xctxt, true);  
@@ -147,7 +147,7 @@ public class Operation extends Expression implements ExpressionOwner
            FuncExtFunction extFunction = (FuncExtFunction)m_right;
            if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(extFunction.getNamespace())) {
               right = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(
-                                                                            xctxt, m_right); 
+                                                                            xctxt, m_right, null); 
            }
            else {
               right = m_right.execute(xctxt, true);  
diff --git a/src/org/apache/xpath/operations/Range.java b/src/org/apache/xpath/operations/Range.java
index a994b942..e7973124 100644
--- a/src/org/apache/xpath/operations/Range.java
+++ b/src/org/apache/xpath/operations/Range.java
@@ -72,7 +72,7 @@ public class Range extends Operation
           if (m_left instanceof FuncExtFunction) {
              FuncExtFunction extFunction = (FuncExtFunction)m_left;
              if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(extFunction.getNamespace())) {
-                 expr1 = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, m_left); 
+                 expr1 = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, m_left, null); 
              }
              else {
                  expr1 = m_left.execute(xctxt, true);  
@@ -85,7 +85,7 @@ public class Range extends Operation
           if (m_right instanceof FuncExtFunction) {
              FuncExtFunction extFunction = (FuncExtFunction)m_right;
              if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(extFunction.getNamespace())) {
-                 expr2 = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, m_right); 
+                 expr2 = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, m_right, null); 
              }
              else {
                  expr2 = m_right.execute(xctxt, true);  
diff --git a/src/org/apache/xpath/operations/SimpleMapOperator.java b/src/org/apache/xpath/operations/SimpleMapOperator.java
index 77aaec0b..72955285 100644
--- a/src/org/apache/xpath/operations/SimpleMapOperator.java
+++ b/src/org/apache/xpath/operations/SimpleMapOperator.java
@@ -61,7 +61,7 @@ public class SimpleMapOperator extends Operation
            FuncExtFunction extFunction = (FuncExtFunction)m_left;
            if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(extFunction.getNamespace())) {
                try {
-                   expr1 = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, m_left);
+                   expr1 = XSConstructorFunctionUtil.processFuncExtFunctionOrXPathOpn(xctxt, m_left, null);
                }
                catch (TransformerException ex) {
                    throw ex; 
diff --git a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
index 473113f1..f47c20f9 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -93,7 +93,8 @@ import org.junit.runners.Suite.SuiteClasses;
                 FnStringToCodepointsTests.class, FnCompareTests.class, FnCodepointEqualTests.class,
                 SequenceFunctionTests.class, FnParseXmlTests.class, FnParseXmlFragmentTests.class,
                 TemplateTests.class, FnAvgTests.class, FnMaxTests.class, FnMinTests.class, FnContainsTokenTests.class,
-                XslVariableAttributeAsTests.class, InstanceOfExprTests.class, XslTemplateAttributeAsTests.class })
+                XslVariableAttributeAsTests.class, InstanceOfExprTests.class, XslTemplateAttributeAsTests.class,
+                XslFunctionTests.class })
 public class AllXsl3Tests {
 
 }
diff --git a/tests/org/apache/xalan/xslt3/XslFunctionTests.java b/tests/org/apache/xalan/xslt3/XslFunctionTests.java
new file mode 100644
index 00000000..2be36887
--- /dev/null
+++ b/tests/org/apache/xalan/xslt3/XslFunctionTests.java
@@ -0,0 +1,121 @@
+/*
+ * 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.xslt3;
+
+import org.apache.xalan.util.XslTransformTestsUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * XSLT test cases, to test stylesheet functions defined 
+ * with syntax xsl:function.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class XslFunctionTests extends XslTransformTestsUtil {
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "xsl_function/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "xsl_function/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 xslFunctionTest1() {
+        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 xslFunctionTest2() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);   
+    }
+    
+    @Test
+    public void xslFunctionTest3() {
+        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 xslFunctionTest4() {
+        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 xslFunctionTest5() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test5.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test5.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFunctionTest6() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test6.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test6.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslFunctionTest7() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test7.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test7.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+
+}
diff --git a/tests/xsl_function/gold/test1.out b/tests/xsl_function/gold/test1.out
new file mode 100644
index 00000000..be3bd695
--- /dev/null
+++ b/tests/xsl_function/gold/test1.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>24</result>
diff --git a/tests/xsl_function/gold/test2.out b/tests/xsl_function/gold/test2.out
new file mode 100644
index 00000000..ec4f818d
--- /dev/null
+++ b/tests/xsl_function/gold/test2.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>testing for string a is this</result>
diff --git a/tests/xsl_function/gold/test3.out b/tests/xsl_function/gold/test3.out
new file mode 100644
index 00000000..b38e378c
--- /dev/null
+++ b/tests/xsl_function/gold/test3.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><avgWordSize>5.2</avgWordSize>
diff --git a/tests/xsl_function/gold/test4.out b/tests/xsl_function/gold/test4.out
new file mode 100644
index 00000000..a993901b
--- /dev/null
+++ b/tests/xsl_function/gold/test4.out
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?><factorial>
+  <number inp="1">1</number>
+  <number inp="2">2</number>
+  <number inp="3">6</number>
+  <number inp="4">24</number>
+  <number inp="5">120</number>
+  <number inp="6">720</number>
+  <number inp="7">5040</number>
+  <number inp="8">40320</number>
+  <number inp="9">362880</number>
+  <number inp="10">3628800</number>
+</factorial>
diff --git a/tests/xsl_function/gold/test5.out b/tests/xsl_function/gold/test5.out
new file mode 100644
index 00000000..c0d9dec0
--- /dev/null
+++ b/tests/xsl_function/gold/test5.out
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?><person id="1">
+    <fName>Gary</fName>
+  </person><person id="3">
+    <fName>Joseph</fName>
+  </person><person id="5">
+    <fName>Michael</fName>
+  </person><person id="2">
+    <fName>Mukul</fName>
+  </person><person id="4">
+    <fName>Noah</fName>
+  </person>
diff --git a/tests/xsl_function/gold/test6.out b/tests/xsl_function/gold/test6.out
new file mode 100644
index 00000000..33530963
--- /dev/null
+++ b/tests/xsl_function/gold/test6.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>false</one>
+  <two>true</two>
+</result>
diff --git a/tests/xsl_function/gold/test7.out b/tests/xsl_function/gold/test7.out
new file mode 100644
index 00000000..33530963
--- /dev/null
+++ b/tests/xsl_function/gold/test7.out
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>false</one>
+  <two>true</two>
+</result>
diff --git a/tests/xsl_function/test1.xsl b/tests/xsl_function/test1.xsl
new file mode 100644
index 00000000..5a39dcb1
--- /dev/null
+++ b/tests/xsl_function/test1.xsl
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                xmlns:fn1="http://test1"                
+                exclude-result-prefixes="xs fn1"
+                version="3.0">
+                
+    <!-- Author: mukulg@apache.org -->
+    
+    <!-- An XSLT stylesheet test case, to test a stylesheet
+         function defined with an XSL element xsl:function.
+    -->               
+    
+    <xsl:output method="xml" indent="yes"/>
+    
+    <xsl:template match="/">       
+       <result>
+          <xsl:copy-of select="fn1:sum(2, 10) + 12"/>  
+       </result>
+    </xsl:template>
+    
+    <!-- A function, doing a sum of two argument values. -->
+    <xsl:function name="fn1:sum" as="xs:double">
+       <xsl:param name="a1" as="xs:double"/>
+       <xsl:param name="a2" as="xs:double"/>
+       
+       <xsl:value-of select="$a1 + $a2"/>
+    </xsl:function>
+    
+    <!--
+      * 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/xsl_function/test1_a.xml b/tests/xsl_function/test1_a.xml
new file mode 100644
index 00000000..1b810774
--- /dev/null
+++ b/tests/xsl_function/test1_a.xml
@@ -0,0 +1,17 @@
+<info>
+  <person id="1">
+    <fName>Gary</fName>
+  </person>
+  <person id="2">
+    <fName>Mukul</fName>
+  </person>
+  <person id="3">
+    <fName>Joseph</fName>
+  </person>
+  <person id="4">
+    <fName>Noah</fName>
+  </person>
+  <person id="5">
+    <fName>Michael</fName>
+  </person>
+</info>
\ No newline at end of file
diff --git a/tests/xsl_function/test1_b.xml b/tests/xsl_function/test1_b.xml
new file mode 100644
index 00000000..77ebccaa
--- /dev/null
+++ b/tests/xsl_function/test1_b.xml
@@ -0,0 +1,17 @@
+<info>
+  <elem1>
+    <a>1</a>
+    <b>2</b>
+    <c>3</c>
+  </elem1>
+  <elem2>
+    <p>1</p>
+    <q>2</q>
+    <r>3</r>
+  </elem2>
+  <elem3>
+    <a>4</a>
+    <b>5</b>
+    <c>6</c>
+  </elem3>
+</info>
\ No newline at end of file
diff --git a/tests/xsl_function/test2.xsl b/tests/xsl_function/test2.xsl
new file mode 100644
index 00000000..6d71c902
--- /dev/null
+++ b/tests/xsl_function/test2.xsl
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                xmlns:str="http://fn1"                
+                exclude-result-prefixes="xs str"
+                version="3.0">
+                
+    <!-- Author: mukulg@apache.org -->
+    
+    <!-- An XSLT stylesheet test case, to test a stylesheet
+         function defined with an XSL element xsl:function.
+    -->                
+    
+    <xsl:output method="xml" indent="yes"/>
+    
+    <xsl:template match="/">       
+       <result>
+          <xsl:value-of select="str:reverse('this is a string for testing')"/>  
+       </result>
+    </xsl:template>
+    
+    <!-- A function, that reverses a sequence of string values. -->
+    <xsl:function name="str:reverse" as="xs:string">
+       <xsl:param name="str" as="xs:string"/>
+       <xsl:value-of select="reverse(tokenize($str, '\s+'))"/>
+    </xsl:function>
+    
+    <!--
+      * 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/xsl_function/test3.xsl b/tests/xsl_function/test3.xsl
new file mode 100644
index 00000000..9c7eca48
--- /dev/null
+++ b/tests/xsl_function/test3.xsl
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                xmlns:fn1="http://fn1"                
+                exclude-result-prefixes="xs fn1"
+                version="3.0">
+    
+    <!-- Author: mukulg@apache.org -->
+    
+    <!-- use with test1_a.xml -->
+    
+    <!-- An XSLT stylesheet test case, to test a stylesheet
+         function defined with an XSL element xsl:function.
+    -->
+    
+    <xsl:output method="xml" indent="yes"/>
+    
+    <xsl:template match="/info">       
+       <xsl:copy-of select="fn1:analyzeNodeSet(*)"/>   
+    </xsl:template>
+    
+    <!-- A function, that analyzes an XML element nodeset passed 
+         to it as an argument, and finds the average word characters
+         length of specific argument nodes (XML elements named as 
+         'fName') at same XML document level. -->
+    <xsl:function name="fn1:analyzeNodeSet" as="element()">
+       <xsl:param name="nodeSet" as="element()+"/>
+       <avgWordSize>
+          <xsl:value-of select="avg(for $node in $nodeSet return string-length($node/*[1]))"/>
+       </avgWordSize>
+    </xsl:function>
+    
+    <!--
+      * 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/xsl_function/test4.xsl b/tests/xsl_function/test4.xsl
new file mode 100644
index 00000000..8cbc9ff8
--- /dev/null
+++ b/tests/xsl_function/test4.xsl
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                xmlns:fn1="http://fn1"                
+                exclude-result-prefixes="xs fn1"
+                version="3.0">
+    
+    <!-- Author: mukulg@apache.org -->
+    
+    <!-- An XSLT stylesheet test case, to test a stylesheet
+         function defined with an XSL element xsl:function.
+    -->
+    <xsl:output method="xml" indent="yes"/>
+    
+    <xsl:template match="/">
+       <factorial>
+          <xsl:for-each select="1 to 10">
+             <xsl:variable name="num" select="."/>
+             <number inp="{$num}">
+                <xsl:value-of select="fn1:factorial($num)"/>
+             </number>
+          </xsl:for-each>
+       </factorial>
+    </xsl:template>
+    
+    <!-- A function that uses recursion, to calculate factorial of 
+         a numeric argument value. -->
+    <xsl:function name="fn1:factorial" as="xs:integer">
+       <xsl:param name="num" as="xs:integer"/>
+       <xsl:value-of select="if ($num = 0) then 1 else $num * fn1:factorial($num - 1)"/>
+    </xsl:function>
+    
+    <!--
+      * 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/xsl_function/test5.xsl b/tests/xsl_function/test5.xsl
new file mode 100644
index 00000000..b96a12cb
--- /dev/null
+++ b/tests/xsl_function/test5.xsl
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                xmlns:fn1="http://fn1"                
+                exclude-result-prefixes="xs fn1"
+                version="3.0">
+                
+    <!-- Author: mukulg@apache.org -->
+    
+    <!-- use with test1_a.xml -->
+    
+    <!-- An XSLT stylesheet test case, to test a stylesheet
+         function defined with an XSL element xsl:function.
+    -->                
+    
+    <xsl:output method="xml" indent="yes"/>
+    
+    <xsl:template match="/info">       
+       <xsl:copy-of select="fn1:sortNodeSet(*)"/>   
+    </xsl:template>
+    
+    <!-- A function, that traverses a node set passed as an argument
+         to it, and sorts the supplied nodes. -->
+    <xsl:function name="fn1:sortNodeSet" as="element()+">
+       <xsl:param name="nodeSet" as="element()+"/>
+       <xsl:for-each select="$nodeSet">
+          <xsl:sort select="./*[1]"/>
+          <xsl:copy-of select="."/>
+       </xsl:for-each>
+    </xsl:function>
+    
+    <!--
+      * 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/xsl_function/test6.xsl b/tests/xsl_function/test6.xsl
new file mode 100644
index 00000000..6c428d7d
--- /dev/null
+++ b/tests/xsl_function/test6.xsl
@@ -0,0 +1,71 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                xmlns:fn1="http://example.com/namespace"
+                version="3.0"
+                exclude-result-prefixes="xs fn1">
+    
+    <!-- Author: mukulg@apache.org -->
+    
+    <!-- use with test1_b.xml -->
+    
+    <!-- An XSLT stylesheet test case, to test a stylesheet
+         function defined with an XSL element xsl:function.
+    --> 
+                    
+	<xsl:output method="xml" indent="yes"/>
+	
+	<xsl:template match="/info">
+	   <result>
+	      <one>
+	         <xsl:value-of select="fn1:shallow-equals(elem1/*, elem2/*)"/>
+	      </one>
+	      <two>
+	         <xsl:value-of select="fn1:shallow-equals(elem1/*, elem3/*)"/>
+	      </two>
+	   </result>
+	</xsl:template>
+	
+	<!-- A function, that checks whether two XML element node sets passed as
+	     arguments to it are shallow equal. This function checks, whether the
+	     size of two node sets are equal, and if so that node's element name
+	     are same pair-wise within the supplied node sets. -->
+	<xsl:function name="fn1:shallow-equals" as="xs:boolean">
+	   <xsl:param name="nodeList1" as="element()*"/>
+	   <xsl:param name="nodeList2" as="element()*"/>
+	   
+	   <xsl:variable name="isNodeListsSizeEqual" select="count($nodeList1) eq count($nodeList2)"/>
+	   <xsl:choose>
+	      <xsl:when test="$isNodeListsSizeEqual">
+	         <xsl:variable name="temp1" as="element(val)*">
+	            <xsl:for-each select="$nodeList1">
+	              <xsl:variable name="pos" select="position()"/>
+	              <val><xsl:value-of select="name(.) eq name($nodeList2[$pos])"/></val>
+	            </xsl:for-each>
+	         </xsl:variable>
+	         <xsl:value-of select="every $val in $temp1 satisfies (xs:boolean(string($val)) eq xs:boolean('true'))"/>
+	      </xsl:when>
+	      <xsl:otherwise>
+	         <xsl:value-of select="xs:boolean('false')"/>
+	      </xsl:otherwise>
+	   </xsl:choose>   
+	</xsl:function>
+	
+	<!--
+      * 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/xsl_function/test7.xsl b/tests/xsl_function/test7.xsl
new file mode 100644
index 00000000..e06b94ed
--- /dev/null
+++ b/tests/xsl_function/test7.xsl
@@ -0,0 +1,71 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xs="http://www.w3.org/2001/XMLSchema"
+                xmlns:fn1="http://example.com/namespace"
+                version="3.0"
+                exclude-result-prefixes="xs fn1">
+                
+    <!-- Author: mukulg@apache.org -->
+    
+    <!-- use with test1_b.xml -->
+    
+    <!-- An XSLT stylesheet test case, to test a stylesheet
+         function defined with an XSL element xsl:function.
+    -->                 
+                
+	<xsl:output method="xml" indent="yes"/>
+	
+	<xsl:template match="/info">
+	   <result>
+	      <one>
+	         <xsl:value-of select="fn1:shallow-equals(elem1, elem2)"/>
+	      </one>
+	      <two>
+	         <xsl:value-of select="fn1:shallow-equals(elem1, elem3)"/>
+	      </two>
+	   </result>
+	</xsl:template>
+	
+	<!-- A function, that checks whether two XML nodes passed as arguments
+	     to it are shallow equal. This function, checks for the equality of
+	     two node sets that are XML element children of the respective
+	     function arguments. -->
+	<xsl:function name="fn1:shallow-equals" as="xs:boolean">
+	   <xsl:param name="node1" as="element()"/>
+	   <xsl:param name="node2" as="element()"/>
+	   
+	   <xsl:variable name="isNodeListsSizeEqual" select="count($node1/*) eq count($node2/*)"/>
+	   <xsl:choose>
+	      <xsl:when test="$isNodeListsSizeEqual">
+	         <xsl:variable name="temp1" as="element(val)*">
+	            <xsl:for-each select="$node1/*">
+	              <xsl:variable name="pos" select="position()"/>
+	              <val><xsl:value-of select="name(.) eq name($node2/*[$pos])"/></val>
+	            </xsl:for-each>
+	         </xsl:variable>
+	         <xsl:value-of select="every $val in $temp1 satisfies (xs:boolean(string($val)) eq xs:boolean('true'))"/>
+	      </xsl:when>
+	      <xsl:otherwise>
+	         <xsl:value-of select="xs:boolean('false')"/>
+	      </xsl:otherwise>
+	   </xsl:choose>   
+	</xsl:function>
+	
+	<!--
+      * 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


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