This is an automated email from the ASF dual-hosted git repository.

afs 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 abccdc47a7 GH-4108: SHACL pre-binding
abccdc47a7 is described below

commit abccdc47a78ff503713d7ab380711d7568592663
Author: Andy Seaborne <[email protected]>
AuthorDate: Wed Jul 29 14:11:37 2026 +0100

    GH-4108: SHACL pre-binding
---
 .../constraint/ShaclPrebindingException.java}      | 17 +++++---------
 .../shacl/engine/constraint/SparqlValidation.java  | 27 ++++++++++++++++++----
 .../org/apache/jena/shacl/vocabulary/SHACL.java    |  7 +++---
 .../{manifest.ttl-orig => manifest-1.0.ttl}        |  0
 .../test/files/std/sparql/pre-binding/manifest.ttl | 21 +++++++++++------
 ...nding-006.ttl => pre-binding-006-withdrawn.ttl} |  0
 ...04.ttl => unsupported-sparql-004-withdrawn.ttl} |  0
 .../test/java/org/apache/jena/shacl/TC_SHACL.java  |  5 ++--
 .../org/apache/jena/shacl/testing/ShaclTest.java   | 14 ++++++++---
 .../org/apache/jena/shacl/testing/ShaclTests.java  |  2 +-
 .../{TestJenaShacl.java => Scripts_JenaShacl.java} |  4 ++--
 .../jena/shacl/tests/jena_shacl/TS_JenaShacl.java  |  2 +-
 ...stShaclCoreWG.java => Scripts_ShaclCoreWG.java} |  4 ++--
 ...aclSparqlWG.java => Scripts_ShaclSparqlWG.java} |  8 +++++--
 .../apache/jena/shacl/tests/std/TS_StdSHACL.java   |  4 ++--
 15 files changed, 74 insertions(+), 41 deletions(-)

diff --git 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TS_JenaShacl.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ShaclPrebindingException.java
similarity index 75%
copy from 
jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TS_JenaShacl.java
copy to 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ShaclPrebindingException.java
index fe82875390..8e7a94e2c6 100644
--- 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TS_JenaShacl.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ShaclPrebindingException.java
@@ -19,17 +19,12 @@
  *   SPDX-License-Identifier: Apache-2.0
  */
 
-package org.apache.jena.shacl.tests.jena_shacl;
+package org.apache.jena.shacl.engine.constraint;
 
-import org.junit.platform.suite.api.SelectClasses;
-import org.junit.platform.suite.api.Suite;
-
-@Suite
-@SelectClasses({
-    // jena tests
-    TestJenaShaclByCode.class,
-    TestJenaShacl.class
-} )
-public class TS_JenaShacl {
+import org.apache.jena.shacl.ShaclException;
 
+public class ShaclPrebindingException extends ShaclException {
+    public ShaclPrebindingException(String msg) {
+        super(msg);
+    }
 }
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/SparqlValidation.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/SparqlValidation.java
index 395d8d29a5..195c47b720 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/SparqlValidation.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/SparqlValidation.java
@@ -50,8 +50,7 @@ import org.apache.jena.sparql.engine.binding.Binding;
 import org.apache.jena.sparql.path.P_Link;
 import org.apache.jena.sparql.path.Path;
 import org.apache.jena.sparql.path.PathFactory;
-import org.apache.jena.sparql.syntax.Element;
-import org.apache.jena.sparql.syntax.ElementPathBlock;
+import org.apache.jena.sparql.syntax.*;
 import org.apache.jena.sparql.syntax.syntaxtransform.ElementTransformCopyBase;
 import org.apache.jena.sparql.syntax.syntaxtransform.QueryTransformOps;
 import org.apache.jena.sparql.util.ModelUtils;
@@ -111,6 +110,16 @@ import org.apache.jena.sparql.util.ModelUtils;
         if ( path != null && !(path instanceof P_Link ) )
             query = QueryTransformOps.transform(query, new 
ElementTransformPath(SparqlConstraint.varPath, path));
 
+        // Check for disallowed syntax forms:
+        // MINUS, SERVICE
+        // "SPARQL queries MUST not contain a MINUS clause"
+        // "SPARQL queries MUST not contain a VALUES clause that mentions any 
potentially pre-bound variable"
+        // "SPARQL queries MUST not use the syntax form ​​AS ?var for any 
potentially pre-bound variable"
+        // "Furthermore, SPARQL queries SHOULD not contain a federated query 
(SERVICE)."
+
+        // VALUES and AS cause QueryScopeException happen during durign 
execution.
+
+        checkQuerySyntaxPreBinding(query);
 
         if ( USE_QueryTransformOps ) {
             // Done with QueryTransformOps.transform
@@ -120,12 +129,11 @@ import org.apache.jena.sparql.util.ModelUtils;
             Query query2 = QueryTransformOps.replaceVars(query, substitutions);
             qExec = QueryExecutionFactory.create(query2, model);
         } else {
+            // Use QueryExecution substitute (not initialBinding)
             // Done with pre-binding.
             QuerySolutionMap qsm = parameterMapToPreBinding(parameterMap, 
focusNode, path, model);
             if ( query.isAskType() )
                 qsm.add("value", 
ModelUtils.convertGraphNodeToRDFNode(valueNode, model));
-            //qExec = 
QueryExecution.create().query(query).model(model).initialBinding(qsm).build();
-
             // ---- Dataset needed for the shapes graph
             Resource shapesGraphResource = model.createResource("foo");
             qsm.add("currentShape", 
ModelUtils.convertGraphNodeToRDFNode(shape.getShapeNode(), model));
@@ -139,6 +147,8 @@ import org.apache.jena.sparql.util.ModelUtils;
         }
 
         // ASK validator.
+        // XXX Wrap in query solution, with $this and ?value.
+
         if ( qExec.getQuery().isAskType() ) {
             boolean askResult = qExec.execAsk();
             if ( ! askResult ) {
@@ -191,6 +201,15 @@ import org.apache.jena.sparql.util.ModelUtils;
         return false;
     }
 
+    private static ElementVisitor eltPrebindingCheckVisitor = new 
ElementVisitorBase() {
+        @Override public void visit(ElementMinus el)          { throw new 
ShaclPrebindingException("MINUS found in query for pre-binding"); }
+        @Override public void visit(ElementService el)        { throw new 
ShaclPrebindingException("SERBVICE found in query for pre-binding"); }
+    };
+
+    private static void checkQuerySyntaxPreBinding(Query query) {
+        ElementWalker.walk(query.getQueryPattern(), eltPrebindingCheckVisitor);
+    }
+
     /** Result message: SELECT substitute */
     private static String substitute(String violationTemplate, Binding row) {
         String x = violationTemplate;
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/vocabulary/SHACL.java 
b/jena-shacl/src/main/java/org/apache/jena/shacl/vocabulary/SHACL.java
index 1dd769ed7d..9552052ce5 100644
--- a/jena-shacl/src/main/java/org/apache/jena/shacl/vocabulary/SHACL.java
+++ b/jena-shacl/src/main/java/org/apache/jena/shacl/vocabulary/SHACL.java
@@ -65,9 +65,6 @@ public class SHACL {
      */
     public static final Node annotationVarName = createProperty( 
"http://www.w3.org/ns/shacl#annotationVarName"; );
 
-    /** <p>The SPARQL ASK query to execute.</p> */
-    public static final Node ask = createProperty( 
"http://www.w3.org/ns/shacl#ask"; );
-
     /** <p>The type that all value nodes must have.</p> */
     public static final Node class_ = createProperty( 
"http://www.w3.org/ns/shacl#class"; );
 
@@ -366,6 +363,10 @@ public class SHACL {
     /** <p>The SPARQL SELECT query to execute.</p> */
     public static final Node select = createProperty( 
"http://www.w3.org/ns/shacl#select"; );
 
+    /** <p>The SPARQL SELECT query to execute.</p> */
+    public static final Node ask = createProperty( 
"http://www.w3.org/ns/shacl#ask"; );
+
+
     /** <p>Defines the severity that validation results produced by a shape 
must have.
      *  Defaults to sh:Violation.</p>
      */
diff --git a/jena-shacl/src/test/files/std/sparql/pre-binding/manifest.ttl-orig 
b/jena-shacl/src/test/files/std/sparql/pre-binding/manifest-1.0.ttl
similarity index 100%
rename from jena-shacl/src/test/files/std/sparql/pre-binding/manifest.ttl-orig
rename to jena-shacl/src/test/files/std/sparql/pre-binding/manifest-1.0.ttl
diff --git a/jena-shacl/src/test/files/std/sparql/pre-binding/manifest.ttl 
b/jena-shacl/src/test/files/std/sparql/pre-binding/manifest.ttl
index 2c8a6457eb..4e931f07d9 100644
--- a/jena-shacl/src/test/files/std/sparql/pre-binding/manifest.ttl
+++ b/jena-shacl/src/test/files/std/sparql/pre-binding/manifest.ttl
@@ -10,22 +10,29 @@
        mf:include <pre-binding-003.ttl> ;
        mf:include <pre-binding-004.ttl> ;
        mf:include <pre-binding-005.ttl> ;
-    # Prebinding $this inside nested SELECT
+    
+    ## Test withdrawn in at SHACL 1.2
 ##     mf:include <pre-binding-006.ttl> ;
+
        mf:include <pre-binding-007.ttl> ;
-    
        mf:include <shapesGraph-001.ttl> ;
 
     # MINUS
-##     mf:include <unsupported-sparql-001.ttl> ;
+       mf:include <unsupported-sparql-001.ttl> ;
+
     # VALUES
-##     mf:include <unsupported-sparql-002.ttl> ;
+       mf:include <unsupported-sparql-002.ttl> ;
+
     # SERVICE
-##     mf:include <unsupported-sparql-003.ttl> ;
+       mf:include <unsupported-sparql-003.ttl> ;
+    
     # SELECT
+    ## Test withdrawn in at SHACL 1.2
 ##     mf:include <unsupported-sparql-004.ttl> ;
+
     # BIND assign to $this
-##     mf:include <unsupported-sparql-005.ttl> ;
+       mf:include <unsupported-sparql-005.ttl> ;
+
     # ASK validator reassign ?value
-##     mf:include <unsupported-sparql-006.ttl> ;
+       mf:include <unsupported-sparql-006.ttl> ;
  .
diff --git 
a/jena-shacl/src/test/files/std/sparql/pre-binding/pre-binding-006.ttl 
b/jena-shacl/src/test/files/std/sparql/pre-binding/pre-binding-006-withdrawn.ttl
similarity index 100%
rename from jena-shacl/src/test/files/std/sparql/pre-binding/pre-binding-006.ttl
rename to 
jena-shacl/src/test/files/std/sparql/pre-binding/pre-binding-006-withdrawn.ttl
diff --git 
a/jena-shacl/src/test/files/std/sparql/pre-binding/unsupported-sparql-004.ttl 
b/jena-shacl/src/test/files/std/sparql/pre-binding/unsupported-sparql-004-withdrawn.ttl
similarity index 100%
rename from 
jena-shacl/src/test/files/std/sparql/pre-binding/unsupported-sparql-004.ttl
rename to 
jena-shacl/src/test/files/std/sparql/pre-binding/unsupported-sparql-004-withdrawn.ttl
diff --git a/jena-shacl/src/test/java/org/apache/jena/shacl/TC_SHACL.java 
b/jena-shacl/src/test/java/org/apache/jena/shacl/TC_SHACL.java
index a35658ff4c..7d2cdc865b 100644
--- a/jena-shacl/src/test/java/org/apache/jena/shacl/TC_SHACL.java
+++ b/jena-shacl/src/test/java/org/apache/jena/shacl/TC_SHACL.java
@@ -34,13 +34,12 @@ import org.apache.jena.shacl.tests.std.TS_StdSHACL;
 @Suite
 @SelectClasses({
     TestValidationReport.class
+    , TestImports.class
+    , TestValidationListener.class
 
     , TS_StdSHACL.class
     , TS_JenaShacl.class
     , TS_Compact.class
-
-    , TestImports.class
-    , TestValidationListener.class
 } )
 
 public class TC_SHACL { }
diff --git 
a/jena-shacl/src/test/java/org/apache/jena/shacl/testing/ShaclTest.java 
b/jena-shacl/src/test/java/org/apache/jena/shacl/testing/ShaclTest.java
index 5755c523c7..eba6da170a 100644
--- a/jena-shacl/src/test/java/org/apache/jena/shacl/testing/ShaclTest.java
+++ b/jena-shacl/src/test/java/org/apache/jena/shacl/testing/ShaclTest.java
@@ -31,8 +31,10 @@ import org.apache.jena.riot.RDFDataMgr;
 import org.apache.jena.shacl.ShaclValidator;
 import org.apache.jena.shacl.Shapes;
 import org.apache.jena.shacl.ValidationReport;
+import org.apache.jena.shacl.engine.constraint.ShaclPrebindingException;
 import org.apache.jena.shacl.lib.ShLib;
 import org.apache.jena.shacl.validation.VR;
+import org.apache.jena.sparql.syntax.syntaxtransform.QueryScopeException;
 
 public class ShaclTest {
 
@@ -50,10 +52,16 @@ public class ShaclTest {
                 try {
                     ValidationReport testReport = 
validate(ShaclValidator.get(), shapesGraph, dataGraph);
                     if ( testReport.conforms() )
-                        fail("Expect a test failure: "+test.origin());
-                } catch (RuntimeException ex) {
-                    // Ignore.
+                        fail("Expected a test failure: "+test.origin());
+                    else
+                        // !conforms expected
+                        return;
+                } catch ( QueryScopeException | ShaclPrebindingException ex) {
+                    // "Success"
+                    return;
                 }
+                // "Success"
+                return;
             }
 
             // Fails on unimplemented.
diff --git 
a/jena-shacl/src/test/java/org/apache/jena/shacl/testing/ShaclTests.java 
b/jena-shacl/src/test/java/org/apache/jena/shacl/testing/ShaclTests.java
index 25f19cd617..248ff903d8 100644
--- a/jena-shacl/src/test/java/org/apache/jena/shacl/testing/ShaclTests.java
+++ b/jena-shacl/src/test/java/org/apache/jena/shacl/testing/ShaclTests.java
@@ -69,7 +69,7 @@ public class ShaclTests {
 
     private static String decideName(ShaclTestItem stc) {
         String fn = FileOps.basename(stc.origin());
-        return stc.name()+"("+fn+")";
+        return stc.name()+" ("+fn+")";
     }
 
     private static void manifest(String manifestFile, List<String> manifests, 
List<ShaclTestItem> testCases) {
diff --git 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TestJenaShacl.java
 
b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/Scripts_JenaShacl.java
similarity index 95%
rename from 
jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TestJenaShacl.java
rename to 
jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/Scripts_JenaShacl.java
index b2d6ba5a57..62f521b195 100644
--- 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TestJenaShacl.java
+++ 
b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/Scripts_JenaShacl.java
@@ -36,7 +36,7 @@ import org.apache.jena.shacl.testing.ShaclTests;
 
 @ParameterizedClass(name="{index}: {0}")
 @MethodSource("provideArgs")
-public class TestJenaShacl {
+public class Scripts_JenaShacl {
 
     private static Stream<Arguments> provideArgs() {
         String manifestFile = "src/test/files/local/manifest.ttl";
@@ -48,7 +48,7 @@ public class TestJenaShacl {
 
     private ShaclTestItem test;
 
-    public TestJenaShacl(String name,  ShaclTestItem test) {
+    public Scripts_JenaShacl(String name,  ShaclTestItem test) {
         this.test = test;
     }
 
diff --git 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TS_JenaShacl.java
 
b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TS_JenaShacl.java
index fe82875390..0a8ecdf70e 100644
--- 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TS_JenaShacl.java
+++ 
b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/jena_shacl/TS_JenaShacl.java
@@ -28,7 +28,7 @@ import org.junit.platform.suite.api.Suite;
 @SelectClasses({
     // jena tests
     TestJenaShaclByCode.class,
-    TestJenaShacl.class
+    Scripts_JenaShacl.class
 } )
 public class TS_JenaShacl {
 
diff --git 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TestShaclCoreWG.java 
b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/Scripts_ShaclCoreWG.java
similarity index 95%
rename from 
jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TestShaclCoreWG.java
rename to 
jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/Scripts_ShaclCoreWG.java
index f22c75750d..15fac23f56 100644
--- 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TestShaclCoreWG.java
+++ 
b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/Scripts_ShaclCoreWG.java
@@ -37,7 +37,7 @@ import org.apache.jena.shacl.testing.ShaclTests;
 
 @ParameterizedClass(name="{0}")
 @MethodSource("provideArgs")
-public class TestShaclCoreWG {
+public class Scripts_ShaclCoreWG {
 
     private static Stream<Arguments> provideArgs() {
         String manifestFile = "src/test/files/std/core/manifest.ttl";
@@ -49,7 +49,7 @@ public class TestShaclCoreWG {
 
     private ShaclTestItem test;
 
-    public TestShaclCoreWG(String name,  ShaclTestItem test) {
+    public Scripts_ShaclCoreWG(String name,  ShaclTestItem test) {
         ShaclSystem.setMode(ShaclSystem.Mode.TEST);
         this.test = test;
     }
diff --git 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TestShaclSparqlWG.java
 
b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/Scripts_ShaclSparqlWG.java
similarity index 90%
rename from 
jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TestShaclSparqlWG.java
rename to 
jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/Scripts_ShaclSparqlWG.java
index 8ea4c51787..6350f63dcb 100644
--- 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TestShaclSparqlWG.java
+++ 
b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/Scripts_ShaclSparqlWG.java
@@ -36,7 +36,7 @@ import org.apache.jena.shacl.testing.ShaclTests;
 
 @ParameterizedClass(name="{0}")
 @MethodSource("provideArgs")
-public class TestShaclSparqlWG {
+public class Scripts_ShaclSparqlWG {
 
     private static Stream<Arguments> provideArgs() {
 //      // The W3C WG tests for SPARQL-based Constraints is made up of:
@@ -44,7 +44,11 @@ public class TestShaclSparqlWG {
 //      //String manifest = 
"src/test/files/std/sparql/pre-binding/manifest.ttl";
 //      //String manifest = "src/test/files/std/sparql/node/manifest.ttl";
 //      //String manifest = "src/test/files/std/sparql/component/manifest.ttl";
+
+        // pre-binding/manifest.ttl is different to the SHACL 1.0 published 
tests.
+        // Some tests withdrawn in SHACL 1.2
         String manifestFile = "src/test/files/std/sparql/manifest.ttl";
+
         List<String> omitManifests = List.of();
         List<Pair<String, ShaclTestItem>> z = 
ShaclTests.manifestNamed(manifestFile, omitManifests);
         List<Arguments> x = z.stream().map(p->Arguments.of(p.getLeft(), 
p.getRight())).toList();
@@ -53,7 +57,7 @@ public class TestShaclSparqlWG {
 
     private ShaclTestItem test;
 
-    public TestShaclSparqlWG(String name,  ShaclTestItem test) {
+    public Scripts_ShaclSparqlWG(String name,  ShaclTestItem test) {
         this.test = test;
     }
 
diff --git 
a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TS_StdSHACL.java 
b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TS_StdSHACL.java
index 268376d6ae..df8caad78e 100644
--- a/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TS_StdSHACL.java
+++ b/jena-shacl/src/test/java/org/apache/jena/shacl/tests/std/TS_StdSHACL.java
@@ -27,8 +27,8 @@ import org.junit.platform.suite.api.Suite;
 @Suite
 @SelectClasses({
     // The W3C Working Group tests.
-    TestShaclCoreWG.class ,
-    TestShaclSparqlWG.class
+    Scripts_ShaclCoreWG.class ,
+    Scripts_ShaclSparqlWG.class
 } )
 
 public class TS_StdSHACL {

Reply via email to