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 2019/06/07 10:50:17 UTC
[jena] branch master updated: JENA-1717: xsd:decimal canonical forms
This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/master by this push:
new 15929f5 JENA-1717: xsd:decimal canonical forms
new 5cca7dc Merge pull request #574 from afs/xsd-decimal
15929f5 is described below
commit 15929f50cf61cabbbaa9b0de36d0684415056820
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Thu May 30 18:18:14 2019 +0100
JENA-1717: xsd:decimal canonical forms
---
.../org/apache/jena/sparql/expr/NodeValue.java | 2 +-
.../sparql/expr/nodevalue/NodeValueDecimal.java | 18 +++-----
.../jena/sparql/expr/nodevalue/XSDFuncOp.java | 33 +++++++++-----
.../java/org/apache/jena/sparql/util/Utils.java | 6 ++-
.../apache/jena/sparql/expr/TestFunctions2.java | 18 ++++----
.../apache/jena/sparql/expr/TestNodeValueOps.java | 2 +-
.../org/apache/jena/sparql/expr/TestXSDFuncOp.java | 52 ++++++++++++++++++++++
7 files changed, 98 insertions(+), 33 deletions(-)
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java
index 5dc5e06..dadc33a 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java
@@ -338,7 +338,7 @@ public abstract class NodeValue extends ExprNode
public static NodeValue makeNodeDecimal(BigDecimal decimal)
{
- NodeValue nv = makeNode(Utils.stringForm(decimal), null, XSDdecimal.getURI()) ;
+ NodeValue nv = XSDFuncOp.canonicalDecimalNV(decimal) ;
return nv ;
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDecimal.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDecimal.java
index ee704f3..9abb783 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDecimal.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDecimal.java
@@ -24,8 +24,6 @@ import org.apache.jena.datatypes.xsd.XSDDatatype ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.NodeFactory ;
import org.apache.jena.sparql.expr.NodeValue ;
-import org.apache.jena.sparql.util.Utils ;
-
public class NodeValueDecimal extends NodeValue
{
@@ -33,7 +31,7 @@ public class NodeValueDecimal extends NodeValue
public NodeValueDecimal(BigDecimal d) { decimal = d ; }
public NodeValueDecimal(BigDecimal d, Node n) { super(n) ; decimal = d ; }
-
+
@Override
public boolean isNumber() { return true ; }
@Override
@@ -51,23 +49,21 @@ public class NodeValueDecimal extends NodeValue
public double getDouble() { return decimal.doubleValue() ; }
@Override
- protected Node makeNode()
- {
- int s = decimal.scale() ;
- return NodeFactory.createLiteral(Utils.stringForm(decimal), XSDDatatype.XSDdecimal) ;
+ protected Node makeNode() {
+ return NodeFactory.createLiteral(XSDFuncOp.canonicalDecimalStr(decimal), XSDDatatype.XSDdecimal) ;
}
-
+
@Override
public String asString() { return toString() ; }
-
+
@Override
public String toString()
{
// Preserve lexical form.
if ( getNode() != null ) return super.asString() ;
- return Utils.stringForm(decimal) ;
+ return XSDFuncOp.canonicalDecimalStr(decimal);
}
-
+
@Override
public void visit(NodeValueVisitor visitor) { visitor.visit(this) ; }
}
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 c3ae8b4..95cc787 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
@@ -158,25 +158,29 @@ public class XSDFuncOp
private static NodeValue decimalDivide(BigDecimal d1, BigDecimal d2) {
try {
BigDecimal d3 = d1.divide(d2, DIVIDE_PRECISION, BigDecimal.ROUND_FLOOR) ;
- return messAroundWithBigDecimalFormat(d3) ;
+ return canonicalDecimalNV(d3) ;
} catch (ArithmeticException ex) {
Log.warn(XSDFuncOp.class, "ArithmeticException in decimal divide - attempting to treat as doubles") ;
BigDecimal d3 = new BigDecimal(d1.doubleValue() / d2.doubleValue()) ;
return NodeValue.makeDecimal(d3) ;
}
}
-
- private static NodeValue messAroundWithBigDecimalFormat(BigDecimal d) {
+
+ public static NodeValue canonicalDecimalNV(BigDecimal d) {
+ String x = canonicalDecimalStr(d);
+ return NodeValue.makeNode(x, XSDDatatype.XSDdecimal) ;
+ }
+
+ public static String canonicalDecimalStr(BigDecimal d) {
String x = d.toPlainString() ;
// The part after the "."
int dotIdx = x.indexOf('.') ;
if ( dotIdx < 0 )
// No DOT.
- return NodeValue.makeNode(x, XSDDatatype.XSDdecimal) ;
+ return x+".0";
// Has a DOT.
-
int i = x.length() - 1 ;
// dotIdx+1 to leave at least ".0"
while ((i > dotIdx + 1) && x.charAt(i) == '0')
@@ -184,12 +188,21 @@ public class XSDFuncOp
if ( i < x.length() - 1 )
// And trailing zeros.
x = x.substring(0, i + 1) ;
-
- // Avoid as expensive.
- // x = x.replaceAll("0+$", "") ;
- return NodeValue.makeNode(x, XSDDatatype.XSDdecimal) ;
+ // Avoid replaceAll as it is expensive.
+ // Leading zeros.
+ int j = 0;
+ for ( ; j < x.length() ; j++ ) {
+ if ( x.charAt(j) != '0')
+ break;
+ }
+ // At least one zero before dot.
+ if ( j == dotIdx )
+ j--;
+ if ( j > 0 )
+ x = x.substring(j, x.length());
+ return x;
}
-
+
public static NodeValue max(NodeValue nv1, NodeValue nv2) {
int x = compareNumeric(nv1, nv2) ;
if ( x == Expr.CMP_LESS )
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/util/Utils.java b/jena-arq/src/main/java/org/apache/jena/sparql/util/Utils.java
index 0c1a9ea..1bc9db7 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/util/Utils.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/util/Utils.java
@@ -20,11 +20,15 @@ package org.apache.jena.sparql.util ;
import java.math.BigDecimal ;
+import org.apache.jena.sparql.expr.nodevalue.XSDFuncOp;
+
/** Miscellaneous operations - not query specific */
public class Utils {
+ /** @deprecated Use {@link XSDFuncOp#canonicalDecimalStr}. */
+ @Deprecated
static public String stringForm(BigDecimal decimal) {
- return decimal.toPlainString() ;
+ return XSDFuncOp.canonicalDecimalStr(decimal);
}
static public String stringForm(double d) {
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java
index bc5985a..16ef87d 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java
@@ -86,9 +86,9 @@ public class TestFunctions2 extends BaseTest
// of the implementation.
@Test public void round_01() { test("round(123)", "123") ; }
- @Test public void round_02() { test("round(123.5)", "'124'^^xsd:decimal") ; }
+ @Test public void round_02() { test("round(123.5)", "'124.0'^^xsd:decimal") ; }
@Test public void round_03() { test("round(-0.5e0)", "0.0e0") ; }
- @Test public void round_04() { test("round(-1.5)", "'-1'^^xsd:decimal") ; }
+ @Test public void round_04() { test("round(-1.5)", "'-1.0'^^xsd:decimal") ; }
@Test public void round_05() { test("round(-0)", "-0") ; }
@Test public void abs_01() { test("abs(1)", "1") ; }
@@ -100,22 +100,22 @@ public class TestFunctions2 extends BaseTest
// CEIL
@Test public void ceil_01() { test("ceil(1)", "1") ; }
- @Test public void ceil_02() { test("ceil(1.0)", "'1'^^xsd:decimal") ; }
+ @Test public void ceil_02() { test("ceil(1.0)", "'1.0'^^xsd:decimal") ; }
@Test public void ceil_03() { test("ceil(1e0)", "1.0e0") ; }
@Test public void ceil_04() { test("ceil(1.5e0)", "2.0e0") ; }
- @Test public void ceil_05() { test("ceil(-0.9)", "'0'^^xsd:decimal") ; }
+ @Test public void ceil_05() { test("ceil(-0.9)", "'0.0'^^xsd:decimal") ; }
@Test public void ceil_06() { test("ceil(-9)", "-9") ; }
- @Test public void ceil_07() { test("ceil(-9.5)", "'-9'^^xsd:decimal") ; }
+ @Test public void ceil_07() { test("ceil(-9.5)", "'-9.0'^^xsd:decimal") ; }
@Test public void ceil_08() { test("ceil(0)", "0") ; }
// FLOOR
@Test public void floor_01() { test("floor(1)", "1") ; }
- @Test public void floor_02() { test("floor(1.0)", "'1'^^xsd:decimal") ; }
+ @Test public void floor_02() { test("floor(1.0)", "'1.0'^^xsd:decimal") ; }
@Test public void floor_03() { test("floor(1e0)", "1.0e0") ; }
@Test public void floor_04() { test("floor(1.5e0)", "1.0e0") ; }
- @Test public void floor_05() { test("floor(-0.9)", "'-1'^^xsd:decimal") ; }
+ @Test public void floor_05() { test("floor(-0.9)", "'-1.0'^^xsd:decimal") ; }
@Test public void floor_06() { test("floor(-9)", "-9") ; }
- @Test public void floor_07() { test("floor(-9.5)", "'-10'^^xsd:decimal") ; }
+ @Test public void floor_07() { test("floor(-9.5)", "'-10.0'^^xsd:decimal") ; }
@Test public void floor_08() { test("floor(0)", "0") ; }
// simple, PLWL, xsd:string.
@@ -441,7 +441,7 @@ public class TestFunctions2 extends BaseTest
@Test public void seconds_20() { test("seconds('2010-12-24T16:24:35.123-08:00'^^xsd:dateTime)", "35.123") ; }
@Test public void seconds_21() { test("seconds('16:24:01.01-08:00'^^xsd:time)", "'01.01'^^xsd:decimal") ; }
- @Test public void seconds_dur_01() { test("seconds('P1Y2M3DT4H5M6S'^^xsd:duration)", "'6'^^xsd:decimal") ; }
+ @Test public void seconds_dur_01() { test("seconds('P1Y2M3DT4H5M6S'^^xsd:duration)", "'6.0'^^xsd:decimal") ; }
// TIMEZONE
@Test public void timezone_01() { test("timezone('2010-12-24T16:24:35.123Z'^^xsd:dateTime)", "'PT0S'^^xsd:dayTimeDuration") ; }
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValueOps.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValueOps.java
index aada461..7247c0d 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValueOps.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValueOps.java
@@ -30,7 +30,7 @@ public class TestNodeValueOps extends BaseTest
// ** Addition
// Numerics
@Test public void nv_add_1() { testAdd("12", "13", "'25'^^xsd:integer" ) ; }
- @Test public void nv_add_2() { testAdd("'12'^^xsd:decimal", "13", "'25'^^xsd:decimal" ) ; }
+ @Test public void nv_add_2() { testAdd("'12'^^xsd:decimal", "13", "'25.0'^^xsd:decimal" ) ; }
@Test public void nv_add_3() { testAdd("'12.0'^^xsd:decimal", "13", "'25.0'^^xsd:decimal" ) ; }
@Test public void nv_add_4() { testAdd("12e0", "13", "25.0e0" ) ; }
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestXSDFuncOp.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestXSDFuncOp.java
index 30b853d..9619730 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestXSDFuncOp.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestXSDFuncOp.java
@@ -18,6 +18,8 @@
package org.apache.jena.sparql.expr;
+import java.math.BigDecimal;
+
import org.apache.jena.atlas.junit.BaseTest ;
import org.apache.jena.datatypes.xsd.XSDDatatype ;
import org.apache.jena.graph.Node ;
@@ -35,6 +37,56 @@ public class TestXSDFuncOp extends BaseTest
private static final double accuracyClose_D = 0.000001d ;
private static final double accuracyClose_F = 0.000001f ;
+
+ @Test public void lex_decimal_1() {
+ lex_decimal(BigDecimal.valueOf(0), "0.0");
+ }
+
+ @Test public void lex_decimal_2() {
+ lex_decimal(BigDecimal.valueOf(1), "1.0");
+ }
+
+ @Test public void lex_decimal_3() {
+ lex_decimal(BigDecimal.valueOf(0.5), "0.5");
+ }
+
+ @Test public void lex_decimal_4() {
+ lex_decimal(BigDecimal.valueOf(-0.5), "-0.5");
+ }
+
+ @Test public void lex_decimal_5() {
+ lex_decimal(BigDecimal.valueOf(1_000_000_000_000_000L), "1000000000000000.0");
+ }
+
+ @Test public void lex_decimal_6() {
+ lex_decimal(BigDecimal.valueOf(-1_000_000_000_000_000L), "-1000000000000000.0");
+ }
+
+ @Test public void lex_decimal_7() {
+ lex_decimal("0.0","0.0");
+ }
+
+ @Test public void lex_decimal_8() {
+ // As input.
+ lex_decimal("0.","0.");
+ }
+
+ @Test public void lex_decimal_9() {
+ // As input.
+ lex_decimal("+.0","+.0");
+ }
+
+ private static void lex_decimal(BigDecimal decimal, String expected) {
+ String lex = XSDFuncOp.canonicalDecimalStr(decimal);
+ assertEquals(expected, lex);
+ }
+
+ private static void lex_decimal(String input, String expected) {
+ NodeValue nv = NodeValue.makeDecimal(input);
+ String lex = nv.asString();
+ assertEquals(expected, lex);
+ }
+
// These add tests also test that the right kind of operation was done.
@Test public void testAddIntegerInteger()