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/13 15:35:18 UTC

[xalan-java] branch xalan-j_xslt3.0 updated: committing improvements to an xpath 3.1 function fn:round (implementing an optional second argument to this function, that provides value for 'precision'). also committing few new working related test cases as well. doing minor improvements to implementations of functions fn:ceiling and fn:floor, 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 ac88e64c committing improvements to an xpath 3.1 function fn:round (implementing an optional second argument to this function, that provides value for 'precision'). also committing few new working related test cases as well. doing minor improvements to implementations of functions fn:ceiling and fn:floor, as well.
     new be4c8d51 Merge pull request #84 from mukulga/xalan-j_xslt3.0_mukul
ac88e64c is described below

commit ac88e64c0de287cbd1341c6d24a149750c5b7bad
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Wed Sep 13 20:59:18 2023 +0530

    committing improvements to an xpath 3.1 function fn:round (implementing an optional second argument to this function, that provides value for 'precision'). also committing few new working related test cases as well. doing minor improvements to implementations of functions fn:ceiling and fn:floor, as well.
---
 src/org/apache/xpath/functions/FuncCeiling.java |  31 ++--
 src/org/apache/xpath/functions/FuncFloor.java   |  11 +-
 src/org/apache/xpath/functions/FuncRound.java   | 184 +++++++++++++++++++++---
 tests/fn_round/gold/test1.out                   |   7 +
 tests/fn_round/gold/test2.out                   |   7 +
 tests/fn_round/test1.xsl                        |  50 +++++++
 tests/fn_round/test1_a.xml                      |   7 +
 tests/fn_round/test2.xsl                        |  43 ++++++
 tests/org/apache/xalan/xpath3/FnRoundTests.java |  70 +++++++++
 tests/org/apache/xalan/xslt3/AllXsl3Tests.java  |   3 +-
 10 files changed, 374 insertions(+), 39 deletions(-)

diff --git a/src/org/apache/xpath/functions/FuncCeiling.java b/src/org/apache/xpath/functions/FuncCeiling.java
index c7f6bac4..2f95c22d 100644
--- a/src/org/apache/xpath/functions/FuncCeiling.java
+++ b/src/org/apache/xpath/functions/FuncCeiling.java
@@ -25,23 +25,26 @@ import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
 
 /**
- * Execute the Ceiling() function.
+ * Implementation of the ceiling() function.
+ * 
  * @xsl.usage advanced
  */
-public class FuncCeiling extends FunctionOneArg
+public class FuncCeiling extends FunctionDef1Arg
 {
     static final long serialVersionUID = -1275988936390464739L;
 
-  /**
-   * Execute the function.  The function must return
-   * a valid object.
-   * @param xctxt The current execution context.
-   * @return A valid XObject.
-   *
-   * @throws javax.xml.transform.TransformerException
-   */
-  public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
-  {
-    return new XNumber(Math.ceil(m_arg0.execute(xctxt).num()));
-  }
+    /**
+     * Execute the function. The function must return
+     * a valid object.
+     * @param xctxt The current execution context.
+     * @return A valid XObject.
+     *
+     * @throws javax.xml.transform.TransformerException
+    */
+    public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
+    {
+        String strValueOfArg = (getArg0AsString(xctxt)).toString();
+      
+        return new XNumber(Math.ceil(Double.valueOf(strValueOfArg)));
+    }
 }
diff --git a/src/org/apache/xpath/functions/FuncFloor.java b/src/org/apache/xpath/functions/FuncFloor.java
index 4e6dd052..dda0c77a 100644
--- a/src/org/apache/xpath/functions/FuncFloor.java
+++ b/src/org/apache/xpath/functions/FuncFloor.java
@@ -25,15 +25,16 @@ import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
 
 /**
- * Execute the Floor() function.
+ * Implementation of the floor() function.
+ * 
  * @xsl.usage advanced
  */
-public class FuncFloor extends FunctionOneArg
+public class FuncFloor extends FunctionDef1Arg
 {
     static final long serialVersionUID = 2326752233236309265L;
 
   /**
-   * Execute the function.  The function must return
+   * Execute the function. The function must return
    * a valid object.
    * @param xctxt The current execution context.
    * @return A valid XObject.
@@ -42,6 +43,8 @@ public class FuncFloor extends FunctionOneArg
    */
   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
   {
-    return new XNumber(java.lang.Math.floor(m_arg0.execute(xctxt).num()));
+      String strValueOfArg = (getArg0AsString(xctxt)).toString();
+      
+      return new XNumber(Math.floor(Double.valueOf(strValueOfArg)));
   }
 }
diff --git a/src/org/apache/xpath/functions/FuncRound.java b/src/org/apache/xpath/functions/FuncRound.java
index 68b414c7..4ea1d27d 100644
--- a/src/org/apache/xpath/functions/FuncRound.java
+++ b/src/org/apache/xpath/functions/FuncRound.java
@@ -20,33 +20,177 @@
  */
 package org.apache.xpath.functions;
 
+import java.text.DecimalFormat;
+
+import javax.xml.transform.SourceLocator;
+
+import org.apache.xalan.res.XSLMessages;
+import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
+import org.apache.xml.dtm.DTM;
+import org.apache.xml.utils.XMLString;
+import org.apache.xpath.Expression;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.SelfIteratorNoPredicate;
 import org.apache.xpath.objects.XNumber;
 import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XString;
+import org.apache.xpath.res.XPATHErrorResources;
 
 /**
- * Execute the round() function.
+ * Implementation of the round() function.
+ * 
  * @xsl.usage advanced
  */
-public class FuncRound extends FunctionOneArg
+public class FuncRound extends Function2Args
 {
-    static final long serialVersionUID = -7970583902573826611L;
+      static final long serialVersionUID = -7970583902573826611L;
+    
+      /**
+       * Execute the function. The function must return a valid object.
+       * @param xctxt The current execution context.
+       * @return A valid XObject.
+       *
+       * @throws javax.xml.transform.TransformerException
+       */
+      public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException {          
+          
+          XObject result = null;
+          
+          SourceLocator srcLocator = xctxt.getSAXLocator();
+          
+          String strValueOfArg0 = (getArgAsString(m_arg0, xctxt)).toString();
+          
+          if ((strValueOfArg0 == null) || "".equals(strValueOfArg0.trim())) {
+              throw new javax.xml.transform.TransformerException("FORG0006 : The first argument to function "
+                                                                                                          + "fn:round() is empty.", srcLocator);
+          }
+          
+          if (m_arg1 == null) {
+             try {
+                result = new XNumber(Math.round(Double.valueOf(strValueOfArg0)));
+                
+                return result;
+             }
+             catch (Exception ex) {
+                throw new javax.xml.transform.TransformerException("FORG0006 : An error occured, while evaluating one argument "
+                                                                                                               + "version of function fn:round(). "
+                                                                                                               + "Please verify the function call with respect to function signature.", 
+                                                                                                                       srcLocator); 
+             }
+          }
+          else {
+              try {
+                  String strValueOfArg1 = (getArgAsString(m_arg1, xctxt)).toString();
+    
+                  int arg1AsInt = (Integer.valueOf(strValueOfArg1)).intValue();
+                     
+                  if (arg1AsInt >= 0) {
+                     DecimalFormat decimalFormat = new DecimalFormat("#." + getStrForZeros(arg1AsInt));
+                     double valAfterRounding = (Double.valueOf(decimalFormat.format(Double.valueOf(
+                                                                                                    strValueOfArg0)))).doubleValue();
+                     result = new XNumber(valAfterRounding);
+                  }
+                  else {
+                     throw new javax.xml.transform.TransformerException("FORG0006 : A negative integer value of second argument to "
+                                                                                                                     + "function fn:round() is not supported.", 
+                                                                                                                     srcLocator); 
+                  }
+              }
+              catch (Exception ex) {
+                  throw new javax.xml.transform.TransformerException("FORG0006 : An error occured, while evaluating two argument "
+                                                                                                 + "version of function fn:round(). Please verify the function call "
+                                                                                                 + "with respect to function signature.", srcLocator);
+              }
+          }
+          
+          return result;
+      }
+      
+      /**
+       * Check that the number of arguments passed to this function is correct.
+       *
+       * @param argNum The number of arguments that is being passed to the function.
+       *
+       * @throws WrongNumberArgsException
+       */
+      public void checkNumberArgs(int argNum) throws WrongNumberArgsException
+      {
+         if (argNum > 2) {
+            reportWrongNumberArgs();
+         }
+      }
 
-  /**
-   * Execute the function.  The function must return
-   * a valid object.
-   * @param xctxt The current execution context.
-   * @return A valid XObject.
-   *
-   * @throws javax.xml.transform.TransformerException
-   */
-  public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
-  {
-          final XObject obj = m_arg0.execute(xctxt);
-          final double val= obj.num();
-          if (val >= -0.5 && val < 0) return new XNumber(-0.0);
-          if (val == 0.0) return new XNumber(val);
-          return new XNumber(java.lang.Math.floor(val
-                                            + 0.5));
-  }
+      /**
+       * Constructs and throws a WrongNumberArgException with the appropriate
+       * message for this function object.
+       *
+       * @throws WrongNumberArgsException
+       */
+      protected void reportWrongNumberArgs() throws WrongNumberArgsException {
+          throw new WrongNumberArgsException(XSLMessages.createXPATHMessage(
+                                                  XPATHErrorResources.ER_ONE_OR_TWO, null)); //"1 or 2"
+      }
+      
+      /**
+       * Execute the first argument expression that is expected to return a
+       * string. If the argument is null, then get the string value from the
+       * current context node.
+       *
+       * @param expr    Function argument's XPath expression object
+       * @param xctxt   Runtime XPath context
+       *
+       * @return The string value of the first argument, or the string value of the
+       *         current context node if the first argument is null.
+       *
+       * @throws javax.xml.transform.TransformerException if an error occurs while
+       *                                   executing the argument expression.
+       */
+      private XMLString getArgAsString(Expression expr, XPathContext xctxt) throws javax.xml.transform.TransformerException {
+            
+          XMLString resultVal = null;
+              
+          if (expr == null) {
+             int currentNode = xctxt.getCurrentNode();
+             if (currentNode == DTM.NULL) {
+                resultVal = XString.EMPTYSTRING;
+             }
+             else {
+                DTM dtm = xctxt.getDTM(currentNode);
+                resultVal = dtm.getStringValue(currentNode);
+             }      
+          }
+          else if (expr instanceof SelfIteratorNoPredicate) {
+             XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
+             if (xpath3ContextItem != null) {
+                resultVal = new XString(XslTransformEvaluationHelper.getStrVal(xpath3ContextItem));
+             }
+             else {
+                XObject arg0XObject = expr.execute(xctxt);
+                   
+                resultVal = new XString(XslTransformEvaluationHelper.getStrVal(arg0XObject));
+             }
+          }
+          else {
+             XObject arg0XObject = expr.execute(xctxt);
+                
+             resultVal = new XString(XslTransformEvaluationHelper.getStrVal(arg0XObject));  
+          }
+            
+          return resultVal;
+      }
+      
+      /*
+       * Given a non-negative integer value, return a string comprising those many 
+       * characters '0'. We use the string value returned by this method, to construct 
+       * a java.text.DecimalFormat object instance.
+       */
+      private String getStrForZeros(int strSize) {
+         String strVal = "";
+         
+         for (int idx = 0; idx < strSize; idx++) {
+            strVal = strVal + "0";  
+         }
+         
+         return strVal;
+      }
 }
diff --git a/tests/fn_round/gold/test1.out b/tests/fn_round/gold/test1.out
new file mode 100644
index 00000000..96199716
--- /dev/null
+++ b/tests/fn_round/gold/test1.out
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <one>3</one>
+  <two>2</two>
+  <three>-2</three>
+  <four>1.12</four>
+  <five>3.14</five>
+</result>
diff --git a/tests/fn_round/gold/test2.out b/tests/fn_round/gold/test2.out
new file mode 100644
index 00000000..fc15c64e
--- /dev/null
+++ b/tests/fn_round/gold/test2.out
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?><result>
+  <val inp="2.5">3</val>
+  <val inp="2.4999">2</val>
+  <val inp="-2.5">-2</val>
+  <val inp="1.125">1.12</val>
+  <val inp="3.1415e0">3.14</val>
+</result>
diff --git a/tests/fn_round/test1.xsl b/tests/fn_round/test1.xsl
new file mode 100644
index 00000000..4364436e
--- /dev/null
+++ b/tests/fn_round/test1.xsl
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+    <!-- Author: mukulg@apache.org -->
+    
+    <!-- An XSLT stylesheet, to test an XPath 3.1 
+         function fn:round(). -->                
+    
+    <xsl:output method="xml" indent="yes"/>
+    
+    <xsl:template match="/">       
+       <result>
+         <one>
+            <xsl:value-of select="round(2.5)"/>
+         </one>
+         <two>
+            <xsl:value-of select="round(2.4999)"/>
+         </two>
+         <three>
+            <xsl:value-of select="round(-2.5)"/>
+         </three>
+         <four>
+            <xsl:value-of select="round(1.125, 2)"/>
+         </four>
+         <five>
+            <xsl:value-of select="round(3.1415e0, 2)"/>
+         </five>
+       </result>
+    </xsl:template>
+    
+    <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+    -->
+    
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/fn_round/test1_a.xml b/tests/fn_round/test1_a.xml
new file mode 100644
index 00000000..aaccddd3
--- /dev/null
+++ b/tests/fn_round/test1_a.xml
@@ -0,0 +1,7 @@
+<data>
+  <val>2.5</val>
+  <val>2.4999</val>
+  <val>-2.5</val>
+  <val>1.125</val>
+  <val>3.1415e0</val>
+</data>
\ No newline at end of file
diff --git a/tests/fn_round/test2.xsl b/tests/fn_round/test2.xsl
new file mode 100644
index 00000000..196c6594
--- /dev/null
+++ b/tests/fn_round/test2.xsl
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="3.0">
+                
+    <!-- Author: mukulg@apache.org -->
+    
+    <!-- use test1_a.xml -->
+    
+    <!-- An XSLT stylesheet, to test an XPath 3.1 function 
+         fn:round(). This stylesheet reads an XML input data 
+         to be transformed, from an external document.-->                
+    
+    <xsl:output method="xml" indent="yes"/>
+    
+    <xsl:template match="/data">       
+       <result>
+         <xsl:for-each select="val">
+           <val inp="{.}">
+              <xsl:value-of select="if (position() lt 4) then round(.) else round(., 2)"/>
+           </val>
+         </xsl:for-each>
+       </result>
+    </xsl:template>
+    
+    <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the  "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+    -->
+    
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/tests/org/apache/xalan/xpath3/FnRoundTests.java b/tests/org/apache/xalan/xpath3/FnRoundTests.java
new file mode 100644
index 00000000..41fbf204
--- /dev/null
+++ b/tests/org/apache/xalan/xpath3/FnRoundTests.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.xalan.xpath3;
+
+import org.apache.xalan.util.XslTransformTestsUtil;
+import org.apache.xalan.xslt3.XSLConstants;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * XPath 3.1 function fn:round test cases.
+ * 
+ * @author Mukul Gandhi <mu...@apache.org>
+ * 
+ * @xsl.usage advanced
+ */
+public class FnRoundTests extends XslTransformTestsUtil {        
+    
+    private static final String XSL_TRANSFORM_INPUT_DIRPATH = XSLConstants.XSL_TRANSFORM_INPUT_DIRPATH_PREFIX + "fn_round/";
+    
+    private static final String XSL_TRANSFORM_GOLD_DIRPATH = XSLConstants.XSL_TRANSFORM_GOLD_DIRPATH_PREFIX + "fn_round/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 xslFnRoundTest1() {
+        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 xslFnRoundTest2() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test1_a.xml"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test2.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test2.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
+
+}
diff --git a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
index f47c20f9..0742c207 100644
--- a/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
+++ b/tests/org/apache/xalan/xslt3/AllXsl3Tests.java
@@ -35,6 +35,7 @@ import org.apache.xalan.xpath3.FnMaxTests;
 import org.apache.xalan.xpath3.FnMinTests;
 import org.apache.xalan.xpath3.FnParseXmlFragmentTests;
 import org.apache.xalan.xpath3.FnParseXmlTests;
+import org.apache.xalan.xpath3.FnRoundTests;
 import org.apache.xalan.xpath3.FnSortTests;
 import org.apache.xalan.xpath3.FnStringJoinTests;
 import org.apache.xalan.xpath3.FnStringToCodepointsTests;
@@ -94,7 +95,7 @@ import org.junit.runners.Suite.SuiteClasses;
                 SequenceFunctionTests.class, FnParseXmlTests.class, FnParseXmlFragmentTests.class,
                 TemplateTests.class, FnAvgTests.class, FnMaxTests.class, FnMinTests.class, FnContainsTokenTests.class,
                 XslVariableAttributeAsTests.class, InstanceOfExprTests.class, XslTemplateAttributeAsTests.class,
-                XslFunctionTests.class })
+                XslFunctionTests.class, FnRoundTests.class })
 public class AllXsl3Tests {
 
 }


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