diff --git a/shacl12-core/index.html b/shacl12-core/index.html
index 6aeb016e..91434c80 100644
--- a/shacl12-core/index.html
+++ b/shacl12-core/index.html
@@ -5899,6 +5899,7 @@
sh:xone
A SHACL list of shapes to validate the value nodes against.
Each value of sh:xone
in a shape is a SHACL list.
Each member of such list must be a well-formed shape.
+ There should be at least one member of such list.
@@ -7299,6 +7300,7 @@ sh:in
A SHACL list that has the allowed values as members.
Each value of sh:in
in a shape is a SHACL list.
A shape has at most one value for sh:in
.
+ There should be at least one member of such list.
diff --git a/shacl12-test-suite/tests/core/node/in-002.ttl b/shacl12-test-suite/tests/core/node/in-002.ttl
new file mode 100644
index 00000000..7b55364f
--- /dev/null
+++ b/shacl12-test-suite/tests/core/node/in-002.ttl
@@ -0,0 +1,46 @@
+@prefix ex: .
+@prefix mf: .
+@prefix owl: .
+@prefix rdf: .
+@prefix rdfs: .
+@prefix sh: .
+@prefix sht: .
+@prefix xsd: .
+
+ex:Instance
+ rdf:type ex:TestShape ;
+.
+ex:TestInUnsatisfiableShape
+ rdf:type rdfs:Class ;
+ rdf:type sh:NodeShape ;
+ rdfs:comment "Unsatisfiable due to empty sh:in list. SHACL-SHACL would raise a warning about the empty list."@en ;
+ rdfs:label "Test shape" ;
+ sh:in () ;
+.
+<>
+ rdf:type mf:Manifest ;
+ mf:entries (
+
+ ) ;
+.
+
+ rdf:type sht:Validate ;
+ rdfs:label "Test of sh:in at node shape 002" ;
+ mf:action [
+ sht:dataGraph <> ;
+ sht:shapesGraph <> ;
+ ] ;
+ mf:result [
+ rdf:type sh:ValidationReport ;
+ sh:conforms "false"^^xsd:boolean ;
+ sh:result [
+ rdf:type sh:ValidationResult ;
+ sh:focusNode ex:Instance ;
+ sh:resultSeverity sh:Violation ;
+ sh:sourceConstraintComponent sh:InConstraintComponent ;
+ sh:sourceShape ex:TestShape ;
+ sh:value ex:Instance ;
+ ] ;
+ ] ;
+ mf:status sht:approved ;
+.
diff --git a/shacl12-test-suite/tests/core/node/in-003.ttl b/shacl12-test-suite/tests/core/node/in-003.ttl
new file mode 100644
index 00000000..0f9def74
--- /dev/null
+++ b/shacl12-test-suite/tests/core/node/in-003.ttl
@@ -0,0 +1,55 @@
+@prefix ex: .
+@prefix mf: .
+@prefix owl: .
+@prefix rdf: .
+@prefix rdfs: .
+@prefix sh: .
+@prefix sht: .
+@prefix xsd: .
+
+ex:TestInUnsatisfiableShape
+ rdf:type rdfs:Class ;
+ rdf:type sh:NodeShape ;
+ rdfs:label "Test shape" ;
+ sh:in rdf:nil ;
+.
+shsh:inSubjectsShape
+ a sh:NodeShape ;
+ rdfs:isDefinedBy shsh: ;
+ sh:property shsh:inSubjectsShapeXonePropertyShape ;
+ sh:targetSubjectsOf sh:in ;
+ .
+shsh:inSubjectsShapeInPropertyShape
+ a sh:PropertyShape ;
+ rdfs:isDefinedBy shsh: ;
+ sh:path sh:in ;
+ sh:minListLength 1 ;
+ sh:severity sh:Warning ;
+ .
+<>
+ rdf:type mf:Manifest ;
+ mf:entries (
+
+ ) ;
+.
+
+ rdf:type sht:Validate ;
+ rdfs:label "Test of sh:in at node shape 003" ;
+ mf:action [
+ sht:dataGraph <> ;
+ sht:shapesGraph <> ;
+ ] ;
+ mf:result [
+ rdf:type sh:ValidationReport ;
+ sh:conforms "false"^^xsd:boolean ;
+ sh:result [
+ rdf:type sh:ValidationResult ;
+ sh:focusNode ex:TestInUnsatisfiableShape ;
+ sh:resultSeverity sh:Warning ;
+ sh:sourceConstraintComponent sh:MinListLengthConstraintComponent ;
+ sh:sourceShape shsh:inSubjectsShapeInPropertyShape ;
+ sh:value rdf:nil ;
+ ] ;
+ ] ;
+ mf:status sht:approved ;
+.
diff --git a/shacl12-test-suite/tests/core/node/xone-002.ttl b/shacl12-test-suite/tests/core/node/xone-002.ttl
new file mode 100644
index 00000000..d17f8db1
--- /dev/null
+++ b/shacl12-test-suite/tests/core/node/xone-002.ttl
@@ -0,0 +1,45 @@
+@prefix ex: .
+@prefix mf: .
+@prefix owl: .
+@prefix rdf: .
+@prefix rdfs: .
+@prefix sh: .
+@prefix sht: .
+@prefix xsd: .
+
+ex:Bob
+ rdf:type ex:Person ;
+.
+ex:TestXoneUnsatisfiableShape
+ rdf:type sh:NodeShape ;
+ rdfs:comment "Unsatisfiable due to empty sh:xone list. SHACL-SHACL would raise a warning about the empty list."@en ;
+ sh:targetClass ex:Person ;
+ sh:xone () ;
+.
+<>
+ rdf:type mf:Manifest ;
+ mf:entries (
+
+ ) ;
+.
+
+ rdf:type sht:Validate ;
+ rdfs:label "Test of sh:xone at node shape 002" ;
+ mf:action [
+ sht:dataGraph <> ;
+ sht:shapesGraph <> ;
+ ] ;
+ mf:result [
+ rdf:type sh:ValidationReport ;
+ sh:conforms "false"^^xsd:boolean ;
+ sh:result [
+ rdf:type sh:ValidationResult ;
+ sh:focusNode ex:Bob ;
+ sh:resultSeverity sh:Violation ;
+ sh:sourceConstraintComponent sh:XoneConstraintComponent ;
+ sh:sourceShape ex:TestXoneUnsatisfiableShape ;
+ sh:value ex:Bob ;
+ ] ;
+ ] ;
+ mf:status sht:approved ;
+.
diff --git a/shacl12-test-suite/tests/core/node/xone-003.ttl b/shacl12-test-suite/tests/core/node/xone-003.ttl
new file mode 100644
index 00000000..f2932671
--- /dev/null
+++ b/shacl12-test-suite/tests/core/node/xone-003.ttl
@@ -0,0 +1,55 @@
+@prefix ex: .
+@prefix mf: .
+@prefix owl: .
+@prefix rdf: .
+@prefix rdfs: .
+@prefix sh: .
+@prefix shsh: .
+@prefix sht: .
+@prefix xsd: .
+
+ex:TestXoneUnsatisfiableShape
+ rdf:type sh:NodeShape ;
+ sh:targetClass ex:Person ;
+ sh:xone rdf:nil ;
+.
+shsh:xoneSubjectsShape
+ a sh:NodeShape ;
+ rdfs:isDefinedBy shsh: ;
+ sh:property shsh:xoneSubjectsShapeXonePropertyShape ;
+ sh:targetSubjectsOf sh:xone ;
+ .
+shsh:xoneSubjectsShapeXonePropertyShape
+ a sh:PropertyShape ;
+ rdfs:isDefinedBy shsh: ;
+ sh:path sh:xone ;
+ sh:minListLength 1 ;
+ sh:severity sh:Warning ;
+ .
+<>
+ rdf:type mf:Manifest ;
+ mf:entries (
+
+ ) ;
+.
+
+ rdf:type sht:Validate ;
+ rdfs:label "Test of sh:xone at node shape 003" ;
+ mf:action [
+ sht:dataGraph <> ;
+ sht:shapesGraph <> ;
+ ] ;
+ mf:result [
+ rdf:type sh:ValidationReport ;
+ sh:conforms "false"^^xsd:boolean ;
+ sh:result [
+ rdf:type sh:ValidationResult ;
+ sh:focusNode ex:TestXoneUnsatisfiableShape ;
+ sh:resultSeverity sh:Warning ;
+ sh:sourceConstraintComponent sh:MinListLengthConstraintComponent ;
+ sh:sourceShape shsh:xoneSubjectsShapeXonePropertyShape ;
+ sh:value rdf:nil ;
+ ] ;
+ ] ;
+ mf:status sht:approved ;
+.
diff --git a/shacl12-vocabularies/shacl-shacl.ttl b/shacl12-vocabularies/shacl-shacl.ttl
index 31f7e7a5..882e56f2 100644
--- a/shacl12-vocabularies/shacl-shacl.ttl
+++ b/shacl12-vocabularies/shacl-shacl.ttl
@@ -164,7 +164,6 @@ shsh:ShapeShape
sh:property [
sh:path sh:in ;
sh:maxCount 1 ; # in-maxCount
- sh:minListLength 1 ; # in-minListLength
] ;
sh:property [
sh:path sh:languageIn ;
@@ -294,7 +293,7 @@ shsh:ShapeShape
] ;
sh:property [
sh:path sh:xone ;
- sh:memberShape shsh:ShapeShape ; # xone-memberShape
+ sh:memberShape shsh:ShapeShape ; # xone-members-node
] .
shsh:NodeShapeShape
@@ -347,6 +346,35 @@ shsh:ShapesListShape
sh:targetObjectsOf sh:xone ; # xone-members-node
sh:memberShape shsh:ShapeShape .
+# Values of sh:in and sh:xone should have length >= 1.
+shsh:inSubjectsShape
+ a sh:NodeShape ;
+ rdfs:comment "A shape that raises warnings on unsatisfiable lists. If some use case requires a length-0 list on 'sh:in', this graph should be supplemented with 'shsh:inSubjectsShape sh:deactivated true .'."@en ;
+ sh:property shsh:inSubjectsShapeInPropertyShape ;
+ sh:targetSubjectsOf sh:in ;
+ .
+
+shsh:inSubjectsShapeInPropertyShape
+ a sh:PropertyShape ;
+ sh:path sh:in ;
+ sh:minListLength 1 ; # in-minListLength
+ sh:severity sh:Warning ;
+ .
+
+shsh:xoneSubjectsShape
+ a sh:NodeShape ;
+ rdfs:comment "A shape that raises warnings on unsatisfiable lists. If some use case requires a length-0 list on 'sh:xone', this graph should be supplemented with 'shsh:xoneSubjectsShape sh:deactivated true .'."@en ;
+ sh:property shsh:xoneSubjectsShapeXonePropertyShape ;
+ sh:targetSubjectsOf sh:xone ;
+ .
+
+shsh:xoneSubjectsShapeXonePropertyShape
+ a sh:PropertyShape ;
+ sh:path sh:xone ;
+ sh:minListLength 1 ; # xone-minListLength
+ sh:severity sh:Warning ;
+ .
+
# A path of blank node path syntax, used to simulate recursion
_:PathPath
sh:alternativePath (