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/05/24 08:44:26 UTC
[jena] branch main updated: JENA-2108: Compare,
collate and sameTerm.
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 57596d7 JENA-2108: Compare, collate and sameTerm.
new 6a5cbe2 Merge pull request #1007 from afs/sparql-star
57596d7 is described below
commit 57596d7aeefadf0c24e1a8502451ceb917e964e4
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Wed May 19 18:06:13 2021 +0100
JENA-2108: Compare, collate and sameTerm.
---
.../org/apache/jena/sparql/expr/NodeValue.java | 66 +++++++++++++++-------
.../jena/sparql/expr/ValueSpaceClassification.java | 12 ++--
.../jena/sparql/expr/nodevalue/NodeFunctions.java | 22 +++++++-
.../apache/jena/sparql/expr/TestExpressions2.java | 14 +++++
.../apache/jena/sparql/expr/TestNodeFunctions.java | 38 +++++++++++++
.../org/apache/jena/sparql/expr/TestNodeValue.java | 44 +++++++++++++--
.../function/library/TestFnFunctionsCollation.java | 6 +-
7 files changed, 167 insertions(+), 35 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 844eed8..11c78c6 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
@@ -41,6 +41,7 @@ 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 ;
+import org.apache.jena.graph.Triple;
import org.apache.jena.graph.impl.LiteralLabel ;
import org.apache.jena.sparql.ARQInternalErrorException ;
import org.apache.jena.sparql.SystemARQ ;
@@ -409,30 +410,26 @@ public abstract class NodeValue extends ExprNode
}
@Override
- public boolean isConstant() { return true ; }
+ public boolean isConstant() { return true ; }
@Override
- public NodeValue getConstant() { return this ; }
+ public NodeValue getConstant() { return this ; }
- public boolean isIRI()
- {
+ public boolean isIRI() {
forceToNode() ;
return node.isURI() ;
}
- public boolean isBlank()
- {
+ public boolean isBlank() {
forceToNode() ;
return node.isBlank() ;
}
- public boolean isTripleTerm()
- {
+ public boolean isTripleTerm() {
forceToNode() ;
- return node.isNodeTriple();
+ return node.isNodeTriple() ;
}
-
// ----------------------------------------------------------------
// ---- sameValueAs
@@ -451,7 +448,7 @@ public abstract class NodeValue extends ExprNode
ValueSpaceClassification compType = classifyValueOp(nv1, nv2) ;
// Special case - date/dateTime comparison is affected by timezones and may be
- // interdeterminate based on the value of the dateTime/date.
+ // indeterminate based on the value of the dateTime/date.
switch (compType)
{
@@ -482,15 +479,15 @@ public abstract class NodeValue extends ExprNode
case VSPACE_STRING: return XSDFuncOp.compareString(nv1, nv2) == Expr.CMP_EQUAL ;
case VSPACE_BOOLEAN: return XSDFuncOp.compareBoolean(nv1, nv2) == Expr.CMP_EQUAL ;
- case VSPACE_LANG:
- {
- // two literals, both with a language tag
- Node node1 = nv1.asNode() ;
- Node node2 = nv2.asNode() ;
- return node1.getLiteralLexicalForm().equals(node2.getLiteralLexicalForm()) &&
- node1.getLiteralLanguage().equalsIgnoreCase(node2.getLiteralLanguage()) ;
+ case VSPACE_TRIPLE_TERM: {
+ Triple t1 = nv1.getNode().getTriple();
+ Triple t2 = nv2.getNode().getTriple();
+ return nSameAs(t1.getSubject(), t2.getSubject())
+ && nSameAs(t1.getPredicate(), t2.getPredicate())
+ && nSameAs(t1.getObject(), t2.getObject());
}
+ case VSPACE_LANG:
case VSPACE_NODE:
// Two non-literals
return NodeFunctions.sameTerm(nv1.getNode(), nv2.getNode()) ;
@@ -539,6 +536,13 @@ public abstract class NodeValue extends ExprNode
throw new ARQInternalErrorException("sameValueAs failure "+nv1+" and "+nv2) ;
}
+ /** Worker for sameAs. */
+ private static boolean nSameAs(Node n1, Node n2) {
+ NodeValue nv1 = NodeValue.makeNode(n1);
+ NodeValue nv2 = NodeValue.makeNode(n2);
+ return sameAs(nv1, nv2);
+ }
+
/** Return true if the two Nodes are known to be different,
* return false if the two Nodes are known to be the same,
* else throw ExprEvalException
@@ -669,6 +673,7 @@ public abstract class NodeValue extends ExprNode
case VSPACE_BOOLEAN :
case VSPACE_DIFFERENT :
case VSPACE_LANG :
+ case VSPACE_TRIPLE_TERM:
case VSPACE_NODE :
case VSPACE_NUM :
case VSPACE_STRING :
@@ -752,6 +757,18 @@ public abstract class NodeValue extends ExprNode
return x ;
}
+ case VSPACE_TRIPLE_TERM: {
+ Triple t1 = nv1.getNode().getTriple();
+ Triple t2 = nv2.getNode().getTriple();
+ int x = nCompare(t1.getSubject(), t2.getSubject(), sortOrderingCompare);
+ if ( x != CMP_EQUAL )
+ return x;
+ x = nCompare(t1.getPredicate(), t2.getPredicate(), sortOrderingCompare);
+ if ( x != CMP_EQUAL )
+ return x;
+ return nCompare(t1.getObject(), t2.getObject(), sortOrderingCompare);
+ }
+
case VSPACE_NODE:
// Two non-literals don't compare except for sorting.
if ( sortOrderingCompare )
@@ -789,6 +806,15 @@ public abstract class NodeValue extends ExprNode
throw new ARQInternalErrorException("Compare failure "+nv1+" and "+nv2) ;
}
+ /** Worker for compare. */
+ private static int nCompare(Node n1, Node n2, boolean sortOrderingCompare) {
+ if ( n1.equals(n2) )
+ return CMP_EQUAL;
+ NodeValue nv1 = NodeValue.makeNode(n1);
+ NodeValue nv2 = NodeValue.makeNode(n2);
+ return compare(nv1, nv2, sortOrderingCompare);
+ }
+
public static ValueSpaceClassification classifyValueOp(NodeValue nv1, NodeValue nv2)
{
ValueSpaceClassification c1 = nv1.getValueSpace() ;
@@ -809,12 +835,13 @@ public abstract class NodeValue extends ExprNode
if ( nv.isDateTime() ) return VSPACE_DATETIME ;
if ( nv.isString()) return VSPACE_STRING ;
if ( nv.isBoolean()) return VSPACE_BOOLEAN ;
+ if ( nv.isTripleTerm()) return VSPACE_TRIPLE_TERM ;
if ( ! nv.isLiteral() ) return VSPACE_NODE ;
if ( ! SystemARQ.ValueExtensions )
return VSPACE_UNKNOWN ;
- // Datatypes and their value spaces that are an extension of strict SPARQL.
+ // Datatypes and their value spaces that are an extension of minimal SPARQL 1.1
if ( nv.isDate() ) return VSPACE_DATE ;
if ( nv.isTime() ) return VSPACE_TIME ;
if ( nv.isDuration() ) return VSPACE_DURATION ;
@@ -827,7 +854,6 @@ public abstract class NodeValue extends ExprNode
if ( nv.isSortKey() ) return VSPACE_SORTKEY ;
- // Already a literal by this point.
if ( NodeUtils.hasLang(nv.asNode()) )
return VSPACE_LANG ;
return VSPACE_UNKNOWN ;
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/ValueSpaceClassification.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/ValueSpaceClassification.java
index 218cdd0..e3c403f 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/ValueSpaceClassification.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/ValueSpaceClassification.java
@@ -20,19 +20,21 @@ package org.apache.jena.sparql.expr;
public enum ValueSpaceClassification {
VSPACE_NODE,
- VSPACE_NUM,
- VSPACE_DATETIME,
+ VSPACE_TRIPLE_TERM,
+
+ VSPACE_NUM,
+ VSPACE_DATETIME,
VSPACE_DATE,
VSPACE_TIME,
VSPACE_DURATION,
-
+
// Collapse to VSPACE_DATETIME?
VSPACE_G_YEAR,
VSPACE_G_YEARMONTH,
VSPACE_G_MONTHDAY,
- VSPACE_G_MONTH,
+ VSPACE_G_MONTH,
VSPACE_G_DAY,
-
+
VSPACE_STRING, VSPACE_LANG, VSPACE_SORTKEY,
VSPACE_BOOLEAN,
VSPACE_UNKNOWN,
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java
index 0eec5e1..2280a5a 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java
@@ -31,6 +31,7 @@ import javax.xml.datatype.Duration;
import org.apache.jena.datatypes.xsd.XSDDatatype ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.NodeFactory ;
+import org.apache.jena.graph.Triple;
import org.apache.jena.irix.IRIException;
import org.apache.jena.irix.IRIs;
import org.apache.jena.irix.IRIx;
@@ -120,6 +121,7 @@ public class NodeFunctions {
return NodeValue.booleanReturn(sameTerm(nv1.asNode(), nv2.asNode())) ;
}
+ /** sameTerm(x,y) */
public static boolean sameTerm(Node node1, Node node2) {
if ( node1.equals(node2) )
return true ;
@@ -130,9 +132,18 @@ public class NodeFunctions {
return false;
return node1.getLiteralLanguage().equalsIgnoreCase(node2.getLiteralLanguage());
}
+ if ( node1.isNodeTriple() && node2.isNodeTriple() ) {
+ return sameTriples(node1.getTriple(), node2.getTriple());
+ }
return false ;
}
+ private static boolean sameTriples(Triple t1, Triple t2) {
+ return sameTerm(t1.getSubject(), t2.getSubject())
+ && sameTerm(t1.getPredicate(), t2.getPredicate())
+ && sameTerm(t1.getObject(), t2.getObject());
+ }
+
// -------- RDFterm-equals -- raises an exception on "don't know" for literals.
// Exact as defined by SPARQL spec, when there are no value extensions.
@@ -162,7 +173,16 @@ public class NodeFunctions {
// Raise error (rather than return false).
NodeValue.raise(new ExprEvalException("Mismatch in RDFterm-equals: " + n1 + ", " + n2)) ;
}
- // One or both not a literal.
+
+ if ( n1.isNodeTriple() && n2.isNodeTriple() ) {
+ Triple t1 = n1.getTriple();
+ Triple t2 = n2.getTriple();
+ return rdfTermEquals(t1.getSubject(), t2.getSubject())
+ && rdfTermEquals(t1.getPredicate(), t2.getPredicate())
+ && rdfTermEquals(t1.getObject(), t2.getObject());
+ }
+
+ // Not both literal nor both tripel terms - .equals would have worked.
return false ;
}
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressions2.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressions2.java
index 84021e5..bd6f0e0 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressions2.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestExpressions2.java
@@ -113,6 +113,20 @@ public class TestExpressions2
@Test (expected=ExprEvalException.class)
public void term_constructor_strlang_03() { eval("STRLANG('abc'@en, 'en') = 'abc'@en") ; }
+ // RDF-star
+ @Test public void triple_term_cmp_01()
+ { eval("<<<ex:s> <ex:p> <ex:p>>> = <<<ex:s> <ex:p> <ex:p>>>"); }
+
+ @Test public void triple_term_cmp_02()
+ { eval("<<<ex:s> <ex:p> <ex:o1>>> != <<<ex:s> <ex:p> <ex:o2>>>"); }
+
+ @Test public void triple_term_cmp_03()
+ { eval("<<<ex:s> <ex:p> 1>> < <<<ex:s> <ex:p> 2>>"); }
+
+ @Test (expected=ExprEvalException.class)
+ public void triple_term_cmp_04()
+ { eval("<<<ex:s> <ex:p1> 2>> < <<<ex:s> <ex:p2> 2>>"); }
+
// XSD casts
@Test public void xsd_cast_01() { eval("xsd:integer('1') = 1", true) ; }
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java
index dcd00db..683bcde 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java
@@ -28,6 +28,7 @@ import org.apache.jena.graph.Node ;
import org.apache.jena.graph.NodeFactory ;
import org.apache.jena.sparql.expr.nodevalue.NodeFunctions ;
import org.apache.jena.sparql.graph.NodeConst ;
+import org.apache.jena.sparql.sse.SSE;
import org.apache.jena.vocabulary.RDF ;
import org.apache.jena.vocabulary.XSD ;
import org.junit.Test ;
@@ -100,9 +101,46 @@ public class TestNodeFunctions {
// Unextended - not known to be same.
Node n1 = NodeFactory.createLiteral("123", XSDDatatype.XSDinteger) ;
Node n2 = NodeFactory.createLiteral("456", XSDDatatype.XSDinteger) ;
+ assertTrue(NodeFunctions.rdfTermEquals(n1, n2));
+ }
+
+ @Test
+ public void testRDFtermEquals5() {
+ Node n1 = SSE.parseNode("<<:s :p 123>>");
+ Node n2 = SSE.parseNode("<<:s :p 123>>");
+ assertTrue(NodeFunctions.rdfTermEquals(n1, n2));
+ }
+
+ @Test
+ public void testRDFtermEquals6() {
+ Node n1 = SSE.parseNode("<<:s :p1 123>>");
+ Node n2 = SSE.parseNode("<<:s :p2 123>>");
+ assertFalse(NodeFunctions.rdfTermEquals(n1, n2));
+ }
+
+ @Test(expected=ExprEvalException.class)
+ public void testRDFtermEquals7() {
+ Node n1 = SSE.parseNode("<<:s :p <<:a :b 'abc'>>>>");
+ Node n2 = SSE.parseNode("<<:s :p <<:a :b 123>>>>");
NodeFunctions.rdfTermEquals(n1, n2);
}
+ @Test(expected=ExprEvalException.class)
+ public void testRDFtermEquals8() {
+ Node n1 = SSE.parseNode("<<:s :p 123>>");
+ Node n2 = SSE.parseNode("<<:s :p 'xyz'>>");
+ assertFalse(NodeFunctions.rdfTermEquals(n1, n2));
+ assertFalse(NodeFunctions.rdfTermEquals(n2, n1));
+ }
+
+ @Test
+ public void testRDFtermEquals9() {
+ Node n1 = SSE.parseNode("<<:s :p 123>>");
+ Node n2 = SSE.parseNode("'xyz'");
+ assertFalse(NodeFunctions.rdfTermEquals(n1, n2));
+ assertFalse(NodeFunctions.rdfTermEquals(n2, n1));
+ }
+
@Test public void testStr1() {
NodeValue nv = NodeValue.makeNodeInteger(56) ;
NodeValue s = NodeFunctions.str(nv) ;
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 cba7db6..edb0e87 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
@@ -820,7 +820,7 @@ public class TestNodeValue
final String[] unordered =
{"Broager", "Åkirkeby", "Børkop", "Ærøskøbing", "Brædstrup", "Wandsbek"};
final String[] ordered =
- {"'Broager'", "'Brædstrup'", "'Børkop'", "'Wandsbek'", "'Ærøskøbing'", "'Åkirkeby'"};
+ {"Broager", "Brædstrup", "Børkop", "Wandsbek", "Ærøskøbing", "Åkirkeby"};
// tests collation sort order for Danish
final String collation = "da";
List<NodeValue> nodeValues = new LinkedList<>();
@@ -835,7 +835,7 @@ public class TestNodeValue
});
List<String> result = new LinkedList<>();
for (NodeValue nv : nodeValues) {
- String s = nv.toString();
+ String s = nv.getNode().getLiteralLexicalForm();
result.add(s);
}
assertArrayEquals(ordered, result.toArray(new String[0]));
@@ -846,7 +846,7 @@ public class TestNodeValue
final String[] unordered = new String[]
{"Broager", "Åkirkeby", "Børkop", "Ærøskøbing", "Brædstrup", "Wandsbek"};
final String[] ordered = new String[]
- {"'Ærøskøbing'", "'Åkirkeby'", "'Brædstrup'", "'Broager'", "'Børkop'", "'Wandsbek'"};
+ {"Ærøskøbing", "Åkirkeby", "Brædstrup", "Broager", "Børkop", "Wandsbek"};
// tests collation sort order with Danish words, but New Zealand English collation rules
final String collation = "en-NZ";
List<NodeValue> nodeValues = new LinkedList<>();
@@ -861,7 +861,7 @@ public class TestNodeValue
});
List<String> result = new LinkedList<>();
for (NodeValue nv : nodeValues) {
- String s = nv.toString();
+ String s = nv.getNode().getLiteralLexicalForm();
result.add(s);
}
assertArrayEquals(ordered, result.toArray(new String[0]));
@@ -1068,8 +1068,8 @@ public class TestNodeValue
@Test
public void testEquals4() {
- NodeValue nv1 = NodeValue.makeNode(org.apache.jena.graph.NodeFactory.createURI("http://example"));
- NodeValue nv2 = NodeValue.makeNode(org.apache.jena.graph.NodeFactory.createURI("http://example"));
+ NodeValue nv1 = NodeValue.makeNode(NodeFactory.createURI("http://example"));
+ NodeValue nv2 = NodeValue.makeNode(NodeFactory.createURI("http://example"));
assertEquals("Not NodeValue.equals()", nv1, nv2);
}
@@ -1093,4 +1093,36 @@ public class TestNodeValue
NodeValue nv2 = NodeValue.makeNode(org.apache.jena.graph.NodeFactory.createLiteral("http://example"));
assertFalse("NodeValue.equals()", nv1.equals(nv2));
}
+
+ @Test
+ public void testTripleTerms1() {
+ Node n1 = SSE.parseNode("<<:s :p 123>>");
+ Node n2 = SSE.parseNode("<<:s :p 456>>");
+ NodeValue nv1 = NodeValue.makeNode(n1);
+ NodeValue nv2 = NodeValue.makeNode(n2);
+ int xa = NodeValue.compare(nv1, nv2);
+ assertEquals(Expr.CMP_LESS, xa);
+ int xb = NodeValue.compare(nv2, nv1);
+ assertEquals(Expr.CMP_GREATER, xb);
+ }
+
+ @Test(expected=ExprNotComparableException.class)
+ public void testTripleTerms2() {
+ Node n1 = SSE.parseNode("<<:s :p 123>>");
+ Node n2 = SSE.parseNode("<<:s :p 'abc'>>");
+ NodeValue nv1 = NodeValue.makeNode(n1);
+ NodeValue nv2 = NodeValue.makeNode(n2);
+ NodeValue.compare(nv1, nv2);
+ }
+
+ @Test
+ public void testTripleTerms3() {
+ Node n1 = SSE.parseNode("<<:s :p 123>>");
+ Node n2 = SSE.parseNode("<<:s :p 'abc'>>");
+ NodeValue nv1 = NodeValue.makeNode(n1);
+ NodeValue nv2 = NodeValue.makeNode(n2);
+ int x = NodeValue.compareAlways(nv1, nv2);
+ assertEquals(Expr.CMP_LESS, x);
+ }
+
}
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFnFunctionsCollation.java b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFnFunctionsCollation.java
index 4b6a2c0..b80e2fa 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFnFunctionsCollation.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFnFunctionsCollation.java
@@ -39,8 +39,8 @@ public class TestFnFunctionsCollation {
final String[] unordered = {"tšekin kieli" , "tulun kieli", "töyhtöhyyppä",
"tsahurin kieli", "tsahurin kieli", "tulun kieli"};
- String[] ordered = {"'tsahurin kieli'", "'tsahurin kieli'", "'tšekin kieli'",
- "'tulun kieli'", "'tulun kieli'", "'töyhtöhyyppä'"};
+ String[] ordered = {"tsahurin kieli", "tsahurin kieli", "tšekin kieli",
+ "tulun kieli", "tulun kieli", "töyhtöhyyppä"};
// tests collation sort order with Danish words, but New Zealand English
// collation rules
List<NodeValue> nodeValues = new LinkedList<>();
@@ -50,7 +50,7 @@ public class TestFnFunctionsCollation {
nodeValues.sort((NodeValue o1, NodeValue o2) -> NodeValue.compare(o1, o2));
List<String> result = new LinkedList<>();
for ( NodeValue nv : nodeValues ) {
- String s = nv.toString();
+ String s = nv.getNode().getLiteralLexicalForm();
result.add(s);
}
assertArrayEquals(ordered, result.toArray(new String[0]));