You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2016/07/16 11:58:57 UTC

[1/2] jena git commit: JENA-508: fn:format-number

Repository: jena
Updated Branches:
  refs/heads/master 807e8ff77 -> b9544d7d7


JENA-508: fn:format-number


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/6d308ff9
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/6d308ff9
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/6d308ff9

Branch: refs/heads/master
Commit: 6d308ff9833a5bbeb70365f579fe6dc5c6b6a1c6
Parents: 807e8ff
Author: Andy Seaborne <an...@apache.org>
Authored: Fri Jul 15 22:27:50 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Jul 16 12:38:24 2016 +0100

----------------------------------------------------------------------
 .../jena/sparql/expr/nodevalue/XSDFuncOp.java   | 43 ++++++++++++
 .../jena/sparql/function/StandardFunctions.java | 17 ++---
 .../function/library/FN_FormatNumber.java       | 52 ++++++++++++++
 .../apache/jena/sparql/expr/TestFunctions.java  | 71 ++++++++++++++++----
 4 files changed, 158 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/6d308ff9/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java
index 7b565fd..390cccf 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java
@@ -33,7 +33,10 @@ import static org.apache.jena.sparql.expr.nodevalue.NumericType.OP_INTEGER ;
 
 import java.math.BigDecimal ;
 import java.math.BigInteger ;
+import java.text.DecimalFormat ;
+import java.text.DecimalFormatSymbols ;
 import java.text.Normalizer;
+import java.text.NumberFormat ;
 import java.util.*;
 import java.util.regex.Matcher ;
 import java.util.regex.Pattern ;
@@ -1604,4 +1607,44 @@ public class XSDFuncOp
         else
             return NodeValue.makeDate(calValue);
     }
+    
+    /** fn:format-number
+     * 
+     * The 3rd argument, if present, called decimal-format-name, is here a 
+     * IETF BCP 47 language tag string.
+     */
+    public static NodeValue formatNumber(NodeValue nv, NodeValue picture, NodeValue nvLocale) {
+        if ( !nv.isNumber() )
+            NodeValue.raise(new ExprEvalException("Not a number: " + nv)) ;
+        if ( !picture.isString() )
+            NodeValue.raise(new ExprEvalException("Not a string: " + picture)) ;
+        if ( nvLocale != null && !nvLocale.isString() )
+            NodeValue.raise(new ExprEvalException("Not a string: " + nvLocale)) ;
+
+        Locale locale = Locale.ROOT ;
+        if ( nvLocale != null )
+            locale = Locale.forLanguageTag(nvLocale.asString()) ;
+        DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale) ;
+        
+        NumberFormat formatter = 
+            (dfs == null )
+                ? new DecimalFormat(picture.getString())
+                : new DecimalFormat(picture.getString(), dfs) ;
+            
+        NumericType nt = XSDFuncOp.classifyNumeric("fn:formatNumber", nv) ;
+        String s = null ;
+        switch(nt) {
+            case OP_DECIMAL :
+            case OP_DOUBLE :
+            case OP_FLOAT :
+                s = formatter.format(nv.getDouble()) ;
+                break ;
+            case OP_INTEGER :
+                s = formatter.format(nv.getInteger().longValue()) ;
+                break ;
+            default :
+                break ;
+        }
+        return NodeValue.makeString(s) ; 
+    }
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/6d308ff9/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java
index 5a9963b..4c41a39 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java
@@ -31,12 +31,9 @@ public class StandardFunctions
     /* JENA-508
      * Missing: (July 2016)
      * 
-     *   fn:format-number
      *   fn:format-dateTime
      *   fn:format-date
      *   fn:format-time
-     *   fn:normalize-space
-     *  fn:normalize-unicode
      * 
      * and adapters to SPARQL operations that have keywords:
      *   fn:replace
@@ -45,13 +42,9 @@ public class StandardFunctions
      */
     
     /* Implementation notes
-     * fn:normalize-space   : leading and trailing whitespace removed, 
-     *                        sequences of internal whitespace reduced to a single space character.
-     *                        Whitespace is "Character.isWhitespace" 
-     *                        Regex \v \h (check). 
-     * fn:normalize-unicode : Java Normalizer.normalize applies the rules.
-     * fn:format-number     : Java NumberFormat picture strings.
-     * fn:format-dateTime/fn:format-time/fn:format-date : Java SimpleDateFormat
+     *   fn:format-dateTime / fn:format-time / fn:format-date
+     *   This is not Java's SimpleDateFormat.
+     *   It has its own picture syntax.
      *     Like adjust-* we may need only one function. 
      */
     
@@ -103,7 +96,7 @@ public class StandardFunctions
         addCastTemporal(registry, XSDDatatype.XSDgDay) ;
 
         //TODO op:numeric-greater-than etc.
-        //TODO sparql:* for al the SPARQL builtins.
+        //TODO sparql:* for all the SPARQL builtins.
         
         // Sections refer to XQ/XP Expression 3.1
         // https://www.w3.org/TR/xpath-functions-3/
@@ -149,6 +142,8 @@ public class StandardFunctions
         // fn:tokenize -> sequence
         
 //        4.7.2 fn:format-number
+        add(registry, xfn+"format-number",  FN_FormatNumber.class) ;
+        
 
 //        4.4.1 fn:abs
 //        4.4.2 fn:ceiling

http://git-wip-us.apache.org/repos/asf/jena/blob/6d308ff9/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_FormatNumber.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_FormatNumber.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_FormatNumber.java
new file mode 100644
index 0000000..7228f4b
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_FormatNumber.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.function.library;
+
+import java.util.List ;
+
+import org.apache.jena.atlas.lib.Lib ;
+import org.apache.jena.query.QueryBuildException ;
+import org.apache.jena.sparql.expr.ExprEvalException ;
+import org.apache.jena.sparql.expr.ExprList ;
+import org.apache.jena.sparql.expr.NodeValue ;
+import org.apache.jena.sparql.expr.nodevalue.XSDFuncOp ;
+import org.apache.jena.sparql.function.FunctionBase ;
+
+/** fn:format-number : 2 or 3 arguments.
+ * The 3rd argument, decimal-format-name, is here a IETF BCP 47 language tag string.
+ */
+public class FN_FormatNumber extends FunctionBase {
+    @Override
+    public void checkBuild(String uri, ExprList args) {
+        if ( args.size() != 2 && args.size() != 3 )
+            throw new QueryBuildException("Function '"+Lib.className(this)+"' takes two or three arguments") ;
+    }
+    
+    @Override
+    public NodeValue exec(List<NodeValue> args) {
+        if ( args.size() != 2 && args.size() != 3 )
+            throw new ExprEvalException("Function '"+Lib.className(this)+"' takes two or three arguments") ;
+        NodeValue value = args.get(0) ; 
+        NodeValue picture = args.get(1) ;
+        NodeValue decimalFormatName = null ;
+        if ( args.size() == 3)
+            decimalFormatName = args.get(2) ;
+        return XSDFuncOp.formatNumber(value, picture, decimalFormatName) ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/6d308ff9/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions.java
index e7bf8a6..eb13b62 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions.java
@@ -34,6 +34,7 @@ import org.apache.jena.graph.NodeFactory ;
 import org.apache.jena.sparql.ARQConstants ;
 import org.apache.jena.sparql.function.FunctionEnvBase ;
 import org.apache.jena.sparql.util.ExprUtils ;
+import org.junit.Assert ;
 import org.junit.Test ;
 
 public class TestFunctions
@@ -423,6 +424,51 @@ public class TestFunctions
     @Test public void exprAdjustTimeToTz_07(){test("fn:adjust-time-to-timezone('10:00:00-07:00'^^xsd:time,'PT10H'^^xsd:dayTimeDuration)",NodeValue.makeNode("03:00:00+10:00",XSDDatatype.XSDtime));}
     //@Test public void exprStrJoin()      { test("fn:string-join('a', 'b')", NodeValue.makeString("ab")) ; }
     
+    private static void testNumberFormat(String expression, String expected) {
+        Expr expr = ExprUtils.parse(expression) ;
+        NodeValue r = expr.eval(null, FunctionEnvBase.createTest()) ;
+        Assert.assertTrue(r.isString());
+        Assert.assertEquals(expected, r.getString()) ;
+        
+    }
+    
+    @Test public void formatNumber_01()     { testNumberFormat("fn:format-number(0,'#')", "0") ; }
+    @Test public void formatNumber_02()     { testNumberFormat("fn:format-number(1234, '#')", "1234") ; }
+    @Test public void formatNumber_03()     { testNumberFormat("fn:format-number(1234, '#,###')", "1,234") ; }
+    @Test public void formatNumber_04()     { testNumberFormat("fn:format-number(1e3, '#,###,###.#')", "1,000") ; }
+    @Test public void formatNumber_05()     { testNumberFormat("fn:format-number(10.5, '##.#')", "10.5") ; }
+    @Test public void formatNumber_06()     { testNumberFormat("fn:format-number(-10.5, '##.##')", "-10.5") ; }
+    @Test public void formatNumber_08()     { testNumberFormat("fn:format-number(123, 'NotAPattern')", "NotAPattern123") ; }
+    
+    @Test public void formatNumber_11()     { testNumberFormat("fn:format-number(0, '#', 'fr')", "0") ; }
+    // No-break space
+    @Test public void formatNumber_12()     { testNumberFormat("fn:format-number(1234.5,'#,###.#', 'fr')", "1\u00A0234,5") ; }
+    @Test public void formatNumber_13()     { testNumberFormat("fn:format-number(1234.5,'#,###.#', 'de')", "1.234,5") ; }
+    
+    @Test public void formatNumber_14()     { testNumberFormat("fn:format-number(12, '0,000.0', 'en')", "0,012.0") ; }
+    @Test public void formatNumber_15()     { testNumberFormat("fn:format-number(0, '00,000', 'fr')", "00\u00A0000") ; }
+
+    @Test(expected=ExprEvalException.class)
+    public void formatNumber_20() {
+        // String as number
+        testNumberFormat("fn:format-number('String', '#')", null) ;
+    }
+    @Test(expected=ExprEvalException.class)
+    public void formatNumber_21() {
+        // Pattern is not a string
+        testNumberFormat("fn:format-number(123, <uri>)", null) ; 
+    }
+    @Test(expected=ExprEvalException.class)
+    public void formatNumber_22() {
+        // Locale is not a string
+        testNumberFormat("fn:format-number(123, '###', 123)", null) ; 
+    }
+
+    public void formatNumber_23() {
+        // Not a locale - default to Locale.ROOT
+        testNumberFormat("fn:format-number(123, '###', 'WhereAmI?')", null) ; 
+    }
+    
     @Test public void exprSameTerm1()     { test("sameTerm(1,1)",           TRUE) ; }
     @Test public void exprSameTerm2()     { test("sameTerm(1,1.0)",         FALSE) ; }
     @Test public void exprSameTerm3()     { test("sameTerm(1,1e0)",         FALSE) ; }
@@ -468,28 +514,25 @@ public class TestFunctions
     E_IRI
     E_BNode
     */ 
-    
-    private void test(String exprStr, NodeValue result)
-    {
+
+    private void test(String exprStr, NodeValue result) {
         Expr expr = ExprUtils.parse(exprStr) ;
         NodeValue r = expr.eval(null, FunctionEnvBase.createTest()) ;
         assertEquals(result, r) ;
     }
-
-    private void testEqual(String exprStr, String exprStrExpected)
-    {
+    
+    private void testEqual(String exprStr, String exprStrExpected) {
         Expr expr = ExprUtils.parse(exprStrExpected) ;
         NodeValue rExpected = expr.eval(null, FunctionEnvBase.createTest()) ;
-        test(exprStr,rExpected);
+        test(exprStr, rExpected) ;
     }
-
-    private void testEvalException(String exprStr)
-    {
+    
+    private void testEvalException(String exprStr) {
         Expr expr = ExprUtils.parse(exprStr) ;
         try {
-             NodeValue r = expr.eval(null, FunctionEnvBase.createTest()) ;
-             fail("No exception raised") ;
-        } catch (ExprEvalException ex) {}
-            
+            NodeValue r = expr.eval(null, FunctionEnvBase.createTest()) ;
+            fail("No exception raised") ;
+        }
+        catch (ExprEvalException ex) {}
     }
 }


[2/2] jena git commit: This closes #115.

Posted by an...@apache.org.
This closes #115.


Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/b9544d7d
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/b9544d7d
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/b9544d7d

Branch: refs/heads/master
Commit: b9544d7d78c984ff178f76f2d2ca54133d53a7c7
Parents: 6d308ff
Author: Andy Seaborne <an...@apache.org>
Authored: Sat Jul 16 12:58:21 2016 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Sat Jul 16 12:58:21 2016 +0100

----------------------------------------------------------------------

----------------------------------------------------------------------