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/05 10:54:34 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing implementation of xpath 3.1 dynamic function calls. also committing few related working test cases as well. minor refactoring of few other parts of xalanj codebase, as well.

This is an automated email from the ASF dual-hosted git repository.

mukulg pushed a commit to branch xalan-j_xslt3.0
in repository https://gitbox.apache.org/repos/asf/xalan-java.git


The following commit(s) were added to refs/heads/xalan-j_xslt3.0 by this push:
     new e4c9811e committing implementation of xpath 3.1 dynamic function calls. also committing few related working test cases as well. minor refactoring of few other parts of xalanj codebase, as well.
     new 504df074 Merge pull request #18 from mukulga/xalan-j_xslt3.0_mukul
e4c9811e is described below

commit e4c9811e859bfc61f1669ec9cc91e9b875d49fa2
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Wed Jul 5 16:17:47 2023 +0530

    committing implementation of xpath 3.1 dynamic function calls. also committing few related working test cases as well. minor refactoring of few other parts of xalanj codebase, as well.
---
 src/org/apache/xalan/templates/ElemValueOf.java    |  12 +-
 src/org/apache/xpath/compiler/Compiler.java        |   7 +
 src/org/apache/xpath/compiler/OpCodes.java         |   4 +-
 src/org/apache/xpath/compiler/XPathParser.java     | 143 +++++++++++++++------
 .../xpath/functions/DynamicFunctionCall.java       | 138 ++++++++++++++++++++
 src/org/apache/xpath/objects/InlineFunction.java   |   8 +-
 src/org/apache/xpath/operations/Variable.java      |   2 +-
 tests/dynamic_function_calls/gold/test1.out        |   1 +
 tests/dynamic_function_calls/gold/test2.out        |  12 ++
 tests/dynamic_function_calls/gold/test3.out        |  12 ++
 tests/dynamic_function_calls/gold/test5.out        |  12 ++
 tests/dynamic_function_calls/test1.xsl             |  38 ++++++
 tests/dynamic_function_calls/test1_a.xml           |  13 ++
 tests/dynamic_function_calls/test1_b.xml           |  13 ++
 tests/dynamic_function_calls/test2.xsl             |  43 +++++++
 tests/dynamic_function_calls/test3.xsl             |  57 ++++++++
 tests/dynamic_function_calls/test4.xsl             |  53 ++++++++
 tests/dynamic_function_calls/test5.xsl             |  57 ++++++++
 .../xalan/xpath3/DynamicFunctionCallTests.java     | 100 ++++++++++++++
 ...ctions.java => XsConstructorFunctionTests.java} |   2 +-
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java     |   7 +-
 21 files changed, 684 insertions(+), 50 deletions(-)

diff --git a/src/org/apache/xalan/templates/ElemValueOf.java b/src/org/apache/xalan/templates/ElemValueOf.java
index b54ff9da..de37ab37 100644
--- a/src/org/apache/xalan/templates/ElemValueOf.java
+++ b/src/org/apache/xalan/templates/ElemValueOf.java
@@ -26,6 +26,7 @@ import org.apache.xml.serializer.SerializationHandler;
 import org.apache.xpath.Expression;
 import org.apache.xpath.XPath;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.functions.DynamicFunctionCall;
 import org.apache.xpath.functions.FuncExtFunction;
 import org.apache.xpath.functions.Function;
 import org.apache.xpath.objects.XObject;
@@ -348,8 +349,17 @@ public class ElemValueOf extends ElemTemplateElement {
                      }
                      (new XString(strValue)).dispatchCharactersEvents(rth);
                   }
+                  else if (expr instanceof DynamicFunctionCall) {
+                     DynamicFunctionCall dfc = (DynamicFunctionCall)expr;
+                     
+                     XObject evalResult = dfc.execute(xctxt);
+                     
+                     String strValue = evalResult.str();
+                     
+                     (new XString(strValue)).dispatchCharactersEvents(rth);
+                  }
                   else {
-                      expr.executeCharsToContentHandler(xctxt, rth);
+                     expr.executeCharsToContentHandler(xctxt, rth);
                   }
               }
           }
diff --git a/src/org/apache/xpath/compiler/Compiler.java b/src/org/apache/xpath/compiler/Compiler.java
index 23a520f8..1ee1b6d0 100644
--- a/src/org/apache/xpath/compiler/Compiler.java
+++ b/src/org/apache/xpath/compiler/Compiler.java
@@ -197,6 +197,8 @@ public class Compiler extends OpMap
       expr = compileFunction(opPos); break;
     case OpCodes.OP_INLINE_FUNCTION :
       expr = compileInlineFunction(opPos); break;
+    case OpCodes.OP_DYNAMIC_FUNCTION_CALL :
+      expr = compileDynamicFunctionCall(opPos); break;
     case OpCodes.OP_LOCATIONPATH :
       expr = locationPath(opPos); break;
     case OpCodes.OP_PREDICATE :
@@ -1163,6 +1165,11 @@ private static final boolean DEBUG = false;
   {
       return XPathParser.fInlineFunction;
   }
+  
+  Expression compileDynamicFunctionCall(int opPos) throws TransformerException
+  {
+      return XPathParser.fDynamicFunctionCall;
+  }
 
   // The current id for extension functions.
   private static long s_nextMethodId = 0;
diff --git a/src/org/apache/xpath/compiler/OpCodes.java b/src/org/apache/xpath/compiler/OpCodes.java
index c8d71dfa..bdf4a5db 100644
--- a/src/org/apache/xpath/compiler/OpCodes.java
+++ b/src/org/apache/xpath/compiler/OpCodes.java
@@ -677,8 +677,10 @@ public class OpCodes
   public static final int OP_VC_GE = 60;
   
   public static final int OP_INLINE_FUNCTION = 61;
+  
+  public static final int OP_DYNAMIC_FUNCTION_CALL = 62;
 
   /** The next free ID. Please keep this up to date. */
-  private static final int NEXT_FREE_ID = 62;
+  private static final int NEXT_FREE_ID = 63;
   
 }
diff --git a/src/org/apache/xpath/compiler/XPathParser.java b/src/org/apache/xpath/compiler/XPathParser.java
index 1aea175c..a454cf7a 100644
--- a/src/org/apache/xpath/compiler/XPathParser.java
+++ b/src/org/apache/xpath/compiler/XPathParser.java
@@ -31,6 +31,7 @@ import org.apache.xalan.res.XSLMessages;
 import org.apache.xml.utils.PrefixResolver;
 import org.apache.xpath.XPathProcessorException;
 import org.apache.xpath.domapi.XPathStylesheetDOM3Exception;
+import org.apache.xpath.functions.DynamicFunctionCall;
 import org.apache.xpath.objects.InlineFunction;
 import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XString;
@@ -78,16 +79,19 @@ public class XPathParser
   protected final static int FILTER_MATCH_PREDICATES = 2;
   
   /*
-   * While parsing XPath 3.1 "function item" inline function expressions, we use this 
-   * constant string array to make parse decisions. The elements of this array are certain 
-   * XPath operator names that need this support.
+   * While parsing XPath 3.1 "function item" inline function expressions and, 
+   * dynamic function calls, we use this constant string array to make parse 
+   * decisions. The elements of this array are certain XPath operator names 
+   * that need this support.
    */
-  static final String[] XPATH_INLINE_FN_OP_ARR = new String[] {"div", "or", "and", "mod", "to", 
-                                                                   "eq", "ne", "lt", "gt", "le", "ge"};
+  static final String[] XPATH_OP_ARR = new String[] {"div", "or", "and", "mod", "to", 
+                                                         "eq", "ne", "lt", "gt", "le", "ge"};
   
-  List<String> fXpathInlineFunctionOpTokensList = null;
+  List<String> fXpathOpArrTokensList = null;
   
   static InlineFunction fInlineFunction = null;
+  
+  static DynamicFunctionCall fDynamicFunctionCall = null;
 
   /**
    * The parser constructor.
@@ -96,7 +100,7 @@ public class XPathParser
   {
     m_errorListener = errorListener;
     m_sourceLocator = sourceLocator;
-    fXpathInlineFunctionOpTokensList = Arrays.asList(XPATH_INLINE_FN_OP_ARR);
+    fXpathOpArrTokensList = Arrays.asList(XPATH_OP_ARR);
   }
 
   /**
@@ -583,6 +587,35 @@ public class XPathParser
       System.err.println(fmsg);
     }
   }
+  
+  private String getXPathStrFromComponentParts(List<String> xpathExprStrPartList) {
+      StringBuffer funcBodyXPathExprStrBuff = new StringBuffer();
+      Object[] funcBodyXPathExprStrPartsArr = xpathExprStrPartList.toArray();
+      
+      for (int idx = 0; idx < funcBodyXPathExprStrPartsArr.length; idx++) {
+          String xpathExprStrPart = null;
+          
+          boolean isXpathInlineFunctionOpToken = false;
+          
+          if ("$".equals(funcBodyXPathExprStrPartsArr[idx]) && (idx < 
+                                                                  (funcBodyXPathExprStrPartsArr.length - 1))) {
+              // this handles, variable references within XPath expression inline function's body
+              xpathExprStrPart = "$" + funcBodyXPathExprStrPartsArr[idx + 1];
+              idx += 1;
+          }
+          else {              
+              xpathExprStrPart = (String)funcBodyXPathExprStrPartsArr[idx];
+              if (fXpathOpArrTokensList.contains(xpathExprStrPart)) {
+                 isXpathInlineFunctionOpToken = true;   
+              }
+          }
+          
+          funcBodyXPathExprStrBuff.append(isXpathInlineFunctionOpToken ? " " + xpathExprStrPart + 
+                                                                                        " " : xpathExprStrPart);
+      }
+      
+      return (funcBodyXPathExprStrBuff.toString()).trim();
+  }
 
   /**
    * Notify the user of an assertion error, and probably throw an
@@ -1510,9 +1543,13 @@ public class XPathParser
    * PrimaryExpr  ::=  VariableReference
    * | '(' Expr ')'
    * | Literal
+   * | VarRef ArgumentList
    * | Number
    * | FunctionCall
    * | FunctionItemExpr
+   * 
+   * The XPath grammar option 'VarRef ArgumentList' shown above
+   * denotes, dynamic function call.
    *
    * @return true if this method successfully matched a PrimaryExpr
    *
@@ -1536,6 +1573,63 @@ public class XPathParser
 
       matchFound = true;
     }
+    else if ((m_tokenChar == '$') && (lookahead('(', 2))) {
+       // support for XPath 3.1 dynamic function calls
+                     
+       appendOp(2, OpCodes.OP_DYNAMIC_FUNCTION_CALL);
+       
+       nextToken();  // consume '$'
+       
+       String funcRefVarName = m_token;       
+       nextToken();
+       consumeExpected('(');
+       
+       // While parsing the arguments detail of a dynamic function call,
+       // we use the code as specified below, and store the resulting
+       // information within an object of class 'DynamicFunctionCall'.
+       
+       List<String> argList = new ArrayList<>();
+       
+       List<String> argDetailsStrPartsList = new ArrayList<String>();
+       
+       while (!tokenIs(')') && m_token != null)
+       {
+          argDetailsStrPartsList.add(m_token);
+          nextToken();
+       }
+       
+       int startIdx = 0;
+       int idxComma;       
+       while (argDetailsStrPartsList.contains(",") && 
+                         (idxComma = argDetailsStrPartsList.indexOf(",")) != -1) {
+          List<String> lst1 = argDetailsStrPartsList.subList(startIdx, idxComma);
+          
+          String xpathStr = getXPathStrFromComponentParts(lst1);
+          
+          argList.add(xpathStr);
+          
+          List<String> lst2 = argDetailsStrPartsList.subList(idxComma + 1, 
+                                                                           argDetailsStrPartsList.size());
+          
+          argDetailsStrPartsList = lst2; 
+       }
+       
+       if (argDetailsStrPartsList.size() > 0) {
+           String xpathStr = getXPathStrFromComponentParts(argDetailsStrPartsList);
+           argList.add(xpathStr);
+       }
+
+       consumeExpected(')');
+       
+       fDynamicFunctionCall = new DynamicFunctionCall();
+       fDynamicFunctionCall.setFuncRefVarName(funcRefVarName);
+       fDynamicFunctionCall.setArgList(argList);
+       
+       m_ops.setOp(opPos + OpMap.MAPINDEX_LENGTH,
+                               m_ops.getOp(OpMap.MAPINDEX_LENGTH) - opPos);
+       
+       matchFound = true;
+    }
     else if (m_tokenChar == '$')
     {
       nextToken();  // consume '$'
@@ -1641,11 +1735,7 @@ public class XPathParser
       // While parsing the XPath expression string that forms body of inline
       // function expression, we only get this XPath expression's string value,
       // as determined below and store that within an object of class 
-      // 'InlineFunction', which is later used during evaluation of XPath 3.1
-      // higher-order functions like fn:for-each, fn:filter.
-      // This seems to be unlike all other XPath expression parsing (i.e, not involving
-      // the function item inline function expressions) implemented by XalanJ's XPath 1.0
-      // processor that uses this XPathParser class.
+      // 'InlineFunction'.
       
       List<String> funcBodyXPathExprStrPartsList = new ArrayList<String>();
       
@@ -1661,33 +1751,7 @@ public class XPathParser
          consumeExpected('}');         
       }
       
-      StringBuffer funcBodyXPathExprStrBuff = new StringBuffer();
-      
-      Object[] funcBodyXPathExprStrPartsArr = funcBodyXPathExprStrPartsList.toArray();
-      
-      for (int idx = 0; idx < funcBodyXPathExprStrPartsArr.length; idx++) {
-          String xpathExprStrPart = null;
-          
-          boolean isXpathInlineFunctionOpToken = false;
-          
-          if ("$".equals(funcBodyXPathExprStrPartsArr[idx]) && (idx < 
-                                                                  (funcBodyXPathExprStrPartsArr.length - 1))) {
-              // this handles, variable references within XPath expression inline function's body
-              xpathExprStrPart = "$" + funcBodyXPathExprStrPartsArr[idx + 1];
-              idx += 1;
-          }
-          else {              
-              xpathExprStrPart = (String)funcBodyXPathExprStrPartsArr[idx];
-              if (fXpathInlineFunctionOpTokensList.contains(xpathExprStrPart)) {
-                 isXpathInlineFunctionOpToken = true;   
-              }
-          }
-          
-          funcBodyXPathExprStrBuff.append(isXpathInlineFunctionOpToken ? " " + xpathExprStrPart + 
-                                                                                           " " : xpathExprStrPart);
-      }
-      
-      funcBodyXPathExprStr = (funcBodyXPathExprStrBuff.toString()).trim();
+      funcBodyXPathExprStr = getXPathStrFromComponentParts(funcBodyXPathExprStrPartsList);
       
       if (funcBodyXPathExprStr.length() > 0) {
          inlineFunction.setFuncBodyXPathExprStr(funcBodyXPathExprStr);
@@ -2641,4 +2705,5 @@ public class XPathParser
 
     return trailingSlashConsumed;
   }
+  
 }
diff --git a/src/org/apache/xpath/functions/DynamicFunctionCall.java b/src/org/apache/xpath/functions/DynamicFunctionCall.java
new file mode 100644
index 00000000..5c97cf64
--- /dev/null
+++ b/src/org/apache/xpath/functions/DynamicFunctionCall.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xpath.functions;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+
+import org.apache.xalan.extensions.ExpressionContext;
+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.InlineFunction;
+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 dynamic 
+ * function call.
+ * 
+ * Ref : https://www.w3.org/TR/xpath-31/#id-dynamic-function-invocation
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class DynamicFunctionCall extends Expression {
+    
+    private static final long serialVersionUID = -4177034386870890029L;
+
+    private String funcRefVarName;
+    
+    private List<String> argList;
+
+    public String getFuncRefVarName() {
+        return funcRefVarName;
+    }
+
+    public void setFuncRefVarName(String funcRefVarName) {
+        this.funcRefVarName = funcRefVarName;
+    }
+
+    public List<String> getArgList() {
+        return argList;
+    }
+
+    public void setArgList(List<String> argList) {
+        this.argList = argList;
+    }
+
+    @Override
+    public void callVisitors(ExpressionOwner owner, XPathVisitor visitor) {
+        // no op
+    }
+
+    @Override
+    public XObject execute(XPathContext xctxt) throws TransformerException {
+        
+       XObject evalResult = null;
+       
+       SourceLocator srcLocator = xctxt.getSAXLocator();
+       
+       int contextNode = xctxt.getContextNode();
+       
+       ExpressionContext exprContext = xctxt.getExpressionContext();
+       
+       XObject functionRef = exprContext.getVariableOrParam(new QName(funcRefVarName));
+       
+       if (functionRef instanceof InlineFunction) {
+           InlineFunction inlineFunction = (InlineFunction)functionRef;
+           
+           String inlineFnXpathStr = inlineFunction.getFuncBodyXPathExprStr();
+           List<String> funcParamNameList = inlineFunction.getFuncParamNameList();           
+           
+           if (argList.size() != funcParamNameList.size()) {
+               throw new javax.xml.transform.TransformerException("XPTY0004 : Number of arguments required for "
+                                                       + "dynamic call to function is " + funcParamNameList.size() + ". "
+                                                       + "Number of arguments provided " + argList.size() + ".", xctxt.getSAXLocator());    
+           }
+           
+           Map<QName, XObject> inlineFunctionVarMap = xctxt.getInlineFunctionVarMap();
+           
+           for (int idx = 0; idx < funcParamNameList.size(); idx++) {              
+              String funcParamName = funcParamNameList.get(idx);
+              
+              String argXPathStr = argList.get(idx);
+              XObject argValue = null;
+              if (argXPathStr.startsWith("$")) {
+                 argValue = exprContext.getVariableOrParam(new QName(argXPathStr.substring(1)));
+              }
+              else {
+                 XPath argXpath = new XPath(argXPathStr, srcLocator, null, XPath.SELECT, null);
+                 argValue = argXpath.execute(xctxt, contextNode, null);
+              }
+              
+              inlineFunctionVarMap.put(new QName(funcParamName), argValue);
+           }
+           
+           XPath inlineFnXpath = new XPath(inlineFnXpathStr, srcLocator, null, XPath.SELECT, null);
+           evalResult = inlineFnXpath.execute(xctxt, contextNode, null);
+           
+           inlineFunctionVarMap.clear();
+       }
+        
+       return evalResult;
+    }
+
+    @Override
+    public void fixupVariables(Vector vars, int globalsSize) {
+       // no op
+    }
+
+    @Override
+    public boolean deepEquals(Expression expr) {
+        return false;
+    }
+
+}
diff --git a/src/org/apache/xpath/objects/InlineFunction.java b/src/org/apache/xpath/objects/InlineFunction.java
index f9cf1c2b..766d5071 100644
--- a/src/org/apache/xpath/objects/InlineFunction.java
+++ b/src/org/apache/xpath/objects/InlineFunction.java
@@ -23,9 +23,9 @@ import org.apache.xpath.ExpressionOwner;
 import org.apache.xpath.XPathVisitor;
 
 /*
- * The XalanJ xpath parser, creates and populates this object,
- * as a representation of XPath 3.1 function item "inline function" 
- * definition within XPath expressions.
+ * The XalanJ xpath parser, creates and populates an object of this 
+ * class, as a representation of XPath 3.1 function item "inline 
+ * function" definition within XPath expressions.
  * 
  * The XPath 3.1 spec, defines function item "inline function" XPath 
  * expressions with following grammar,
@@ -43,7 +43,7 @@ import org.apache.xpath.XPathVisitor;
  * 
  * @author Mukul Gandhi <mu...@apache.org>
  *   
- * @xsl.usage advanced  
+ * @xsl.usage advanced 
  */
 public class InlineFunction extends XObject {
 
diff --git a/src/org/apache/xpath/operations/Variable.java b/src/org/apache/xpath/operations/Variable.java
index 1f247949..05a58138 100644
--- a/src/org/apache/xpath/operations/Variable.java
+++ b/src/org/apache/xpath/operations/Variable.java
@@ -214,7 +214,7 @@ public class Variable extends Expression implements PathComponent
     
     if (inlineFuncVarValue != null) {
         // dereferencing, XPath 3.1 function item "inline function" 
-        // parameter references within "inline function" body. 
+        // parameter reference within "inline function" body. 
         result = inlineFuncVarValue;
         return result;
     }
diff --git a/tests/dynamic_function_calls/gold/test1.out b/tests/dynamic_function_calls/gold/test1.out
new file mode 100644
index 00000000..040a9acd
--- /dev/null
+++ b/tests/dynamic_function_calls/gold/test1.out
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><result>5</result>
diff --git a/tests/dynamic_function_calls/gold/test2.out b/tests/dynamic_function_calls/gold/test2.out
new file mode 100644
index 00000000..9802c5b2
--- /dev/null
+++ b/tests/dynamic_function_calls/gold/test2.out
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val>-2</val>
+  <val>1</val>
+  <val>6</val>
+  <val>13</val>
+  <val>22</val>
+  <val>33</val>
+  <val>46</val>
+  <val>61</val>
+  <val>78</val>
+  <val>97</val>
+</result>
diff --git a/tests/dynamic_function_calls/gold/test3.out b/tests/dynamic_function_calls/gold/test3.out
new file mode 100644
index 00000000..720429b8
--- /dev/null
+++ b/tests/dynamic_function_calls/gold/test3.out
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val>4</val>
+  <val>5</val>
+  <val>6</val>
+  <val>7</val>
+  <val>8</val>
+  <val>9</val>
+  <val>10</val>
+  <val>11</val>
+  <val>12</val>
+  <val>13</val>
+</result>
diff --git a/tests/dynamic_function_calls/gold/test5.out b/tests/dynamic_function_calls/gold/test5.out
new file mode 100644
index 00000000..ebc2088e
--- /dev/null
+++ b/tests/dynamic_function_calls/gold/test5.out
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val length="1">h</val>
+  <val length="2">he</val>
+  <val length="3">hel</val>
+  <val length="4">hell</val>
+  <val length="5">hello</val>
+  <val length="6">hello </val>
+  <val length="7">hello w</val>
+  <val length="8">hello wo</val>
+  <val length="9">hello wor</val>
+  <val length="10">hello worl</val>
+</result>
diff --git a/tests/dynamic_function_calls/test1.xsl b/tests/dynamic_function_calls/test1.xsl
new file mode 100644
index 00000000..6334dd64
--- /dev/null
+++ b/tests/dynamic_function_calls/test1.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 -->
+   
+   <!-- An XSLT stylesheet, to test the XPath 3.1 dynamic function 
+        calls. -->                
+
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="func1" select="function($x, $y) { $x + $y }"/>
+
+   <xsl:template match="/">
+      <result>
+         <xsl:value-of select="$func1(2, 3)"/>  
+      </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/dynamic_function_calls/test1_a.xml b/tests/dynamic_function_calls/test1_a.xml
new file mode 100644
index 00000000..607f93c7
--- /dev/null
+++ b/tests/dynamic_function_calls/test1_a.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <list>
+    <idx>1</idx>
+    <idx>2</idx>
+    <idx>3</idx>
+    <idx>4</idx>
+    <idx>5</idx>
+    <idx>6</idx>
+    <idx>7</idx>
+    <idx>8</idx>
+    <idx>9</idx>
+    <idx>10</idx>
+ </list>
\ No newline at end of file
diff --git a/tests/dynamic_function_calls/test1_b.xml b/tests/dynamic_function_calls/test1_b.xml
new file mode 100644
index 00000000..f02bfa8e
--- /dev/null
+++ b/tests/dynamic_function_calls/test1_b.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <list attr="hello world. this string is used for testing.">
+    <idx>1</idx>
+    <idx>2</idx>
+    <idx>3</idx>
+    <idx>4</idx>
+    <idx>5</idx>
+    <idx>6</idx>
+    <idx>7</idx>
+    <idx>8</idx>
+    <idx>9</idx>
+    <idx>10</idx>
+ </list>
\ No newline at end of file
diff --git a/tests/dynamic_function_calls/test2.xsl b/tests/dynamic_function_calls/test2.xsl
new file mode 100644
index 00000000..0d98ca77
--- /dev/null
+++ b/tests/dynamic_function_calls/test2.xsl
@@ -0,0 +1,43 @@
+<?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 -->
+   
+   <!-- An XSLT stylesheet, to test the XPath 3.1 dynamic function 
+        calls. -->                
+
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="func1" select="function($x) { $x * $x }"/>
+
+   <xsl:template match="/list">
+      <result>
+         <xsl:for-each select="idx">
+            <xsl:variable name="n1" select="number(.)"/>
+            <val><xsl:value-of select="$func1($n1) - 3"/></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/dynamic_function_calls/test3.xsl b/tests/dynamic_function_calls/test3.xsl
new file mode 100644
index 00000000..6e9b3fe8
--- /dev/null
+++ b/tests/dynamic_function_calls/test3.xsl
@@ -0,0 +1,57 @@
+<?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 -->
+   
+   <!-- An XSLT stylesheet, to test the XPath 3.1 dynamic function 
+        calls. -->                 
+
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/list">
+      <result>
+        <xsl:for-each select="idx">
+           <xsl:call-template name="Template1">                            
+              <xsl:with-param name="funcA" select="function($x) { $x + 3 }"/>
+              <xsl:with-param name="num" select="."/>
+           </xsl:call-template>
+        </xsl:for-each>
+      </result>
+   </xsl:template>
+   
+   <!-- This template expects following two arguments,
+        1) function item "inline function" definition.
+        2) a number.
+        
+        This template makes, a function call having a 
+        numeric argument. The function definition used,
+        is the function item passed as argument. -->
+   <xsl:template name="Template1">            
+      <xsl:param name="funcA"/>
+      <xsl:param name="num"/>
+      
+      <val><xsl:value-of select="$funcA($num)"/></val>
+   </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/dynamic_function_calls/test4.xsl b/tests/dynamic_function_calls/test4.xsl
new file mode 100644
index 00000000..af258c07
--- /dev/null
+++ b/tests/dynamic_function_calls/test4.xsl
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_a.xml -->
+   
+   <!-- An XSLT stylesheet, to test the XPath 3.1 dynamic function 
+        calls. -->                 
+
+   <xsl:output method="xml" indent="yes"/>
+
+   <xsl:template match="/list">
+      <result>
+         <xsl:apply-templates select="idx">                            
+            <xsl:with-param name="funcA" select="function($x) { $x + 3 }"/>
+         </xsl:apply-templates>
+      </result>
+   </xsl:template>
+   
+   <!-- This template expects as an argument, a function item 
+        "inline function" definition.
+        
+        This template makes, a function call having a 
+        numeric argument (which is the context item). The 
+        function definition used, is the function item 
+        passed as argument. -->
+   <xsl:template match="idx">            
+      <xsl:param name="funcA"/>
+      
+      <val><xsl:value-of select="$funcA(.)"/></val>
+   </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/dynamic_function_calls/test5.xsl b/tests/dynamic_function_calls/test5.xsl
new file mode 100644
index 00000000..9d3eaee7
--- /dev/null
+++ b/tests/dynamic_function_calls/test5.xsl
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+   <!-- Author: mukulg@apache.org -->
+   
+   <!-- use with test1_b.xml -->
+   
+   <!-- An XSLT stylesheet, to test the XPath 3.1 dynamic function 
+        calls. -->                
+
+   <xsl:output method="xml" indent="yes"/>
+   
+   <xsl:variable name="subStr" select="function($str, $x) { substring($str, 1, $x) }"/>
+   
+   <xsl:variable name="strLen" select="function($str) { string-length($str) }"/>
+
+   <xsl:template match="/list">
+      <result>
+        <xsl:for-each select="idx">
+           <xsl:call-template name="Template1">                            
+              <xsl:with-param name="subStr" select="$subStr"/>
+              <xsl:with-param name="str" select="../@attr"/>
+              <xsl:with-param name="len" select="number(.)"/>
+           </xsl:call-template>
+        </xsl:for-each>
+      </result>
+   </xsl:template>
+   
+   <xsl:template name="Template1">            
+      <xsl:param name="subStr"/>
+      <xsl:param name="str"/>
+      <xsl:param name="len"/>
+      
+      <xsl:variable name="strNew" select="$subStr($str, $len)"/>      
+      <val length="{$strLen($strNew)}"><xsl:value-of select="$strNew"/></val>
+   </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/DynamicFunctionCallTests.java b/tests/org/apache/xalan/xpath3/DynamicFunctionCallTests.java
new file mode 100644
index 00000000..e05fb409
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/DynamicFunctionCallTests.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 dynamic function call test cases.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class DynamicFunctionCallTests extends XslTransformTestsUtil {        
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "dynamic_function_calls/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "dynamic_function_calls/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 xslDynamicFunctionCallTest1() {
+        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 xslDynamicFunctionCallTest2() {
+        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 xslDynamicFunctionCallTest3() {
+        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 xslDynamicFunctionCallTest4() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test4.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test3.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+    
+    @Test
+    public void xslDynamicFunctionCallTest5() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_b.xml"; 
+        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/xpath3/XsConstructorFunctions.java b/tests/org/apache/xalan/xpath3/XsConstructorFunctionTests.java
similarity index 98%
rename from tests/org/apache/xalan/xpath3/XsConstructorFunctions.java
rename to tests/org/apache/xalan/xpath3/XsConstructorFunctionTests.java
index ef279847..90ad7258 100644
--- a/tests/org/apache/xalan/xpath3/XsConstructorFunctions.java
+++ b/tests/org/apache/xalan/xpath3/XsConstructorFunctionTests.java
@@ -30,7 +30,7 @@ import org.junit.Test;
  * 
  * @xsl.usage advanced
  */
-public class XsConstructorFunctions extends XslTransformTestsUtil {        
+public class XsConstructorFunctionTests extends XslTransformTestsUtil {        
     
     private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "xs_constructor_functions/";
     
diff --git a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
index 248daa7d..0aae607c 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -16,6 +16,7 @@
  */
 package org.apache.xalan.xslt3;
 
+import org.apache.xalan.xpath3.DynamicFunctionCallTests;
 import org.apache.xalan.xpath3.FnAbsTests;
 import org.apache.xalan.xpath3.FnFilterTests;
 import org.apache.xalan.xpath3.FnForEachTests;
@@ -28,7 +29,7 @@ import org.apache.xalan.xpath3.RangeExprTests;
 import org.apache.xalan.xpath3.SequenceTests;
 import org.apache.xalan.xpath3.StringTests;
 import org.apache.xalan.xpath3.ValueComparisonTests;
-import org.apache.xalan.xpath3.XsConstructorFunctions;
+import org.apache.xalan.xpath3.XsConstructorFunctionTests;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 import org.junit.runners.Suite.SuiteClasses;
@@ -49,11 +50,11 @@ import org.junit.runners.Suite.SuiteClasses;
 @SuiteClasses({ AnalyzeStringTests.class, AttributeTests.class, GroupingTests.class,
                 GroupingWithSortTests.class, RtfMigrationTests.class, QuantifiedExprTests.class, 
                 FnUnparsedTextTests.class, FnTokenizeTests.class, FnStringJoinTests.class,
-                FnAbsTests.class, StringTests.class, XsConstructorFunctions.class, 
+                FnAbsTests.class, StringTests.class, XsConstructorFunctionTests.class, 
                 FnIndexOfTests.class, SequenceTests.class, RangeExprTests.class, 
                 W3c_xslt30_IterateTests.class, W3c_xslt30_AxesTests.class, XslIterateTests.class,
                 ValueComparisonTests.class, InlineFunctionItemExprTests.class, FnForEachTests.class, 
-                FnFilterTests.class })
+                FnFilterTests.class, DynamicFunctionCallTests.class })
 public class AllXsl3Tests {
 
 }


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