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 2021/11/10 22:29:19 UTC
[jena] branch main updated: JENA-2197: Whitespace facet on XSD
literals
This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 165fac4 JENA-2197: Whitespace facet on XSD literals
new 3fa5214 Merge pull request #1107 from afs/ws-facet
165fac4 is described below
commit 165fac4a6ed0d1ad1d8332a70e8c026f9e4dd295
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Mon Nov 8 20:48:16 2021 +0000
JENA-2197: Whitespace facet on XSD literals
---
.../org/apache/jena/sparql/expr/NodeValue.java | 85 ++++++++++------------
.../sparql/expr/nodevalue/NodeValueDateTime.java | 16 ++--
.../org/apache/jena/sparql/expr/TestNodeValue.java | 63 +++++++++++++++-
3 files changed, 111 insertions(+), 53 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 32e928c..41ecb54 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
@@ -38,7 +38,6 @@ import org.apache.jena.datatypes.DatatypeFormatException ;
import org.apache.jena.datatypes.RDFDatatype ;
import org.apache.jena.datatypes.TypeMapper ;
import org.apache.jena.datatypes.xsd.XSDDatatype;
-import org.apache.jena.datatypes.xsd.XSDDateTime ;
import org.apache.jena.ext.xerces.DatatypeFactoryInst;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.NodeFactory ;
@@ -210,30 +209,26 @@ public abstract class NodeValue extends ExprNode
public static NodeValue makeDate(String lexicalForm)
{ return NodeValue.makeNode(lexicalForm, XSDdate) ; }
- public static NodeValue makeDateTime(Calendar cal)
- {
- String lex = DateTimeUtils.calendarToXSDDateTimeString(cal) ;
- return NodeValue.makeNode(lex, XSDdateTime) ;
+ public static NodeValue makeDateTime(Calendar cal) {
+ String lex = DateTimeUtils.calendarToXSDDateTimeString(cal);
+ return NodeValue.makeNode(lex, XSDdateTime);
}
- public static NodeValue makeDateTime(XMLGregorianCalendar cal)
- {
- String lex = cal.toXMLFormat() ;
- Node node = org.apache.jena.graph.NodeFactory.createLiteral(lex, XSDdateTime) ;
- return new NodeValueDateTime(lex, node) ;
+ public static NodeValue makeDateTime(XMLGregorianCalendar cal) {
+ String lex = cal.toXMLFormat();
+ Node node = NodeFactory.createLiteral(lex, XSDdateTime);
+ return NodeValueDateTime.create(lex, node);
}
- public static NodeValue makeDate(Calendar cal)
- {
- String lex = DateTimeUtils.calendarToXSDDateString(cal) ;
- return NodeValue.makeNode(lex, XSDdate) ;
+ public static NodeValue makeDate(Calendar cal) {
+ String lex = DateTimeUtils.calendarToXSDDateString(cal);
+ return NodeValue.makeNode(lex, XSDdate);
}
- public static NodeValue makeDate(XMLGregorianCalendar cal)
- {
- String lex = cal.toXMLFormat() ;
- Node node = org.apache.jena.graph.NodeFactory.createLiteral(lex, XSDdate) ;
- return new NodeValueDateTime(lex, node) ;
+ public static NodeValue makeDate(XMLGregorianCalendar cal) {
+ String lex = cal.toXMLFormat();
+ Node node = NodeFactory.createLiteral(lex, XSDdate);
+ return NodeValueDateTime.create(lex, node);
}
public static NodeValue makeDuration(String lexicalForm)
@@ -1037,13 +1032,16 @@ public abstract class NodeValue extends ExprNode
// Order here is promotion order integer-decimal-float-double
- if ( ! datatype.equals(XSDdecimal) ) {
+ // XSD allows whitespace. Java String.trim removes too much
+ // so must test for validity on the untrimmed lexical form.
+ String lexTrimmed = lex.trim();
+
+ if ( ! datatype.equals(XSDdecimal) ) { // ! decimal is short for integers and all derived types.
// XSD integer and derived types
if ( XSDinteger.isValidLiteral(lit) )
{
- // .trim() implements the facet of whitespace collapse.
// BigInteger does not accept such whitespace.
- String s = node.getLiteralLexicalForm().trim() ;
+ String s = lexTrimmed;
if ( s.startsWith("+") )
// BigInteger does not accept leading "+"
s = s.substring(1) ;
@@ -1055,7 +1053,7 @@ public abstract class NodeValue extends ExprNode
}
if ( datatype.equals(XSDdecimal) && XSDdecimal.isValidLiteral(lit) ) {
- BigDecimal decimal = new BigDecimal(lit.getLexicalForm()) ;
+ BigDecimal decimal = new BigDecimal(lexTrimmed) ;
return new NodeValueDecimal(decimal, node) ;
}
@@ -1071,59 +1069,56 @@ public abstract class NodeValue extends ExprNode
return new NodeValueDouble(d, node) ;
}
+ if ( datatype.equals(XSDboolean) && XSDboolean.isValidLiteral(lit) ) {
+ boolean b = (Boolean) lit.getValue();
+ return new NodeValueBoolean(b, node) ;
+ }
+
if ( (datatype.equals(XSDdateTime) || datatype.equals(XSDdateTimeStamp)) && XSDdateTime.isValid(lex) ) {
- return new NodeValueDateTime(lex, node) ;
+ return NodeValueDateTime.create(lexTrimmed, node) ;
}
if ( datatype.equals(XSDdate) && XSDdate.isValidLiteral(lit) ) {
- // Jena datatype support works on masked dataTimes.
- //XSDDateTime dateTime = (XSDDateTime)lit.getValue() ;
- return new NodeValueDateTime(lex, node) ;
+ return NodeValueDateTime.create(lexTrimmed, node) ;
}
if ( datatype.equals(XSDtime) && XSDtime.isValidLiteral(lit) ) {
- return new NodeValueDateTime(lex, node) ;
+ return NodeValueDateTime.create(lexTrimmed, node) ;
}
if ( datatype.equals(XSDgYear) && XSDgYear.isValidLiteral(lit) ) {
- return new NodeValueDateTime(lex, node) ;
+ return NodeValueDateTime.create(lexTrimmed, node) ;
}
if ( datatype.equals(XSDgYearMonth) && XSDgYearMonth.isValidLiteral(lit) ) {
- return new NodeValueDateTime(lex, node) ;
+ return NodeValueDateTime.create(lexTrimmed, node) ;
}
if ( datatype.equals(XSDgMonth) && XSDgMonth.isValidLiteral(lit) ) {
- XSDDateTime time = (XSDDateTime)lit.getValue() ;
- return new NodeValueDateTime(lex, node) ;
+ return NodeValueDateTime.create(lexTrimmed, node) ;
}
if ( datatype.equals(XSDgMonthDay) && XSDgMonthDay.isValidLiteral(lit) ) {
- XSDDateTime time = (XSDDateTime)lit.getValue() ;
- return new NodeValueDateTime(lex, node) ;
+ return NodeValueDateTime.create(lexTrimmed, node) ;
}
if ( datatype.equals(XSDgDay) && XSDgDay.isValidLiteral(lit) ) {
- XSDDateTime time = (XSDDateTime)lit.getValue() ;
- return new NodeValueDateTime(lex, node) ;
+ return NodeValueDateTime.create(lexTrimmed, node) ;
}
+ // -- Duration
+
if ( datatype.equals(XSDduration) && XSDduration.isValid(lex) ) {
- Duration duration = xmlDatatypeFactory.newDuration(lex) ;
+ Duration duration = xmlDatatypeFactory.newDuration(lexTrimmed) ;
return new NodeValueDuration(duration, node) ;
}
if ( datatype.equals(XSDyearMonthDuration) && XSDyearMonthDuration.isValid(lex) ) {
- Duration duration = xmlDatatypeFactory.newDuration(lex) ;
+ Duration duration = xmlDatatypeFactory.newDuration(lexTrimmed) ;
return new NodeValueDuration(duration, node) ;
}
if ( datatype.equals(XSDdayTimeDuration) && XSDdayTimeDuration.isValid(lex) ) {
- Duration duration = xmlDatatypeFactory.newDuration(lex) ;
+ Duration duration = xmlDatatypeFactory.newDuration(lexTrimmed) ;
return new NodeValueDuration(duration, node) ;
}
- if ( datatype.equals(XSDboolean) && XSDboolean.isValidLiteral(lit) ) {
- boolean b = (Boolean) lit.getValue();
- return new NodeValueBoolean(b, node) ;
- }
-
// If wired into the TypeMapper via RomanNumeralDatatype.enableAsFirstClassDatatype
// if ( RomanNumeralDatatype.get().isValidLiteral(lit) )
// {
@@ -1136,7 +1131,7 @@ public abstract class NodeValue extends ExprNode
{
if ( lit.getDatatypeURI().equals(RomanNumeralDatatype.get().getURI()) )
{
- Object obj = RomanNumeralDatatype.get().parse(lit.getLexicalForm()) ;
+ Object obj = RomanNumeralDatatype.get().parse(lexTrimmed) ;
if ( obj instanceof Integer )
return new NodeValueInteger(((Integer)obj).longValue()) ;
if ( obj instanceof RomanNumeral )
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDateTime.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDateTime.java
index 1efdf91..80d06bc 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDateTime.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueDateTime.java
@@ -30,21 +30,27 @@ public class NodeValueDateTime extends NodeValue
{
final private XMLGregorianCalendar datetime ;
- public NodeValueDateTime(String lex, Node n)
- {
- super(n) ;
+ /** Lex - caller removes leading and trailing whitespace. */
+ public static NodeValueDateTime create(String lex, Node n) {
+ XMLGregorianCalendar datetime;
// Java bug : Java6, Java8: gMonth with a timezone of Z causes IllegalArgumentException
- if ( XSDgMonth.equals(getNode().getLiteralDatatype()) )
+ if ( XSDgMonth.equals(n.getLiteralDatatype()) )
{
if ( lex.endsWith("Z") )
{
lex = lex.substring(0, lex.length()-1) ;
datetime = NodeValue.xmlDatatypeFactory.newXMLGregorianCalendar(lex) ;
datetime.setTimezone(0) ;
- return ;
+ return new NodeValueDateTime(datetime, n);
}
}
datetime = NodeValue.xmlDatatypeFactory.newXMLGregorianCalendar(lex) ;
+ return new NodeValueDateTime(datetime, n);
+ }
+
+ public NodeValueDateTime(XMLGregorianCalendar datetime, Node n) {
+ super(n);
+ this.datetime = datetime;
}
// Look at datatype.
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValue.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValue.java
index edb0e87..3c1e300 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValue.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValue.java
@@ -386,7 +386,7 @@ public class TestNodeValue
@Test
public void testNodeFloat1() {
- // Theer is no SPARQL representation in short form of a float.
+ // There is no SPARQL representation in short form of a float.
NodeValue v = NodeValue.makeNode("57.0", XSDDatatype.XSDfloat);
assertTrue("Not a number: " + v, v.isNumber());
assertTrue("Not a float: " + v, v.isFloat());
@@ -398,8 +398,22 @@ public class TestNodeValue
}
@Test
+ public void testNodeFloat2() {
+ // WhiteSpace facet
+ NodeValue v = NodeValue.makeNode(" 57.0 ", XSDDatatype.XSDfloat);
+ assertTrue("Not a number: " + v, v.isNumber());
+ assertTrue("Not a float: " + v, v.isFloat());
+ assertTrue("Not a double(float): " + v, v.isDouble());
+ assertTrue("Not a node: " + v, v.hasNode());
+ String actualStr = v.asQuotedString();
+
+ assertEquals("Print form mismatch", "\" 57.0 \"^^<" + XSDDatatype.XSDfloat.getURI() + ">", actualStr);
+ }
+
+
+ @Test
public void testNodeDouble1() {
- // Note input form is legal and canomical as a lexical form double
+ // Note input form is legal and canonical as a lexical form double
NodeValue v = NodeValue.makeNode("57.0e0", XSDDatatype.XSDdouble);
assertTrue("Not a number: " + v, v.isNumber());
assertTrue("Not a double: " + v, v.isDouble());
@@ -444,7 +458,6 @@ public class TestNodeValue
assertTrue("Not a node: " + v, v.hasNode());
}
-
@Test
public void testNodeBool1() {
NodeValue v = NodeValue.makeNode("true", XSDDatatype.XSDboolean);
@@ -479,6 +492,50 @@ public class TestNodeValue
assertFalse("Not false: " + v, XSDFuncOp.booleanEffectiveValue(v));
}
+ @Test
+ public void testNodeDateTime1() {
+ NodeValue v = NodeValue.makeNode("2021-11-08T20:37:25+01:00", XSDDatatype.XSDdateTime);
+ assertTrue("Not a dateTime: " + v, v.isDateTime());
+ }
+
+ @Test
+ public void testNodeDateTime2() {
+ NodeValue v = NodeValue.makeNode("\t2021-11-08T20:37:26+01:00\t", XSDDatatype.XSDdateTime);
+ assertTrue("Not a dateTime: " + v, v.isDateTime());
+ }
+
+ @Test
+ public void testNodeGYear1() {
+ NodeValue v = NodeValue.makeNode("2021", XSDDatatype.XSDgYear);
+ assertTrue("Not a gYear: " + v, v.isGYear());
+ }
+
+ @Test
+ public void testNodeGYear2() {
+ NodeValue v = NodeValue.makeNode("\t2021\t", XSDDatatype.XSDgYear);
+ assertTrue("Not a gYear: " + v, v.isGYear());
+ }
+
+ @Test
+ public void testNodeDuration1() {
+ NodeValue v = NodeValue.makeNode("P1Y", XSDDatatype.XSDyearMonthDuration);
+ assertTrue("Not a yearMonthDuration: " + v, v.isYearMonthDuration());
+ assertTrue("Not a duration: " + v, v.isDuration());
+ }
+
+ @Test
+ public void testNodeDuration2() {
+ NodeValue v = NodeValue.makeNode("P1Y ", XSDDatatype.XSDduration);
+ assertTrue("Not a yearMonthDuration: " + v, v.isDuration());
+ }
+
+ @Test
+ public void testNodeDuration3() {
+ // Internal whiespace -> invalide.
+ NodeValue v = NodeValue.makeNode("P1Y 10S", XSDDatatype.XSDduration);
+ assertFalse("Is a valid duration: " + v, v.isDuration());
+ }
+
static NodeValue make(String str) {
Node n = NodeFactoryExtra.parseNode(str);
NodeValue nv = NodeValue.makeNode(n);