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

commit bee9dccde41347886531aff489d732259ff3a786
Author: Andy Seaborne <[email protected]>
AuthorDate: Fri Apr 24 08:17:56 2026 +0100

    GH-3888: Minimal impl of sh:memberShape
---
 .../{ConstraintTerm.java => ConstraintList.java}   | 22 ++++----
 .../shacl/engine/constraint/ConstraintTerm.java    |  4 +-
 .../engine/constraint/DatatypeConstraint.java      |  3 +-
 .../jena/shacl/engine/constraint/InConstraint.java |  2 +-
 .../shacl/engine/constraint/JLogConstraint.java    |  2 +-
 .../engine/constraint/JViolationConstraint.java    |  2 +-
 .../{JLogConstraint.java => ListMaxLength.java}    | 52 ++++++++---------
 .../{InConstraint.java => ListMemberShape.java}    | 66 ++++++++++++++--------
 .../{JLogConstraint.java => ListMinLength.java}    | 52 ++++++++---------
 .../{InConstraint.java => ListUniqueMembers.java}  | 55 ++++++++----------
 .../engine/constraint/NodeKindConstraint.java      | 22 +++++---
 .../shacl/engine/constraint/PatternConstraint.java |  2 +-
 .../jena/shacl/engine/constraint/ShXone.java       |  3 +-
 .../shacl/engine/constraint/StrLanguageIn.java     |  2 +-
 .../engine/constraint/StrMaxLengthConstraint.java  |  2 +-
 .../engine/constraint/StrMinLengthConstraint.java  |  2 +-
 .../engine/constraint/ValueRangeConstraint.java    |  3 +-
 .../jena/shacl/parser/ConstraintVisitor.java       |  5 ++
 .../org/apache/jena/shacl/parser/Constraints.java  |  9 +++
 .../org/apache/jena/shacl/vocabulary/SHACL.java    | 60 ++++++++++++++------
 20 files changed, 212 insertions(+), 158 deletions(-)

diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintTerm.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintList.java
similarity index 74%
copy from 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintTerm.java
copy to 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintList.java
index 284830cf88..8493c8f339 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintTerm.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintList.java
@@ -33,37 +33,35 @@ import 
org.apache.jena.shacl.validation.event.ConstraintEvaluatedOnFocusNodeEven
 import 
org.apache.jena.shacl.validation.event.ConstraintEvaluatedOnSinglePathNodeEvent;
 import org.apache.jena.sparql.path.Path;
 
-/* Constraint that does not need access to the data other than the nodes 
supplied. e.g. sh:datatype. */
-public abstract class ConstraintTerm implements Constraint {
+public abstract class ConstraintList implements Constraint {
 
-    public ConstraintTerm() {}
+    protected ConstraintList() {}
 
     @Override
     final
     public void validatePropertyShape(ValidationContext vCxt, Graph data, 
Shape shape, Node focusNode, Path path, Set<Node> valueNodes) {
-        valueNodes.forEach(x->applyConstraintTerm(vCxt, shape, focusNode, 
path, x));
+        valueNodes.forEach(x->applyConstraintList(vCxt, shape, focusNode, 
path, data, x));
     }
 
     @Override
     final
     public void validateNodeShape(ValidationContext vCxt, Graph data, Shape 
shape, Node focusNode) {
-        applyConstraintTerm(vCxt, shape, focusNode, null, focusNode);
+        applyConstraintList(vCxt, shape, focusNode, null, data, focusNode);
     }
 
-    private void applyConstraintTerm(ValidationContext vCxt, Shape shape, Node 
focusNode, Path path, Node term) {
-        ReportItem item = validate(vCxt, term);
-        boolean passed = item == null;
+    private void applyConstraintList(ValidationContext vCxt, Shape shape, Node 
focusNode, Path path, Graph data, Node listHead) {
+        ReportItem item = validateList(vCxt, data, listHead);
+        boolean passed = (item == null);
         if (path == null) {
             vCxt.notifyValidationListener(() -> new 
ConstraintEvaluatedOnFocusNodeEvent(vCxt, shape, focusNode, this, passed));
         } else {
             vCxt.notifyValidationListener(() -> new 
ConstraintEvaluatedOnSinglePathNodeEvent(vCxt, shape, focusNode, this, path,
-                                            term, passed));
+                                                                               
              listHead, passed));
         }
-        if ( passed ) {
+        if ( passed )
             return;
-        }
         vCxt.reportEntry(item, shape, focusNode, path, this);
     }
 
-    public abstract ReportItem validate(ValidationContext vCxt, Node n) ;
+    protected abstract ReportItem validateList(ValidationContext vCxt, Graph 
data, Node n) ;
 }
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintTerm.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintTerm.java
index 284830cf88..0264c6fdb6 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintTerm.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintTerm.java
@@ -52,7 +52,7 @@ public abstract class ConstraintTerm implements Constraint {
 
     private void applyConstraintTerm(ValidationContext vCxt, Shape shape, Node 
focusNode, Path path, Node term) {
         ReportItem item = validate(vCxt, term);
-        boolean passed = item == null;
+        boolean passed = (item == null);
         if (path == null) {
             vCxt.notifyValidationListener(() -> new 
ConstraintEvaluatedOnFocusNodeEvent(vCxt, shape, focusNode, this, passed));
         } else {
@@ -65,5 +65,5 @@ public abstract class ConstraintTerm implements Constraint {
         vCxt.reportEntry(item, shape, focusNode, path, this);
     }
 
-    public abstract ReportItem validate(ValidationContext vCxt, Node n) ;
+    protected abstract ReportItem validate(ValidationContext vCxt, Node n) ;
 }
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/DatatypeConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/DatatypeConstraint.java
index 35d329fe05..b47ad94d57 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/DatatypeConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/DatatypeConstraint.java
@@ -75,7 +75,7 @@ public class DatatypeConstraint extends ConstraintTerm {
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
+    protected ReportItem validate(ValidationContext vCxt, Node n) {
         if ( n.isLiteral() && dtURI.equals(n.getLiteralDatatypeURI()) ) {
             // Must be valid for the type
             if ( ! rdfDatatype.isValid(n.getLiteralLexicalForm()) ) {
@@ -131,6 +131,7 @@ public class DatatypeConstraint extends ConstraintTerm {
 
     @Override
     public String toString() {
+        // DRY (with ListMmeberShape, others?
         String x;
         if ( datatype.isURI() ) {
             if ( dtURI.startsWith(XSD.getURI()) )
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
index 0d9bd00d86..82f1300c5c 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
@@ -56,7 +56,7 @@ public class InConstraint extends ConstraintTerm {
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
+    protected ReportItem validate(ValidationContext vCxt, Node n) {
         if ( values.contains(n) )
             return null;
         String errMsg = toString()+" : RDF term "+displayStr(n)+" not in 
expected values";
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
index 4a4bd6b697..4fdd687c75 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
@@ -50,7 +50,7 @@ public class JLogConstraint extends ConstraintTerm {
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
+    protected ReportItem validate(ValidationContext vCxt, Node n) {
         String msg = String.format("%s[%s]", message, ShLib.displayStr(n));
         ShaclSystem.shaclSystemLogger.warn(msg);
         return null;
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JViolationConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JViolationConstraint.java
index ac8430b65d..5945e106e5 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JViolationConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JViolationConstraint.java
@@ -49,7 +49,7 @@ public class JViolationConstraint extends ConstraintTerm {
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
+    protected ReportItem validate(ValidationContext vCxt, Node n) {
         if ( ! generateViolation )
             return null;
         return new ReportItem("Violation");
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListMaxLength.java
similarity index 63%
copy from 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
copy to 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListMaxLength.java
index 4a4bd6b697..36253ed3f3 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListMaxLength.java
@@ -21,54 +21,55 @@
 
 package org.apache.jena.shacl.engine.constraint;
 
-import java.util.Objects;
-
+import org.apache.jena.atlas.io.IndentedWriter;
+import org.apache.jena.atlas.lib.NotImplemented;
+import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.Node;
+import org.apache.jena.riot.out.NodeFormatter;
 import org.apache.jena.shacl.engine.ValidationContext;
-import org.apache.jena.shacl.lib.ShLib;
 import org.apache.jena.shacl.parser.ConstraintVisitor;
-import org.apache.jena.shacl.sys.ShaclSystem;
 import org.apache.jena.shacl.validation.ReportItem;
-import org.apache.jena.shacl.vocabulary.SHJ;
+import org.apache.jena.shacl.vocabulary.SHACL;
+
+/** sh:memberShape */
 
-/** A constraint that logs when touched but does not causes a violation */
-public class JLogConstraint extends ConstraintTerm {
+public class ListMaxLength extends ConstraintList {
 
-    private final String message;
+    public ListMaxLength(Node node) {}
 
-    public JLogConstraint(String message) {
-        this.message = message;
+    @Override
+    public void visit(ConstraintVisitor visitor){
+        visitor.visit(this);
     }
 
-    public String getMessage() {
-        return message;
+    @Override
+    public void printCompact(IndentedWriter out, NodeFormatter nodeFmt) {
+        throw new NotImplemented();
     }
 
     @Override
-    public Node getComponent() {
-        return SHJ.LogConstraintComponent;
+    protected ReportItem validateList(ValidationContext vCxt, Graph data, Node 
headNode) {
+        throw new NotImplemented();
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
-        String msg = String.format("%s[%s]", message, ShLib.displayStr(n));
-        ShaclSystem.shaclSystemLogger.warn(msg);
-        return null;
+    public Node getComponent() {
+        return SHACL.ListMaxLengthConstraintComponent;
     }
 
     @Override
-    public void visit(ConstraintVisitor visitor){
-        visitor.visit(this);
+    public void print(IndentedWriter out, NodeFormatter nodeFmt) {
+        out.print(toString());
     }
 
     @Override
     public String toString() {
-        return "Log["+message+"]";
+        return "ListMemberShape[]";
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(message);
+        throw new NotImplemented();
     }
 
     @Override
@@ -77,10 +78,9 @@ public class JLogConstraint extends ConstraintTerm {
             return true;
         if ( obj == null )
             return false;
-        if ( getClass() != obj.getClass() )
+        if ( !(obj instanceof ListMaxLength other) )
             return false;
-        JLogConstraint other = (JLogConstraint)obj;
-        return Objects.equals(message, other.message);
+        throw new NotImplemented();
     }
-}
 
+}
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListMemberShape.java
similarity index 57%
copy from 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
copy to 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListMemberShape.java
index 0d9bd00d86..133edec8e9 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListMemberShape.java
@@ -21,66 +21,84 @@
 
 package org.apache.jena.shacl.engine.constraint;
 
-import static 
org.apache.jena.shacl.compact.writer.CompactOut.compactArrayNodes;
+import static org.apache.jena.shacl.compact.writer.CompactOut.compact;
 import static org.apache.jena.shacl.lib.ShLib.displayStr;
 
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
 import org.apache.jena.atlas.io.IndentedWriter;
+import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.Node;
 import org.apache.jena.riot.out.NodeFormatter;
 import org.apache.jena.shacl.engine.ValidationContext;
 import org.apache.jena.shacl.parser.ConstraintVisitor;
+import org.apache.jena.shacl.parser.Shape;
 import org.apache.jena.shacl.validation.ReportItem;
+import org.apache.jena.shacl.validation.ValidationProc;
 import org.apache.jena.shacl.vocabulary.SHACL;
+import org.apache.jena.sparql.util.graph.GNode;
+import org.apache.jena.sparql.util.graph.GraphList;
 
-/** sh:in */
-public class InConstraint extends ConstraintTerm {
+/** sh:memberShape */
 
-    private final List<Node> values = new ArrayList<>();
+public class ListMemberShape extends ConstraintList {
 
-    public InConstraint(List<Node> list) {
-        values.addAll(list);
+    protected final Node shape;
+
+    public ListMemberShape(Node node) {
+        this.shape = node;
     }
 
-    public List<Node> getValues() {
-        return Collections.unmodifiableList(values);
+    @Override
+    public void visit(ConstraintVisitor visitor){
+        visitor.visit(this);
     }
 
     @Override
-    public Node getComponent() {
-        return SHACL.InConstraintComponent;
+    public void printCompact(IndentedWriter out, NodeFormatter nodeFmt) {
+        compact(out, nodeFmt, "memberShape", shape);
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
-        if ( values.contains(n) )
+    protected ReportItem validateList(ValidationContext vCxt, Graph data, Node 
headNode) {
+        Shape memberShape = vCxt.getShapes().getShape(shape);
+        if ( memberShape == null ) {
+            // XXX
+            //vCxt.reportEntry(, shape, focusNode, path, valueNode, 
constraint);
+            // No shape. Error?
             return null;
-        String errMsg = toString()+" : RDF term "+displayStr(n)+" not in 
expected values";
-        return new ReportItem(errMsg, n);
+        }
+        // XXX Check for valid lists.
+        GNode gNode = GNode.create(data, headNode);
+        List<Node> members = GraphList.members(gNode);
+
+        members.forEach(x->{
+            ValidationProc.execValidateShape(vCxt, data, memberShape, x);
+        });
+        // XXX Isolate validation and wrap violations?
+        return null;
     }
 
     @Override
-    public void visit(ConstraintVisitor visitor){
-        visitor.visit(this);
+    public Node getComponent() {
+        return SHACL.MemberShapeConstraintComponent;
     }
 
     @Override
-    public void printCompact(IndentedWriter out, NodeFormatter nodeFmt) {
-        compactArrayNodes(out, nodeFmt, "in", values);
+    public void print(IndentedWriter out, NodeFormatter nodeFmt) {
+        out.print(toString());
     }
 
     @Override
     public String toString() {
-        return "InConstraint"+values;
+        // XXX Prefixes
+        return "ListMemberShape["+displayStr(shape)+"]";
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(values);
+        return Objects.hash(shape);
     }
 
     @Override
@@ -89,8 +107,8 @@ public class InConstraint extends ConstraintTerm {
             return true;
         if ( obj == null )
             return false;
-        if ( !(obj instanceof InConstraint other) )
+        if ( !(obj instanceof ListMemberShape other) )
             return false;
-        return Objects.equals(values, other.values);
+        return shape.sameTermAs(other.shape);
     }
 }
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListMinLength.java
similarity index 63%
copy from 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
copy to 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListMinLength.java
index 4a4bd6b697..6fff10ba56 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/JLogConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListMinLength.java
@@ -21,54 +21,55 @@
 
 package org.apache.jena.shacl.engine.constraint;
 
-import java.util.Objects;
-
+import org.apache.jena.atlas.io.IndentedWriter;
+import org.apache.jena.atlas.lib.NotImplemented;
+import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.Node;
+import org.apache.jena.riot.out.NodeFormatter;
 import org.apache.jena.shacl.engine.ValidationContext;
-import org.apache.jena.shacl.lib.ShLib;
 import org.apache.jena.shacl.parser.ConstraintVisitor;
-import org.apache.jena.shacl.sys.ShaclSystem;
 import org.apache.jena.shacl.validation.ReportItem;
-import org.apache.jena.shacl.vocabulary.SHJ;
+import org.apache.jena.shacl.vocabulary.SHACL;
+
+/** sh:memberShape */
 
-/** A constraint that logs when touched but does not causes a violation */
-public class JLogConstraint extends ConstraintTerm {
+public class ListMinLength extends ConstraintList {
 
-    private final String message;
+    public ListMinLength(Node node) { }
 
-    public JLogConstraint(String message) {
-        this.message = message;
+    @Override
+    public void visit(ConstraintVisitor visitor){
+        visitor.visit(this);
     }
 
-    public String getMessage() {
-        return message;
+    @Override
+    public void printCompact(IndentedWriter out, NodeFormatter nodeFmt) {
+        throw new NotImplemented();
     }
 
     @Override
-    public Node getComponent() {
-        return SHJ.LogConstraintComponent;
+    protected ReportItem validateList(ValidationContext vCxt, Graph data, Node 
headNode) {
+        throw new NotImplemented();
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
-        String msg = String.format("%s[%s]", message, ShLib.displayStr(n));
-        ShaclSystem.shaclSystemLogger.warn(msg);
-        return null;
+    public Node getComponent() {
+        return SHACL.ListMinLengthConstraintComponent;
     }
 
     @Override
-    public void visit(ConstraintVisitor visitor){
-        visitor.visit(this);
+    public void print(IndentedWriter out, NodeFormatter nodeFmt) {
+        out.print(toString());
     }
 
     @Override
     public String toString() {
-        return "Log["+message+"]";
+        return "ListMemberShape[]";
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(message);
+        throw new NotImplemented();
     }
 
     @Override
@@ -77,10 +78,9 @@ public class JLogConstraint extends ConstraintTerm {
             return true;
         if ( obj == null )
             return false;
-        if ( getClass() != obj.getClass() )
+        if ( !(obj instanceof ListMinLength other) )
             return false;
-        JLogConstraint other = (JLogConstraint)obj;
-        return Objects.equals(message, other.message);
+        throw new NotImplemented();
     }
-}
 
+}
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListUniqueMembers.java
similarity index 62%
copy from 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
copy to 
jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListUniqueMembers.java
index 0d9bd00d86..4c7893015a 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/InConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ListUniqueMembers.java
@@ -21,15 +21,9 @@
 
 package org.apache.jena.shacl.engine.constraint;
 
-import static 
org.apache.jena.shacl.compact.writer.CompactOut.compactArrayNodes;
-import static org.apache.jena.shacl.lib.ShLib.displayStr;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
 import org.apache.jena.atlas.io.IndentedWriter;
+import org.apache.jena.atlas.lib.NotImplemented;
+import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.Node;
 import org.apache.jena.riot.out.NodeFormatter;
 import org.apache.jena.shacl.engine.ValidationContext;
@@ -37,50 +31,48 @@ import org.apache.jena.shacl.parser.ConstraintVisitor;
 import org.apache.jena.shacl.validation.ReportItem;
 import org.apache.jena.shacl.vocabulary.SHACL;
 
-/** sh:in */
-public class InConstraint extends ConstraintTerm {
+/** sh:memberShape */
 
-    private final List<Node> values = new ArrayList<>();
+public class ListUniqueMembers extends ConstraintList {
 
-    public InConstraint(List<Node> list) {
-        values.addAll(list);
-    }
+    public ListUniqueMembers(Node node) {}
 
-    public List<Node> getValues() {
-        return Collections.unmodifiableList(values);
+    @Override
+    public void visit(ConstraintVisitor visitor){
+        visitor.visit(this);
     }
 
     @Override
-    public Node getComponent() {
-        return SHACL.InConstraintComponent;
+    public void printCompact(IndentedWriter out, NodeFormatter nodeFmt) {
+        //compact(out, nodeFmt, "nodeKind", getKind());
+        // Property context only.
+//        String s = getKind().getLocalName();
+//        out.print(s);
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
-        if ( values.contains(n) )
-            return null;
-        String errMsg = toString()+" : RDF term "+displayStr(n)+" not in 
expected values";
-        return new ReportItem(errMsg, n);
+    protected ReportItem validateList(ValidationContext vCxt, Graph data, Node 
headNode) {
+        throw new NotImplemented();
     }
 
     @Override
-    public void visit(ConstraintVisitor visitor){
-        visitor.visit(this);
+    public Node getComponent() {
+        return SHACL.UniqueMembersConstraintComponent;
     }
 
     @Override
-    public void printCompact(IndentedWriter out, NodeFormatter nodeFmt) {
-        compactArrayNodes(out, nodeFmt, "in", values);
+    public void print(IndentedWriter out, NodeFormatter nodeFmt) {
+        out.print(toString());
     }
 
     @Override
     public String toString() {
-        return "InConstraint"+values;
+        return "ListMemberShape[]";
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(values);
+        throw new NotImplemented();
     }
 
     @Override
@@ -89,8 +81,9 @@ public class InConstraint extends ConstraintTerm {
             return true;
         if ( obj == null )
             return false;
-        if ( !(obj instanceof InConstraint other) )
+        if ( !(obj instanceof ListUniqueMembers other) )
             return false;
-        return Objects.equals(values, other.values);
+        throw new NotImplemented();
     }
+
 }
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/NodeKindConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/NodeKindConstraint.java
index ee955f022b..6404af002e 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/NodeKindConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/NodeKindConstraint.java
@@ -39,25 +39,28 @@ import org.apache.jena.shacl.vocabulary.SHACL;
 public class NodeKindConstraint extends ConstraintTerm {
 
     //sh:NodeKind: sh:BlankNode, sh:IRI, sh:Literal sh:BlankNodeOrIRI, 
sh:BlankNodeOrLiteral and sh:IRIOrLiteral.
+    // SHACL 1.2 -- sh:TripleTerm
 
     private final Node kind;
     private final boolean canBeIRI;
     private final boolean canBeBlankNode;
     private final boolean canBeLiteral;
+    private final boolean canBeTripleTerm;
 
     public NodeKindConstraint(Node kind) {
         Objects.requireNonNull(kind);
         if ( ! kind.isURI() )
             throw new IllegalArgumentException("NodeKindConstraint; not an IRI 
for the kind kind");
         this.kind = kind;
-        this.canBeIRI       = kind.equals(SHACL.IRI)       || 
kind.equals(SHACL.BlankNodeOrIRI)     || kind.equals(SHACL.IRIOrLiteral);
-        this.canBeBlankNode = kind.equals(SHACL.BlankNode) || 
kind.equals(SHACL.BlankNodeOrIRI)     || kind.equals(SHACL.BlankNodeOrLiteral);
-        this.canBeLiteral   = kind.equals(SHACL.Literal)   || 
kind.equals(SHACL.BlankNodeOrLiteral) || kind.equals(SHACL.IRIOrLiteral);
+        this.canBeIRI         = kind.equals(SHACL.IRI)       || 
kind.equals(SHACL.BlankNodeOrIRI)     || kind.equals(SHACL.IRIOrLiteral);
+        this.canBeBlankNode   = kind.equals(SHACL.BlankNode) || 
kind.equals(SHACL.BlankNodeOrIRI)     || kind.equals(SHACL.BlankNodeOrLiteral);
+        this.canBeLiteral     = kind.equals(SHACL.Literal)   || 
kind.equals(SHACL.BlankNodeOrLiteral) || kind.equals(SHACL.IRIOrLiteral);
+        this.canBeTripleTerm  = kind.equals(SHACL.TripleTerm);
 
-        if ( ! canBeIRI && ! canBeBlankNode && ! canBeLiteral )
+        if ( ! canBeIRI && ! canBeBlankNode && ! canBeLiteral && ! 
canBeTripleTerm )
             throw new IllegalArgumentException(
                 "NodeKind["+kind.getLocalName()+"] : "+
-                "not one of sh:BlankNode, sh:IRI, sh:Literal 
sh:BlankNodeOrIRI, sh:BlankNodeOrLiteral and sh:IRIOrLiteral");
+                "not one of sh:BlankNode, sh:IRI, sh:Literal 
sh:BlankNodeOrIRI, sh:BlankNodeOrLiteral, sh:IRIOrLiteral, or sh:TripleTerm");
     }
 
     public  Node getKind() { return kind; }
@@ -88,10 +91,11 @@ public class NodeKindConstraint extends ConstraintTerm {
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
-        if ( canBeIRI && n.isURI() )          return null;
-        if ( canBeBlankNode && n.isBlank() )  return null;
-        if ( canBeLiteral && n.isLiteral() )  return null;
+    protected ReportItem validate(ValidationContext vCxt, Node n) {
+        if ( canBeIRI && n.isURI() )                return null;
+        if ( canBeBlankNode && n.isBlank() )        return null;
+        if ( canBeLiteral && n.isLiteral() )        return null;
+        if ( canBeTripleTerm && n.isTripleTerm() )  return null;
         String msg = toString()+" : Expected "+kind.getLocalName()+" for 
"+displayStr(n);
         return new ReportItem(msg, n);
     }
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/PatternConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/PatternConstraint.java
index 0e1b551bef..02088e026c 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/PatternConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/PatternConstraint.java
@@ -66,7 +66,7 @@ public class PatternConstraint extends ConstraintTerm {
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
+    protected ReportItem validate(ValidationContext vCxt, Node n) {
         if ( n.isBlank() ) {
             String msg = toString()+": Blank node: "+ShLib.displayStr(n);
             return new ReportItem(msg, n);
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ShXone.java 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ShXone.java
index 727e5824c0..a4c1670904 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ShXone.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ShXone.java
@@ -51,8 +51,9 @@ public class ShXone extends ConstraintOpN {
         int c = 0;
         for ( Shape sh : others ) {
             ValidationContext vCxt2 = ValidationContext.create(vCxt);
+            vCxt2.setVerbose(false);
             ValidationProc.execValidateShape(vCxt2, data, sh, node);
-            boolean innerConforms = vCxt2.generateReport().conforms();
+            boolean innerConforms = ! vCxt2.hasViolation();
             if ( innerConforms ) {
                 c++;
                 // Choice: count all vs break as soon as error detected
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrLanguageIn.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrLanguageIn.java
index c4d7167f9d..a7c139274d 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrLanguageIn.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrLanguageIn.java
@@ -47,7 +47,7 @@ public class StrLanguageIn extends ConstraintTerm {
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
+    protected ReportItem validate(ValidationContext vCxt, Node n) {
         if ( ! n.isLiteral() )
             return new ReportItem(toString()+": Not a literal",n);
         String langTag = n.getLiteralLanguage();
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrMaxLengthConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrMaxLengthConstraint.java
index 8c450ba8e0..4504448c81 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrMaxLengthConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrMaxLengthConstraint.java
@@ -49,7 +49,7 @@ public class StrMaxLengthConstraint extends ConstraintTerm {
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
+    protected ReportItem validate(ValidationContext vCxt, Node n) {
         if ( n.isBlank() ) {
             String msg = toString()+": Blank node: "+ShLib.displayStr(n);
             return new ReportItem(msg, n);
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrMinLengthConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrMinLengthConstraint.java
index c043ec9a48..ee77623dc3 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrMinLengthConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/StrMinLengthConstraint.java
@@ -49,7 +49,7 @@ public class StrMinLengthConstraint extends ConstraintTerm {
     }
 
     @Override
-    public ReportItem validate(ValidationContext vCxt, Node n) {
+    protected ReportItem validate(ValidationContext vCxt, Node n) {
         if ( n.isBlank() ) {
             String msg = toString()+": Blank node: "+ShLib.displayStr(n);
             return new ReportItem(msg, n);
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ValueRangeConstraint.java
 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ValueRangeConstraint.java
index da605c88a1..813d248181 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ValueRangeConstraint.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ValueRangeConstraint.java
@@ -51,7 +51,8 @@ public abstract class ValueRangeConstraint extends 
ConstraintTerm {
     }
 
     @Override
-    final public ReportItem validate(ValidationContext vCxt, Node n) {
+    protected
+    final ReportItem validate(ValidationContext vCxt, Node n) {
         NodeValue nv = NodeValue.makeNode(n);
         ValueSpace vs = NodeValue.classifyValueOp(nodeValue, nv);
         try {
diff --git 
a/jena-shacl/src/main/java/org/apache/jena/shacl/parser/ConstraintVisitor.java 
b/jena-shacl/src/main/java/org/apache/jena/shacl/parser/ConstraintVisitor.java
index 401879d29e..9a44b18a8d 100644
--- 
a/jena-shacl/src/main/java/org/apache/jena/shacl/parser/ConstraintVisitor.java
+++ 
b/jena-shacl/src/main/java/org/apache/jena/shacl/parser/ConstraintVisitor.java
@@ -55,6 +55,11 @@ public interface ConstraintVisitor {
     void visit(ConstraintComponentSPARQL constraint);
     void visit(SparqlConstraint constraint);
 
+    void visit(ListMemberShape constraint);
+    void visit(ListMinLength constraint);
+    void visit(ListMaxLength constraint);
+    void visit(ListUniqueMembers constraint);
+
     // Other Constraints
     void visit(JViolationConstraint constraint);
     void visit(JLogConstraint constraint);
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 24708af8d9..6e54e27d08 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
@@ -108,6 +108,11 @@ public class Constraints {
         dispatch.put( SHACL.in,                (g, s, p, o) -> new 
InConstraint(list(g,o)) );
         dispatch.put( SHACL.closed,            (g, s, p, o) -> new 
ClosedConstraint(g,s,booleanValue(o)) );
 
+        dispatch.put( SHACL.memberShape,       (g, s, p, o) -> new 
ListMemberShape(o));
+        dispatch.put( SHACL.minListLength,     (g, s, p, o) -> new 
ListMinLength(o));
+        dispatch.put( SHACL.maxListLength,     (g, s, p, o) -> new 
ListMaxLength(o));
+        dispatch.put( SHACL.uniqueMembers,     (g, s, p, o) -> new 
ListUniqueMembers(o));
+
         // Below
         //dispatch.put( SHACL.not,                (g, s, p, o) -> 
notImplemented(p) );
         //dispatch.put( SHACL.and,                (g, s, p, o) -> 
notImplemented(p) );
@@ -202,6 +207,10 @@ public class Constraints {
             Shape other = ShapesParser.parseShapeStep(traversed, parsed, g, o);
             if ( other instanceof PropertyShape )
                 throw new ShaclParseException("Object of sh:node must be a 
node shape, not a property shape");
+            if ( other == null ) {
+                System.err.print("sh:node - no such shape");
+                return null;
+            }
             return new ShNode(other);
         }
 
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 2975fb28d5..1dd769ed7d 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
@@ -29,6 +29,7 @@ import org.apache.jena.graph.NodeFactory;
 // Vocabulary for http://www.w3.org/ns/shacl#
 // schemagen then converted to Node level.
 // then add SHACL-AF
+// Then SHACL 1.2 added
 
 public class SHACL {
     private static Node createResource(String uri) { return 
NodeFactory.createURI(uri); }
@@ -231,6 +232,39 @@ public class SHACL {
     /** <p>Specifies the node kind (e.g. IRI or literal) each value node.</p> 
*/
     public static final Node nodeKind = createProperty( 
"http://www.w3.org/ns/shacl#nodeKind"; );
 
+    /** SHACL 1.2: sh:memberShape */
+    public static final Node memberShape = createProperty( 
"http://www.w3.org/ns/shacl#memberShape"; );
+
+    /** SHACL 1.2: minListLength */
+    public static final Node minListLength = createProperty( 
"http://www.w3.org/ns/shacl#minListLength"; );
+
+    /** SHACL 1.2: maxListLength */
+    public static final Node maxListLength = createProperty( 
"http://www.w3.org/ns/shacl#maxListLength"; );
+
+    /** SHACL 1.2: uniqueMembers */
+    public static final Node uniqueMembers = createProperty( 
"http://www.w3.org/ns/shacl#uniqueMembers"; );
+
+    /** <p>Node kind -- literal.</p> */
+    public static final Node Literal = createResource( 
"http://www.w3.org/ns/shacl#Literal"; );
+
+    /** <p>Node kind -- IRI.</p> */
+    public static final Node IRI = createResource( 
"http://www.w3.org/ns/shacl#IRI"; );
+
+    /** <p>Node kind -- blank node.</p> */
+    public static final Node BlankNode = createResource( 
"http://www.w3.org/ns/shacl#BlankNode"; );
+
+    /** <p>Node kind -- triple term</p> */
+    public static final Node TripleTerm = createResource( 
"http://www.w3.org/ns/shacl#TripleTerm"; );
+
+    /** <p>Node kind -- IRI or literal.</p> */
+    public static final Node IRIOrLiteral = createResource( 
"http://www.w3.org/ns/shacl#IRIOrLiteral"; );
+
+    /** <p>Node kind -- blank node or IRI.</p> */
+    public static final Node BlankNodeOrIRI = createResource( 
"http://www.w3.org/ns/shacl#BlankNodeOrIRI"; );
+
+    /** <p>Node kind -- blank nodes or literals.</p> */
+    public static final Node BlankNodeOrLiteral = createResource( 
"http://www.w3.org/ns/shacl#BlankNodeOrLiteral"; );
+
     /** <p>The validator(s) used to evaluate a constraint in the context of a 
node shape.</p> */
     public static final Node nodeValidator = createProperty( 
"http://www.w3.org/ns/shacl#nodeValidator"; );
 
@@ -430,15 +464,6 @@ public class SHACL {
 
     public static final Node AndConstraintComponent_and = createResource( 
"http://www.w3.org/ns/shacl#AndConstraintComponent-and"; );
 
-    /** <p>The node kind of all blank nodes.</p> */
-    public static final Node BlankNode = createResource( 
"http://www.w3.org/ns/shacl#BlankNode"; );
-
-    /** <p>The node kind of all blank nodes or IRIs.</p> */
-    public static final Node BlankNodeOrIRI = createResource( 
"http://www.w3.org/ns/shacl#BlankNodeOrIRI"; );
-
-    /** <p>The node kind of all blank nodes or literals.</p> */
-    public static final Node BlankNodeOrLiteral = createResource( 
"http://www.w3.org/ns/shacl#BlankNodeOrLiteral"; );
-
     /** <p>A constraint component that can be used to verify that each value 
node is
      *  an instance of a given type.</p>
      */
@@ -499,12 +524,6 @@ public class SHACL {
 
     public static final Node HasValueConstraintComponent_hasValue = 
createResource( 
"http://www.w3.org/ns/shacl#HasValueConstraintComponent-hasValue"; );
 
-    /** <p>The node kind of all IRIs.</p> */
-    public static final Node IRI = createResource( 
"http://www.w3.org/ns/shacl#IRI"; );
-
-    /** <p>The node kind of all IRIs or literals.</p> */
-    public static final Node IRIOrLiteral = createResource( 
"http://www.w3.org/ns/shacl#IRIOrLiteral"; );
-
     /** <p>A constraint component that can be used to exclusively enumerate 
the permitted
      *  value nodes.</p>
      */
@@ -575,9 +594,6 @@ public class SHACL {
 
     public static final Node 
LessThanOrEqualsConstraintComponent_lessThanOrEquals = createResource( 
"http://www.w3.org/ns/shacl#LessThanOrEqualsConstraintComponent-lessThanOrEquals";
 );
 
-    /** <p>The node kind of all literals.</p> */
-    public static final Node Literal = createResource( 
"http://www.w3.org/ns/shacl#Literal"; );
-
     /** <p>A constraint component that can be used to restrict the maximum 
number of
      *  value nodes.</p>
      */
@@ -653,6 +669,14 @@ public class SHACL {
 
     public static final Node NodeKindConstraintComponent_nodeKind = 
createResource( 
"http://www.w3.org/ns/shacl#NodeKindConstraintComponent-nodeKind"; );
 
+    public static final Node MemberShapeConstraintComponent = createResource( 
"http://www.w3.org/ns/shacl#MemberShapeConstraintComponent"; );
+
+    public static final Node ListMinLengthConstraintComponent = 
createResource( "http://www.w3.org/ns/shacl#ListMinLengthConstraintComponent"; );
+
+    public static final Node ListMaxLengthConstraintComponent = 
createResource( "http://www.w3.org/ns/shacl#ListMaxLengthConstraintComponent"; );
+
+    public static final Node UniqueMembersConstraintComponent = 
createResource( "http://www.w3.org/ns/shacl#UniqueMembersConstraintComponent"; );
+
     /** <p>A node shape is a shape that specifies constraint that need to be 
met with
      *  respect to focus nodes.</p>
      */


Reply via email to