diff --git a/jena-arq/Grammar/arq.jj b/jena-arq/Grammar/arq.jj index 988beb3f17a..1062221641e 100644 --- a/jena-arq/Grammar/arq.jj +++ b/jena-arq/Grammar/arq.jj @@ -2480,6 +2480,7 @@ TOKEN: ["\u200C"-"\u200D"] | ["\u2070"-"\u218F"] | ["\u2C00"-"\u2FEF"] | ["\u3001"-"\uD7FF"] | ["\uF900"-"\uFFFD"] // [#x10000-#xEFFFF] + // \-U not legal here so as an extension allow surrogate pairs. // Put in surrogate pairs because by the time javacc sees codepoints, // they are in UTF-16. | diff --git a/jena-arq/Grammar/jj2bnf b/jena-arq/Grammar/jj2bnf index 891d472848f..f122cb74bde 100755 --- a/jena-arq/Grammar/jj2bnf +++ b/jena-arq/Grammar/jj2bnf @@ -30,6 +30,8 @@ if ( $#ARGV != 1 ) exit 1 ; } +$WithNumbers = 1 ; + $/ = undef ; # Just table or full page. @@ -122,9 +124,6 @@ for $t (@t) { $tokenbody =~ s/"/'/g ; # '" -- But not literal " -- how? $tokenbody =~ s/\<\>\'\{\}/\<\>\"\{\}/ ; # '" IRI fixup - ## IRIREF - special case of inline but with nested terminal name. - $tokenbody =~ s//UCHAR/ ; # - $inline{$tokenname} = $tokenbody ; #print "INLINE: ",$tokenname," => ",$tokenbody,"\n" ; } else { @@ -159,11 +158,11 @@ for $r (@rules) { # Inlines for $k (keys %inline) { -## $s = esc($inline{$k}) ; -## $k = esc($k) ; -## # Assumes escaped <> round tokens. -## $k = quotemeta $k ; -## $ruleBodyStr =~ s/$k/$s/g ; + ## $s = esc($inline{$k}) ; + ## $k = esc($k) ; + ## # Assumes escaped <> round tokens. + ## $k = quotemeta $k ; + ## $ruleBodyStr =~ s/$k/$s/g ; $s = $inline{$k}; $ruleBodyStr =~ s/$k/$s/g ; @@ -196,12 +195,14 @@ for $r (@rules) { ## Third part of the output. $ruleBodyStr = fixupRule($rulename, $ruleBodyStr) ; - ##Why no NL needed? - ## printf "%-5s %-25s ::= %s\n", $rlabel, $rn, $ruleBodyStr ; - printf "%-25s ::= %s\n", $rn, $ruleBodyStr ; - - # $rule{$rulename, $rulebody) ; - # print $rulename , "\n" ; + if ( $WithNumbers ) { + ## 5 spaces for the line number text, 2 gap = 7 + $ruleNumStr = sprintf("%-5s", '[' . $ruleNum . ']'); + printf "%s %-25s ::= %s\n", $ruleNumStr, $rn, $ruleBodyStr ; + } else { + ## No number label + printf "%-25s ::= %s\n", $rn, $ruleBodyStr ; + } } sub readFile { @@ -237,7 +238,7 @@ sub fixupRule { $body =~ s/^\(\s+([^\(]*)\s+\)$/$1/ ; # There aren't any of these -## $body =~ s!\(\s+(\S*)\s+\)!$1!g ; + ## $body =~ s!\(\s+(\S*)\s+\)!$1!g ; # Remove <> around tokens. $body =~ s/<(\w+)>/$1/g ; @@ -252,12 +253,12 @@ sub fixupRule { $head eq "Aggregate" ) { ## Except BNODE, STRLEN etc -## [138] RegexExpression ::= 'REGEX' '(' Expression ',' Expression ( ',' Expression )? ')' -## [139] SubstringExpression ::= 'SUBSTR' '(' Expression ',' Expression ( ',' Expression )? ')' -## [140] StrReplaceExpression ::= 'REPLACE' '(' Expression ',' Expression ',' Expression ( ',' Expression )? ')' -## [141] ExistsFunc ::= 'EXISTS' GroupGraphPattern -## [142] NotExistsFunc ::= 'NOT' 'EXISTS' GroupGraphPattern -## | 'BNODE' ( '(' Expression ')' | ) + ## [138] RegexExpression ::= 'REGEX' '(' Expression ',' Expression ( ',' Expression )? ')' + ## [139] SubstringExpression ::= 'SUBSTR' '(' Expression ',' Expression ( ',' Expression )? ')' + ## [140] StrReplaceExpression ::= 'REPLACE' '(' Expression ',' Expression ',' Expression ( ',' Expression )? ')' + ## [141] ExistsFunc ::= 'EXISTS' GroupGraphPattern + ## [142] NotExistsFunc ::= 'NOT' 'EXISTS' GroupGraphPattern + ## | 'BNODE' ( '(' Expression ')' | ) print STDERR "A:",$body,"\n" if $p ; @@ -266,8 +267,15 @@ sub fixupRule { ## Alternative more general removal: NB space-) - matched the BNF parens ##$body =~ s%'BNODE'.*? \)%XXX-BNODE-XXX%; - - $body =~ s%\|\s*%\n | %g ; + + if ( $WithNumbers ) { + ## Align spaces with the number label + ## With number label + $body =~ s%\|\s*%\n | %g ; + } else { + ## No number label + $body =~ s%\|\s*%\n | %g ; + } ## Replace marker $body =~ s%XXX-BNODE-XXX%'BNODE' \( '(' Expression ')' \| NIL \)%; @@ -289,9 +297,9 @@ sub fixupRule { } ## Split? -## if ( $head eq "Query" ) -## { -## } + ## if ( $head eq "Query" ) + ## { + ## } #Rules where an outer () is unnecessary. if ( $head eq "GroupCondition" || diff --git a/jena-arq/Grammar/main.jj b/jena-arq/Grammar/main.jj index 2be4b93b036..c8e75a01dc9 100644 --- a/jena-arq/Grammar/main.jj +++ b/jena-arq/Grammar/main.jj @@ -3066,6 +3066,7 @@ TOKEN: ["\u3001"-"\uD7FF"] | ["\uF900"-"\uFFFD"] // [#x10000-#xEFFFF] #ifdef ARQ + // \-U not legal here so as an extension allow surrogate pairs. // Put in surrogate pairs because by the time javacc sees codepoints, // they are in UTF-16. | diff --git a/jena-arq/src/main/java/org/apache/jena/riot/web/HttpNames.java b/jena-arq/src/main/java/org/apache/jena/riot/web/HttpNames.java index 0de6308a37f..3d171521af0 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/web/HttpNames.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/web/HttpNames.java @@ -63,9 +63,9 @@ public class HttpNames // XXX Rename as mtCharset? public static final String charset = "charset" ; // RDF .1.2+ SPARQL 1.2+ HTTP header parameters - public static final String mtParamVersion = "version" ; + public static final String mtParamVersion = "version" ; // RFC 6906 -- https://www.rfc-editor.org/rfc/rfc6906 - public static final String mtParamProfile = "profile" ; + public static final String mtParamProfile = "profile" ; // GSP parameter names public static final String paramGraph = "graph" ; @@ -99,7 +99,7 @@ public class HttpNames public static final String paramForceAccept = "force-accept" ; // Force the accept header at the last moment public static final String paramTimeout = "timeout" ; - // Replace by enum HttpMethods + // Replace by enum HttpMethod public static final String METHOD_DELETE = "DELETE"; public static final String METHOD_HEAD = "HEAD"; public static final String METHOD_GET = "GET"; diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/Substitute.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/Substitute.java index e0710381022..e2f3a11d99f 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/Substitute.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/Substitute.java @@ -118,10 +118,9 @@ public static Triple substitute(Triple triple, Binding binding) { Node p1 = substitute(p, binding); Node o1 = substitute(o, binding); - Triple t = triple; - if ( s1 != s || p1 != p || o1 != o ) - t = Triple.create(s1, p1, o1); - return t; + if ( s1 == s && p1 == p && o1 == o ) + return triple; + return Triple.create(s1, p1, o1); } public static TriplePath substitute(TriplePath triplePath, Binding binding) { @@ -136,10 +135,9 @@ public static TriplePath substitute(TriplePath triplePath, Binding binding) { Node s1 = substitute(s, binding); Node o1 = substitute(o, binding); - TriplePath tp = triplePath; - if ( s1 != s || o1 != o ) - tp = new TriplePath(s1, triplePath.getPath(), o1); - return tp; + if ( s1 == s && o1 == o ) + return triplePath; + return new TriplePath(s1, triplePath.getPath(), o1); } public static Quad substitute(Quad quad, Binding binding) { @@ -158,10 +156,9 @@ public static Quad substitute(Quad quad, Binding binding) { Node p1 = substitute(p, binding); Node o1 = substitute(o, binding); - Quad q = quad; - if ( s1 != s || p1 != p || o1 != o || g1 != g ) - q = Quad.create(g1, s1, p1, o1); - return q; + if ( s1 == s && p1 == p && o1 == o && g1 == g ) + return quad; + return Quad.create(g1, s1, p1, o1); } public static Node substitute(Node n, Binding binding) { @@ -187,9 +184,10 @@ public static Node substitute(Node n, Binding binding) { // No change - return original if ( s1 == s && o1 == o && p1 == p ) return n; + // Change happened. Create new. + Node n2 = NodeFactory.createTripleTerm(s1, p1, o1); + return n2; - // Change. Create new. - return NodeFactory.createTripleTerm(s1, p1, o1); } /** Substitute for a node that makes up a triple in a Node_Triple. Recursively. */ @@ -198,7 +196,6 @@ private static Node subTripleTermNode(Node n, Binding binding) { if ( ! n.isConcrete() ) n = substitute(n, binding); } else if ( Var.isVar(n) ) { - Var var = Var.alloc(n); n = Var.lookup(binding::get, n); } return n; diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/modify/TemplateLib.java b/jena-arq/src/main/java/org/apache/jena/sparql/modify/TemplateLib.java index 262f39b2e05..828034c6007 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/modify/TemplateLib.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/modify/TemplateLib.java @@ -124,62 +124,55 @@ public static Quad subst(Quad quad, Binding b, Map bNodeMap) { Node p = quad.getPredicate(); Node o = quad.getObject(); - Node g1 = g; - Node s1 = s; - Node p1 = p; - Node o1 = o; - - // replace blank nodes. - if ( g1.isBlank() || Var.isBlankNodeVar(g1) ) - g1 = newBlank(g1, bNodeMap); - - if ( s1.isBlank() || Var.isBlankNodeVar(s1) ) - s1 = newBlank(s1, bNodeMap); - - if ( p1.isBlank() || Var.isBlankNodeVar(p1) ) - p1 = newBlank(p1, bNodeMap); - - if ( o1.isBlank() || Var.isBlankNodeVar(o1) ) - o1 = newBlank(o1, bNodeMap); - - Quad q = quad; - if ( s1 != s || p1 != p || o1 != o || g1 != g ) - q = Quad.create(g1, s1, p1, o1); - Quad q2 = Substitute.substitute(q, b); - return q2; + Node g1 = subst(g, b, bNodeMap, false); + Node s1 = subst(s, b, bNodeMap, true); + Node p1 = subst(p, b, bNodeMap, false); + Node o1 = subst(o, b, bNodeMap, true); + + if ( s1 == s && p1 == p && o1 == o && g1 == g ) + return quad; + return Quad.create(g1, s1, p1, o1); } /** Substitute into a triple, with rewriting of bNodes */ public static Triple subst(Triple triple, Binding b, Map bNodeMap) { + // Transfer to quads. Node s = triple.getSubject(); Node p = triple.getPredicate(); Node o = triple.getObject(); - Node s1 = s; - Node p1 = p; - Node o1 = o; + Node s1 = subst(s, b, bNodeMap, true); + Node p1 = subst(p, b, bNodeMap, false); + Node o1 = subst(o, b, bNodeMap, true); - if ( s1.isBlank() || Var.isBlankNodeVar(s1) ) - s1 = newBlank(s1, bNodeMap); - - if ( p1.isBlank() || Var.isBlankNodeVar(p1) ) - p1 = newBlank(p1, bNodeMap); - - if ( o1.isBlank() || Var.isBlankNodeVar(o1) ) - o1 = newBlank(o1, bNodeMap); + if ( s1 == s && p1 == p && o1 == o ) + return triple; + return Triple.create(s1, p1, o1); + } - Triple t = triple; - if ( s1 != s || p1 != p || o1 != o ) - t = Triple.create(s1, p1, o1); - Triple t2 = Substitute.substitute(t, b); - return t2; + // Deep node processing, with blank node rewrite and variable substitution. + public static Node subst(Node n, Binding b, Map bNodeMap, boolean allowTripleTerms) { + if ( n.isURI() || n.isLiteral() ) + return n; + if ( Var.isVar(n)) + return Substitute.substitute(Var.alloc(n), b); + if ( n.isBlank() || Var.isBlankNodeVar(n) ) + return newBlank(n, bNodeMap); + if ( allowTripleTerms && n.isTripleTerm() ) { + Triple t1 = subst(n.getTriple(), b, bNodeMap); + return NodeFactory.createTripleTerm(t1); + } + return n; } - /** generate a blank node consistently */ + /** Generate a blank node consistently */ private static Node newBlank(Node n, Map bNodeMap) { - if ( !bNodeMap.containsKey(n) ) - bNodeMap.put(n, NodeFactory.createBlankNode()); - return bNodeMap.get(n); + Node n2 = bNodeMap.get(n); + if ( n2 != null ) + return n2; + Node bNew = NodeFactory.createBlankNode(); + bNodeMap.put(n, bNew); + return bNew; } // ---- Template to query pattern diff --git a/jena-arq/src/main/java/org/apache/jena/system/G.java b/jena-arq/src/main/java/org/apache/jena/system/G.java index 538f41bd333..da96d5d472e 100644 --- a/jena-arq/src/main/java/org/apache/jena/system/G.java +++ b/jena-arq/src/main/java/org/apache/jena/system/G.java @@ -505,16 +505,23 @@ public static Set typesOfNodeAsSet(Graph graph, Node node) { } // ---- RDF list. + // Most ways to call GList.xxx - /** Return a java list for an RDF list of data. */ + /** @deprecated use {@link #listMembers(Graph, Node)} */ + @Deprecated(forRemoval = true) public static List rdfList(Graph graph, Node node) { + return listMembers(graph, node); + } + + /** Return a java list of an RDF list of data. */ + public static List listMembers(Graph graph, Node node) { Objects.requireNonNull(graph, "graph"); Objects.requireNonNull(node, "node"); List nodes = GList.members(graph, node); return nodes; } - /** Return a the length of an RDF list. */ + /** Return a the length of an RDF list. Return -1 if it is not a list. */ public static int listLength(Graph graph, Node node) { Objects.requireNonNull(graph, "graph"); Objects.requireNonNull(node, "node"); @@ -523,6 +530,20 @@ public static int listLength(Graph graph, Node node) { return (int)GList.listLength(graph, node); } + /** + * Test whether node looks like a list (RDF Collection). + * The test is whether node is {@code rdf:nil} + * or has exactly one of each of {@code rdf:first} + * and {@code rdf:next}. + * Multiple occurrences of {@code rdf:first} + * or {@code rdf:next} are considered errors. + */ + public static boolean isList(Graph graph, Node node) { + Objects.requireNonNull(graph, "graph"); + Objects.requireNonNull(node, "node"); + return GList.isListNode(graph, node); + } + /** * Return a java list where the {@code node} is an RDF list of nodes, * of if the node is not a list, return the node as a list of one. diff --git a/jena-arq/src/test/java/org/apache/jena/arq/junit/manifest/Manifest.java b/jena-arq/src/test/java/org/apache/jena/arq/junit/manifest/Manifest.java index 92e31fb0f87..edebe55c6dc 100644 --- a/jena-arq/src/test/java/org/apache/jena/arq/junit/manifest/Manifest.java +++ b/jena-arq/src/test/java/org/apache/jena/arq/junit/manifest/Manifest.java @@ -110,7 +110,7 @@ private void parseEntries() { Node entriesNode = G.getZeroOrOneSP(manifestGraph, manifest, TestManifest.entries.asNode()); if ( entriesNode == null ) return; - List items = G.rdfList(manifestGraph, entriesNode); + List items = G.listMembers(manifestGraph, entriesNode); List missingEntries = items.stream().filter(entry -> ! G.contains(manifestGraph, entry, null, null)).toList(); if ( ! missingEntries.isEmpty() ) { @@ -167,7 +167,7 @@ private void parseOneIncludesList(Node r) if ( ! r.isBlank() ) return; // Blank node - assumed to be a list. - List includes = G.rdfList(manifestGraph, r); + List includes = G.listMembers(manifestGraph, r); for ( Node inc : includes ) { if ( inc.isBlank() || inc.isURI() ) { parseOneIncludesList(inc); diff --git a/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/RiotTests.java b/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/RiotTests.java index 73672b8699a..8e64d5587cf 100644 --- a/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/RiotTests.java +++ b/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/RiotTests.java @@ -39,6 +39,7 @@ public class RiotTests { /** Create a RIOT language test - or return null for "unrecognized" */ + @SuppressWarnings("deprecation") public static Runnable makeRIOTTest(ManifestEntry entry) { //Resource manifest = entry.getManifest(); Node item = entry.getEntry(); @@ -76,6 +77,11 @@ public static Runnable makeRIOTTest(ManifestEntry entry) { if ( equalsType(testType, VocabLangRDF.TestNegativeSyntaxTTL) ) return new RiotSyntaxTest(entry, RDFLanguages.TURTLE, false); + // XXX Remove of rdf-test update + // These are parse errors + if ( equalsType(testType, VocabLangRDF.TestNegativeEvalTTL) ) + return new RiotSyntaxTest(entry, RDFLanguages.TURTLE, false); + // TRIG if ( equalsType(testType, VocabLangRDF.TestPositiveSyntaxTriG) ) { String base = rebase(input, assumedBase); @@ -84,6 +90,10 @@ public static Runnable makeRIOTTest(ManifestEntry entry) { if ( equalsType(testType, VocabLangRDF.TestNegativeSyntaxTriG) ) return new RiotSyntaxTest(entry, RDFLanguages.TRIG, false); + // XXX Remove of rdf-test update + if ( equalsType(testType, VocabLangRDF.TestNegativeEvalTriG) ) + return new RiotSyntaxTest(entry, RDFLanguages.TURTLE, false); + // NT if ( equalsType(testType, VocabLangRDF.TestPositiveSyntaxNT) ) return new RiotSyntaxTest(entry, RDFLanguages.NTRIPLES, true); @@ -117,19 +127,22 @@ public static Runnable makeRIOTTest(ManifestEntry entry) { String base = rebase(input, assumedBase); return new RiotEvalTest(entry, base, RDFLanguages.TURTLE, true); } - if ( equalsType(testType, VocabLangRDF.TestNegativeEvalTTL) ) { - String base = rebase(input, assumedBase); - return new RiotEvalTest(entry, base, RDFLanguages.TURTLE, false); - } - if ( equalsType(testType, VocabLangRDF.TestEvalTriG) ) { String base = rebase(input, assumedBase); return new RiotEvalTest(entry, base, RDFLanguages.TRIG, true); } - if ( equalsType(testType, VocabLangRDF.TestNegativeEvalTriG) ) { - String base = rebase(input, assumedBase); - return new RiotEvalTest(entry, base, RDFLanguages.TRIG, false); - } + +// // XXX Remove of rdf-test update +// if ( equalsType(testType, VocabLangRDF.TestNegativeEvalTTL) ) { +// String base = rebase(input, assumedBase); +// return new RiotEvalTest(entry, base, RDFLanguages.TURTLE, false); +// } + +// // XXX Remove of rdf-test update +// if ( equalsType(testType, VocabLangRDF.TestNegativeEvalTriG) ) { +// String base = rebase(input, assumedBase); +// return new RiotEvalTest(entry, base, RDFLanguages.TRIG, false); +// } if ( equalsType(testType, VocabLangRDF.TestEvalNT) ) { String base = entry.getAction().getURI();//rebase(input, assumedRootURI); diff --git a/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/VocabLangRDF.java b/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/VocabLangRDF.java index 0704260fe6c..f65f8a5439a 100644 --- a/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/VocabLangRDF.java +++ b/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/VocabLangRDF.java @@ -47,6 +47,7 @@ public class VocabLangRDF public static final Resource TestPositiveSyntaxTTL = m_model.createResource( NS+"TestTurtlePositiveSyntax" ); public static final Resource TestNegativeSyntaxTTL = m_model.createResource( NS+"TestTurtleNegativeSyntax" ); public static final Resource TestEvalTTL = m_model.createResource( NS+"TestTurtleEval" ); + @Deprecated public static final Resource TestNegativeEvalTTL = m_model.createResource( NS+"TestTurtleNegativeEval" ); public static final Resource TestPositiveSyntaxNT = m_model.createResource( NS+"TestNTriplesPositiveSyntax" ); @@ -67,6 +68,7 @@ public class VocabLangRDF public static final Resource TestPositiveSyntaxTriG = m_model.createResource( NS+"TestTrigPositiveSyntax" ); public static final Resource TestNegativeSyntaxTriG = m_model.createResource( NS+"TestTrigNegativeSyntax" ); public static final Resource TestEvalTriG = m_model.createResource( NS+"TestTrigEval" ); + @Deprecated public static final Resource TestNegativeEvalTriG = m_model.createResource( NS+"TestTrigNegativeEval" ); public static final Resource TestPositiveSyntaxRDFXML = m_model.createResource( NS+"TestXMLPositiveSyntax" ); diff --git a/jena-arq/src/test/java/org/apache/jena/rdf12/AbstratTestSPARQL12Eval.java b/jena-arq/src/test/java/org/apache/jena/rdf12/AbstratTestSPARQL12Eval.java index effc88a8cfd..0ad75de7e6e 100644 --- a/jena-arq/src/test/java/org/apache/jena/rdf12/AbstratTestSPARQL12Eval.java +++ b/jena-arq/src/test/java/org/apache/jena/rdf12/AbstratTestSPARQL12Eval.java @@ -22,10 +22,15 @@ package org.apache.jena.rdf12; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; import org.junit.jupiter.api.Test; import org.apache.jena.graph.Graph; +import org.apache.jena.riot.Lang; +import org.apache.jena.riot.RDFFormat; +import org.apache.jena.riot.RDFParser; +import org.apache.jena.riot.RDFWriter; import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.Quad; import org.apache.jena.sparql.exec.QueryExec; @@ -33,6 +38,7 @@ import org.apache.jena.sparql.exec.RowSetOps; import org.apache.jena.sparql.sse.SSE; import org.apache.jena.sparql.sse.SSE_ParseException; +import org.apache.jena.sparql.util.IsoMatcher; import org.apache.jena.system.Txn; /** @@ -88,6 +94,29 @@ private static void addQuad(DatasetGraph dsg, String str) { test("SELECT * { << ?x ?y ?z >> . }", 1); } + + @Test public void eval_sparql12_construct1() { + String s = """ + PREFIX : + :s :p <<( _:b0 :q :x2 )>> . + :s :p <<( _:b1 :q :x1 )>> . + """; + Graph expected = RDFParser.fromString(s, Lang.TTL).toGraph(); + testConstruct("PREFIX : CONSTRUCT { :s :p <<( _:b :q ?x )>> } WHERE { VALUES ?x { :x1 :x2 } }", + expected); + } + + @Test public void eval_sparql12_construct2() { + String s = """ + PREFIX : + << _:b1 :q :x1 >> . + << _:b2 :q :x2 >> . + """; + Graph expected = RDFParser.fromString(s, Lang.TTL).toGraph(); + testConstruct("PREFIX : CONSTRUCT { << _:b :q ?x >> } WHERE { VALUES ?x { :x1 :x2 } }", + expected); + } + private void test(String queryString, int expected) { DatasetGraph dsg = dsg(); Txn.executeRead(dsg, ()->{ @@ -99,6 +128,23 @@ private void test(String queryString, int expected) { }); } + private void testConstruct(String queryString, Graph expected) { + DatasetGraph dsg = dsg(); + Txn.executeRead(dsg, ()->{ + try( QueryExec qExec = QueryExec.dataset(dsg).query(queryString).build() ) { + Graph actual = qExec.construct(); + boolean b = IsoMatcher.isomorphic(expected, actual); + if ( !b ) { + System.err.println("==== Expected"); + RDFWriter.source(expected).format(RDFFormat.TURTLE_FLAT).output(System.err); + System.err.println("==== Actual"); + RDFWriter.source(actual).format(RDFFormat.TURTLE_FLAT).output(System.err); + System.err.println("===="); + fail("CONSTRUCT results are not isomorphic to expecte results"); + } + } + }); + } } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/BuildLib.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/BuildLib.java index 5d595d9c16b..9d194cdac16 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/BuildLib.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/BuildLib.java @@ -48,8 +48,6 @@ import org.apache.jena.sparql.exec.QueryExec; import org.apache.jena.sparql.exec.QueryExecBuilder; import org.apache.jena.sparql.exec.RowSet; -import org.apache.jena.sparql.util.graph.GNode; -import org.apache.jena.sparql.util.graph.GraphList; import org.apache.jena.system.G; import org.apache.jena.vocabulary.RDFS; @@ -108,23 +106,13 @@ private static Binding querySubstitution(String varName, Node value) { List results = new ArrayList<>(); nodes.forEach(node->{ - List members = listMembers(graph, node); - if ( members != null ) - results.addAll(members); - else - results.add(node); + // Returns a List.of(node) if not an RDF List. + List values = G.getOneOrList(graph, node); + results.addAll(values); }); return results; } - private static List listMembers(Graph graph, Node node) { - GNode gnode = new GNode(graph, node); - if ( ! GraphList.isListNode(gnode) ) - return null; - List list = GraphList.members(gnode); - return list; - } - // Node presentation /*package*/ static String displayStr(Graph graph, Node n) { diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionProcessor.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionProcessor.java index 3b0af8d361b..728241fcac5 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionProcessor.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionProcessor.java @@ -34,7 +34,7 @@ public interface ActionProcessor { public default void process(HttpAction action) { switch ( action.getRequestMethod() ) { case METHOD_GET -> execGet(action); - //case METHOD_QUERY -> execQuery(action); + case METHOD_QUERY -> execQuery(action); case METHOD_POST -> execPost(action); case METHOD_PATCH -> execPatch(action); case METHOD_PUT -> execPut(action); @@ -50,6 +50,7 @@ public default void process(HttpAction action) { // A common override is "executeLifecycle(action);" public default void execHead(HttpAction action) { execAny(METHOD_HEAD, action); } public default void execGet(HttpAction action) { execAny(METHOD_GET, action); } + public default void execQuery(HttpAction action) { execAny(METHOD_QUERY, action); } public default void execPost(HttpAction action) { execAny(METHOD_POST, action); } public default void execPatch(HttpAction action) { execAny(METHOD_PATCH, action); } public default void execPut(HttpAction action) { execAny(METHOD_PUT, action); } diff --git a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/ShaclPaths.java b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/ShaclPaths.java index 2f6cb233280..c26f2e79b1e 100644 --- a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/ShaclPaths.java +++ b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/ShaclPaths.java @@ -102,7 +102,7 @@ private static Path path(Graph graph, Node node) { return PathFactory.pathLink(node); if ( isList(graph, node) ) { - List nodes = G.rdfList(graph, node); + List nodes = G.listMembers(graph, node); if ( nodes.isEmpty() ) throw new ShaclParseException("Empty list for path sequence"); Path path = null; @@ -158,7 +158,7 @@ private static Path path(Graph graph, Node node) { if ( ! isList(graph, x) ) { throw new ShaclParseException("Not a list for path alternativePath"); } - List nodes = G.rdfList(graph, x); + List nodes = G.listMembers(graph, x); Path path = null; for ( Node n : nodes ) { Path p = path(graph, n); diff --git a/jena-shacl/src/main/java/org/apache/jena/shacl/parser/Constraints.java b/jena-shacl/src/main/java/org/apache/jena/shacl/parser/Constraints.java index 465a8a042d9..e3fd4f3e679 100644 --- a/jena-shacl/src/main/java/org/apache/jena/shacl/parser/Constraints.java +++ b/jena-shacl/src/main/java/org/apache/jena/shacl/parser/Constraints.java @@ -305,7 +305,7 @@ private static boolean booleanValue(Node node) { /** Return the list elements of an RDF list start at {@code node} */ private static List list(Graph g, Node node) { - return G.rdfList(g, node); + return G.listMembers(g, node); } private static List listString(Graph g, Node node) {