diff --git a/shacl12-core/index.html b/shacl12-core/index.html index 0c130e0d..5b7de87b 100644 --- a/shacl12-core/index.html +++ b/shacl12-core/index.html @@ -2751,7 +2751,7 @@

Handling of Ill-formed Shapes Graphs

Handling of Recursive Shapes

-

+

The following properties are the so-called shape-expecting constraint parameters in SHACL Core:

@@ -2810,7 +2814,7 @@

Conformance Checking

conforms to a given shape, and false otherwise.

- Note that some constraint components of SHACL Core (e.g., those of sh:not, sh:or and sh:node) + Note that all shape-expecting constraint parameters of SHACL Core rely on conformance checking. In these cases, the validation results used to determine the outcome of conformance checking are separated from those of the surrounding validation process and typically do not end up in the same validation report @@ -4516,6 +4520,462 @@

sh:uniqueLang

+
+

List Constraint Components

+

+ The constraint components in this section apply to value nodes that are SHACL lists. + They specify conditions on the structure, length, and members of SHACL lists. +

+ +
+

sh:memberShape

+

+ sh:memberShape specifies that all members of SHACL list value nodes must conform to the given node shape. +

+

+ Constraint Component IRI: sh:MemberShapeConstraintComponent +

+ +
Parameters:
+ + + + + + + + + +
PropertySummary and Syntax Rules
sh:memberShape + The shape that all members of the SHACL list must conform to. + The value of sh:memberShape must be a well-formed node shape. +
+
+
TEXTUAL DEFINITION
+
+ Let $memberShape be a parameter value for sh:memberShape. + Each value node v must be a SHACL list - if v is not a SHACL list there is a validation result. + If any member m of the SHACL list v does not conform to $memberShape, there is a validation result. +
+
+

The remainder of this section is informative.

+

+ Each member m of a value node v that does not conform to the $memberShape should be reported as a separate sh:detail in the validation result for v. + If v is not a valid SHACL list, this should be reported as a top-level validation result and validation of individual members should not be attempted. +

+

+ Examples of how to generate sh:details in validation results can be found in the test cases for sh:memberShape in the SHACL test suite: memberShape-001.ttl. +

+

+ In the following example, all values of the property ex:speakerOrder must be SHACL lists with members that are IRIs. +

+ +
+ +
+

sh:minListLength

+

+ sh:minListLength specifies the minimum number of members that SHACL list value nodes must have. +

+

+ Constraint Component IRI: sh:MinListLengthConstraintComponent +

+ +
Parameters:
+ + + + + + + + + +
PropertySummary and Syntax Rules
sh:minListLength + The minimum number of members in the SHACL list. + The values of sh:minListLength in a shape are literals with datatype xsd:integer. + The values of sh:minListLength in a shape are integers greater than or equal to 0. +
+
+
TEXTUAL DEFINITION
+
+ Let $minListLength be a parameter value for sh:minListLength. + Each value node v must be a SHACL list - if v is not a SHACL list there is a validation result. + If the number of members in a list v is less than $minListLength, + there is a validation result. +
+
+

The remainder of this section is informative.

+

+ In the following example, all values of the property ex:skills must be SHACL lists with at least 1 member. + Additional test cases for sh:minListLength can be found in the SHACL test suite: minListLength-001.ttl. +

+ +
+ +
+

sh:maxListLength

+

+ sh:maxListLength specifies the maximum number of members that SHACL list value nodes must have. +

+

+ Constraint Component IRI: sh:MaxListLengthConstraintComponent +

+ +
Parameters:
+ + + + + + + + + +
PropertySummary and Syntax Rules
sh:maxListLength + The maximum number of members in the SHACL list. + The values of sh:maxListLength in a shape are literals with datatype xsd:integer. + The values of sh:maxListLength in a shape are integers greater than or equal to 0. +
+
+
TEXTUAL DEFINITION
+
+ Let $maxListLength be a parameter value for sh:maxListLength. + Each value node v must be a SHACL list - if v is not a SHACL list there is a validation result. + If the number of members in the list v is greater than $maxListLength, + there is a validation result. +
+
+

The remainder of this section is informative.

+

+ In the following example, all values of the property ex:hobbies must be SHACL lists with at most 2 members. + Additional test cases for sh:maxListLength can be found in the SHACL test suite: maxListLength-001.ttl. +

+ +
+ +
+

sh:uniqueMembers

+

+ sh:uniqueMembers specifies whether SHACL list value nodes must have unique members. +

+

+ Constraint Component IRI: sh:UniqueMembersConstraintComponent +

+ +
Parameters:
+ + + + + + + + + +
PropertySummary and Syntax Rules
sh:uniqueMembers + A boolean that specifies whether the members of the SHACL list must be unique. + The values of sh:uniqueMembers in a shape are literals with datatype xsd:boolean. +
+
+
TEXTUAL DEFINITION
+
+ Let $uniqueMembers be a parameter value for sh:uniqueMembers. + Each value node v must be a SHACL list - if v is not a SHACL list there is a validation result. + If $uniqueMembers is true and the list v has duplicate members, + there is a validation result. +
+
+

The remainder of this section is informative.

+

+ Each duplicate member m of a list v should be reported as a separate sh:detail in the validation result for v. If the list v is not a valid SHACL list, this should be reported as a top-level validation result and validation of unique membership should not be attempted. +

+

+ Examples of how to generate sh:details in validation results can be found in the test cases for sh:uniqueMembers in the SHACL test suite: uniqueMembers-001.ttl. +

+

+ In the following example, all values of the property ex:preferences must be SHACL lists with members that have unique values within each SHACL list. +

+ +
+
+

Property Pair Constraint Components

diff --git a/shacl12-test-suite/tests/core/node/manifest.ttl b/shacl12-test-suite/tests/core/node/manifest.ttl index 59b174b3..4cb49515 100644 --- a/shacl12-test-suite/tests/core/node/manifest.ttl +++ b/shacl12-test-suite/tests/core/node/manifest.ttl @@ -26,11 +26,14 @@ mf:include ; mf:include ; mf:include ; + mf:include ; + mf:include ; mf:include ; mf:include ; mf:include ; mf:include ; mf:include ; + mf:include ; mf:include ; mf:include ; mf:include ; @@ -40,6 +43,7 @@ mf:include ; mf:include ; mf:include ; + mf:include ; mf:include ; mf:include ; mf:include ; diff --git a/shacl12-test-suite/tests/core/node/maxListLength-001.ttl b/shacl12-test-suite/tests/core/node/maxListLength-001.ttl new file mode 100644 index 00000000..5e412494 --- /dev/null +++ b/shacl12-test-suite/tests/core/node/maxListLength-001.ttl @@ -0,0 +1,63 @@ +@prefix dash: . +@prefix ex: . +@prefix mf: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix sht: . +@prefix xsd: . + +ex:ListShape + rdf:type sh:NodeShape ; + sh:maxListLength 2 ; + # Satisfies all constraints + sh:targetNode ex:list0, rdf:nil ; + # Violates maxListLength constraint + sh:targetNode ex:list1, ex:notAList ; +. + +ex:list0 + rdf:first 1 ; + rdf:rest ( 2 ) . + +ex:list1 + rdf:first 1 ; + rdf:rest ( 2 3 ) . + +<> + rdf:type mf:Manifest ; + mf:entries ( + + ) ; +. + + + rdf:type sht:Validate ; + rdfs:label "Test of sh:maxListLength on node shape 001" ; + 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:list1 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MaxListLengthConstraintComponent ; + sh:sourceShape ex:ListShape ; + sh:value ex:list1 ; + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:notAList ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MaxListLengthConstraintComponent ; + sh:sourceShape ex:ListShape ; + sh:value ex:notAList ; + ] ; + ] ; + mf:status sht:approved ; +. diff --git a/shacl12-test-suite/tests/core/node/memberShape-001.ttl b/shacl12-test-suite/tests/core/node/memberShape-001.ttl new file mode 100644 index 00000000..bb251f2b --- /dev/null +++ b/shacl12-test-suite/tests/core/node/memberShape-001.ttl @@ -0,0 +1,174 @@ +@prefix dash: . +@prefix ex: . +@prefix mf: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix sht: . +@prefix xsd: . + +ex:IRIShape a sh:NodeShape ; + sh:nodeKind sh:IRI . + +ex:IRIListShape + rdf:type sh:NodeShape ; + sh:memberShape ex:IRIShape ; + sh:targetNode ex:list0 ; + # Valid empty list + sh:targetNode rdf:nil ; + # ex:list1 is valid, the remainder trigger violations (including ex:list3 which has no properties in this graph) + sh:targetNode ex:list1, ex:list2, ex:list3, ex:list4, ex:list5, ex:list6, ex:list7, ex:list9 ; +. + +ex:list0 + rdf:first ex:Alice ; + rdf:rest ( + ex:Bob + ) ; +. + +ex:list1 + rdf:first ex:Alice ; + rdf:rest rdf:nil ; + ex:extraProperty "extra" ; +. + +ex:list2 + rdf:first ex:Alice ; + rdf:rest ( + "Bob" + ) +. + +ex:list4 + rdf:first ex:Alice ; +. + +ex:list5 + rdf:first "Charlie" ; + rdf:rest ( + "Donna" + ) +. + +ex:list6 + rdf:first "Charlie" ; +. + +ex:list8 rdfs:label "Malformed SHACL List" . + +ex:list7 + rdf:first "Charlie" ; + rdf:rest ex:list8 ; +. + +# using ex:list9 and ex:list10 to test recursive list error +ex:list9 + rdf:first ex:Alice ; + rdf:rest ex:list10 ; +. + +ex:list10 + rdf:first "Bob" ; + rdf:rest ex:list9 . + +<> + rdf:type mf:Manifest ; + mf:entries ( + + ) ; +. + + + rdf:type sht:Validate ; + rdfs:label "Test of sh:memberShape on node shape 001" ; + 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:list2 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MemberShapeConstraintComponent ; + sh:sourceShape ex:IRIListShape ; + sh:value ex:list2 ; + sh:detail [ + rdf:type sh:ValidationResult ; + sh:focusNode "Bob" ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:NodeKindConstraintComponent ; + sh:sourceShape ex:IRIShape ; + sh:value "Bob" ; + ] ; + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:list3 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MemberShapeConstraintComponent ; + sh:sourceShape ex:IRIListShape ; + sh:value ex:list3 ; + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:list4 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MemberShapeConstraintComponent ; + sh:sourceShape ex:IRIListShape ; + sh:value ex:list4 ; + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:list5 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MemberShapeConstraintComponent ; + sh:sourceShape ex:IRIListShape ; + sh:value ex:list5 ; + sh:detail [ + rdf:type sh:ValidationResult ; + sh:focusNode "Charlie" ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:NodeKindConstraintComponent ; + sh:sourceShape ex:IRIShape ; + sh:value "Charlie" ; + ], [ + rdf:type sh:ValidationResult ; + sh:focusNode "Donna" ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:NodeKindConstraintComponent ; + sh:sourceShape ex:IRIShape ; + sh:value "Donna" ; + ] + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:list6 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MemberShapeConstraintComponent ; + sh:sourceShape ex:IRIListShape ; + sh:value ex:list6 ; + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:list7 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MemberShapeConstraintComponent ; + sh:sourceShape ex:IRIListShape ; + sh:value ex:list7 ; + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:list9 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MemberShapeConstraintComponent ; + sh:sourceShape ex:IRIListShape ; + sh:value ex:list9 ; + ] ; + ] ; + mf:status sht:approved ; +. diff --git a/shacl12-test-suite/tests/core/node/minListLength-001.ttl b/shacl12-test-suite/tests/core/node/minListLength-001.ttl new file mode 100644 index 00000000..5b38bf2f --- /dev/null +++ b/shacl12-test-suite/tests/core/node/minListLength-001.ttl @@ -0,0 +1,59 @@ +@prefix dash: . +@prefix ex: . +@prefix mf: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix sht: . +@prefix xsd: . + +ex:ListShape + rdf:type sh:NodeShape ; + sh:minListLength 1 ; + # Satisfies all constraints + sh:targetNode ex:list0 ; + # Violates minListLength constraint + sh:targetNode rdf:nil, ex:notAList ; +. + +ex:list0 + rdf:first 1 ; + rdf:rest ( 2 ) . + +<> + rdf:type mf:Manifest ; + mf:entries ( + + ) ; +. + + + rdf:type sht:Validate ; + rdfs:label "Test of sh:minListLength on node shape 001" ; + 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 rdf:nil ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MinListLengthConstraintComponent ; + sh:sourceShape ex:ListShape ; + sh:value rdf:nil ; + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:notAList ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MinListLengthConstraintComponent ; + sh:sourceShape ex:ListShape ; + sh:value ex:notAList ; + ] ; + ] ; + mf:status sht:approved ; +. diff --git a/shacl12-test-suite/tests/core/node/uniqueMembers-001.ttl b/shacl12-test-suite/tests/core/node/uniqueMembers-001.ttl new file mode 100644 index 00000000..bc2790dc --- /dev/null +++ b/shacl12-test-suite/tests/core/node/uniqueMembers-001.ttl @@ -0,0 +1,78 @@ +@prefix dash: . +@prefix ex: . +@prefix mf: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix sht: . +@prefix xsd: . + +ex:ListShape + rdf:type sh:NodeShape ; + sh:uniqueMembers true ; + # Satisfies all constraints + sh:targetNode ex:list0, rdf:nil ; + # Violates uniqueMembers constraint + sh:targetNode ex:list1, ex:notAList ; +. + +ex:list0 + rdf:first 1 ; + rdf:rest ( 2 ) . + +ex:list1 + rdf:first 1 ; + rdf:rest ( 2 1 2 2 ) . + +<> + rdf:type mf:Manifest ; + mf:entries ( + + ) ; +. + + + rdf:type sht:Validate ; + rdfs:label "Test of sh:uniqueMembers on node shape 001" ; + 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:list1 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:UniqueMembersConstraintComponent ; + sh:sourceShape ex:ListShape ; + sh:value ex:list1 ; + sh:detail [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:list1 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:UniqueMembersConstraintComponent ; + sh:sourceShape ex:ListShape ; + sh:value 1 ; + ], [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:list1 ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:UniqueMembersConstraintComponent ; + sh:sourceShape ex:ListShape ; + sh:value 2 ; + ] + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:notAList ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:UniqueMembersConstraintComponent ; + sh:sourceShape ex:ListShape ; + sh:value ex:notAList ; + ] ; + ] ; + mf:status sht:approved ; +. diff --git a/shacl12-test-suite/tests/core/property/manifest.ttl b/shacl12-test-suite/tests/core/property/manifest.ttl index 2ab26040..a0c3e724 100644 --- a/shacl12-test-suite/tests/core/property/manifest.ttl +++ b/shacl12-test-suite/tests/core/property/manifest.ttl @@ -26,11 +26,14 @@ mf:include ; mf:include ; mf:include ; + mf:include ; + mf:include ; mf:include ; mf:include ; mf:include ; mf:include ; mf:include ; + mf:include ; mf:include ; mf:include ; mf:include ; @@ -46,4 +49,5 @@ mf:include ; mf:include ; mf:include ; + mf:include ; . \ No newline at end of file diff --git a/shacl12-test-suite/tests/core/property/maxListLength-001.ttl b/shacl12-test-suite/tests/core/property/maxListLength-001.ttl new file mode 100644 index 00000000..6b98001b --- /dev/null +++ b/shacl12-test-suite/tests/core/property/maxListLength-001.ttl @@ -0,0 +1,86 @@ +@prefix dash: . +@prefix ex: . +@prefix mf: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix sht: . +@prefix xsd: . + +ex:PersonShape + rdf:type sh:NodeShape ; + sh:targetClass ex:Person ; + sh:property ex:PersonShape-hobbies ; +. + +ex:PersonShape-hobbies + rdf:type sh:PropertyShape ; + sh:path ex:hobbies ; + sh:maxListLength 2 ; +. + +# Satisfies all constraints +ex:person1 + rdf:type ex:Person ; + ex:hobbies ( "reading" "writing" ) ; +. + +ex:person2 + rdf:type ex:Person ; + ex:hobbies rdf:nil ; +. + +# Violates maxListLength constraint +ex:person3 + rdf:type ex:Person ; + ex:hobbies _:b1 ; +. + +ex:person4 + rdf:type ex:Person ; + ex:hobbies ex:notAList ; +. + +_:b1 + rdf:first "reading" ; + rdf:rest ( "writing" "swimming" ) . + +<> + rdf:type mf:Manifest ; + mf:entries ( + + ) ; +. + + + rdf:type sht:Validate ; + rdfs:label "Test of sh:maxListLength on property shape 001" ; + 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:person3 ; + sh:resultPath ex:hobbies ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MaxListLengthConstraintComponent ; + sh:sourceShape ex:PersonShape-hobbies ; + sh:value _:b1 ; + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:person4 ; + sh:resultPath ex:hobbies ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MaxListLengthConstraintComponent ; + sh:sourceShape ex:PersonShape-hobbies ; + sh:value ex:notAList ; + ] ; + ] ; + mf:status sht:approved ; +. diff --git a/shacl12-test-suite/tests/core/property/memberShape-001.ttl b/shacl12-test-suite/tests/core/property/memberShape-001.ttl new file mode 100644 index 00000000..f525f1ec --- /dev/null +++ b/shacl12-test-suite/tests/core/property/memberShape-001.ttl @@ -0,0 +1,87 @@ +@prefix dash: . +@prefix ex: . +@prefix mf: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix sht: . +@prefix xsd: . + +ex:IRIShape a sh:NodeShape ; + sh:nodeKind sh:IRI . + +ex:TestShape + rdf:type sh:NodeShape ; + sh:targetClass ex:ListSubject ; + sh:property ex:TestShape-testProperty ; +. + +ex:TestShape-testProperty + sh:path ex:testProperty ; + sh:memberShape ex:IRIShape ; +. + +# Valid with all IRIs in the list +ex:list1 + rdf:type ex:ListSubject ; + ex:testProperty ( + ex:Alice + ex:Bob + ex:Charlie + ) ; +. + +_:bc rdfs:label "Blank node which triggers violation" . + +# Invalid with a blank node in the list +ex:list2 + rdfs:label "List with a blank node" ; + rdf:type ex:ListSubject ; + ex:testProperty _:b1 ; +. + +_:b1 + rdf:first ex:Bob ; + rdf:rest ( + _:bc + ) +. + +<> + rdf:type mf:Manifest ; + mf:entries ( + + ) ; +. + + + rdf:type sht:Validate ; + rdfs:label "Test of sh:memberShape at property shape 001" ; + 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:list2 ; + sh:resultPath ex:testProperty ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MemberShapeConstraintComponent ; + sh:sourceShape ex:TestShape-testProperty ; + sh:value _:b1 ; + sh:detail [ + rdf:type sh:ValidationResult ; + sh:focusNode _:bc ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:NodeKindConstraintComponent ; + sh:sourceShape ex:IRIShape ; + sh:value _:bc ; + ] ; + ] ; + ] ; + mf:status sht:approved ; +. diff --git a/shacl12-test-suite/tests/core/property/minListLength-001.ttl b/shacl12-test-suite/tests/core/property/minListLength-001.ttl new file mode 100644 index 00000000..ebe5bf8a --- /dev/null +++ b/shacl12-test-suite/tests/core/property/minListLength-001.ttl @@ -0,0 +1,80 @@ +@prefix dash: . +@prefix ex: . +@prefix mf: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix sht: . +@prefix xsd: . + +ex:PersonShape + rdf:type sh:NodeShape ; + sh:targetClass ex:Person ; + sh:property [ + sh:path ex:skills ; + sh:minListLength 1 ; + ] ; +. + +ex:PersonShape-skills + rdf:type sh:PropertyShape ; + sh:path ex:skills ; + sh:minListLength 1 ; +. + +# Satisfies all constraints +ex:person1 + rdf:type ex:Person ; + ex:skills ( "programming" "design" ) ; +. + +# Violates minListLength constraint +ex:person2 + rdf:type ex:Person ; + ex:skills rdf:nil ; +. + +ex:person3 + rdf:type ex:Person ; + ex:skills ex:notAList ; +. + +<> + rdf:type mf:Manifest ; + mf:entries ( + + ) ; +. + + + rdf:type sht:Validate ; + rdfs:label "Test of sh:minListLength on property shape 001" ; + 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:person2 ; + sh:resultPath ex:skills ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MinListLengthConstraintComponent ; + sh:sourceShape ex:PersonShape-skills ; + sh:value rdf:nil ; + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:person3 ; + sh:resultPath ex:skills ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:MinListLengthConstraintComponent ; + sh:sourceShape ex:PersonShape-skills ; + sh:value ex:notAList ; + ] ; + ] ; + mf:status sht:approved ; +. diff --git a/shacl12-test-suite/tests/core/property/uniqueMembers-001.ttl b/shacl12-test-suite/tests/core/property/uniqueMembers-001.ttl new file mode 100644 index 00000000..2f77226a --- /dev/null +++ b/shacl12-test-suite/tests/core/property/uniqueMembers-001.ttl @@ -0,0 +1,104 @@ +@prefix dash: . +@prefix ex: . +@prefix mf: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix sht: . +@prefix xsd: . + +ex:PersonShape + rdf:type sh:NodeShape ; + sh:targetClass ex:Person ; + sh:property ex:PersonShape-preferences + ; +. + +ex:PersonShape-preferences + rdf:type sh:PropertyShape ; + sh:path ex:preferences ; + sh:uniqueMembers true ; +. + +# Satisfies all constraints +ex:person1 + rdf:type ex:Person ; + ex:preferences ( "coffee" "tea" ) ; +. + +ex:person2 + rdf:type ex:Person ; + ex:preferences rdf:nil ; +. + +# Violates uniqueMembers constraint +ex:person3 + rdf:type ex:Person ; + ex:preferences _:b1 ; +. + +ex:person4 + rdf:type ex:Person ; + ex:preferences ex:notAList ; +. + +_:b1 + rdf:first "coffee" ; + rdf:rest ( "tea" "coffee" "tea" "tea" ) . + +<> + rdf:type mf:Manifest ; + mf:entries ( + + ) ; +. + + + rdf:type sht:Validate ; + rdfs:label "Test of sh:uniqueMembers on property shape 001" ; + 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:person3 ; + sh:resultPath ex:preferences ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:UniqueMembersConstraintComponent ; + sh:sourceShape ex:PersonShape-preferences ; + sh:value _:b1 ; + sh:detail [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:person3 ; + sh:resultPath ex:preferences ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:UniqueMembersConstraintComponent ; + sh:sourceShape ex:PersonShape-preferences ; + sh:value "coffee" ; + ], [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:person3 ; + sh:resultPath ex:preferences ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:UniqueMembersConstraintComponent ; + sh:sourceShape ex:PersonShape-preferences ; + sh:value "tea" ; + ] + ] ; + sh:result [ + rdf:type sh:ValidationResult ; + sh:focusNode ex:person4 ; + sh:resultPath ex:preferences ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:UniqueMembersConstraintComponent ; + sh:sourceShape ex:PersonShape-preferences ; + sh:value ex:notAList ; + ] ; + ] ; + mf:status sht:approved ; +. diff --git a/shacl12-vocabularies/shacl-shacl.ttl b/shacl12-vocabularies/shacl-shacl.ttl index 043cccbb..0c808319 100644 --- a/shacl12-vocabularies/shacl-shacl.ttl +++ b/shacl12-vocabularies/shacl-shacl.ttl @@ -72,10 +72,12 @@ shsh:ShapeShape sh:targetSubjectsOf sh:targetClass, sh:targetNode, sh:targetObjectsOf, sh:targetSubjectsOf ; sh:targetSubjectsOf sh:and, sh:class, sh:closed, sh:datatype, sh:disjoint, sh:equals, sh:flags, sh:hasValue, sh:ignoredProperties, sh:in, sh:languageIn, sh:lessThan, sh:lessThanOrEquals, sh:maxCount, sh:maxExclusive, - sh:maxInclusive, sh:maxLength, sh:minCount, sh:minExclusive, sh:minInclusive, sh:minLength, sh:node, sh:nodeKind, + sh:maxInclusive, sh:maxLength, sh:memberShape, sh:minCount, sh:minExclusive, sh:minInclusive, sh:minLength, sh:node, sh:nodeKind, sh:not, sh:or, sh:pattern, sh:property, sh:qualifiedMaxCount, sh:qualifiedMinCount, sh:qualifiedValueShape, - sh:qualifiedValueShape, sh:qualifiedValueShapesDisjoint, sh:qualifiedValueShapesDisjoint, sh:uniqueLang, sh:xone ; + sh:qualifiedValueShape, sh:qualifiedValueShapesDisjoint, sh:qualifiedValueShapesDisjoint, sh:uniqueLang, sh:xone , + sh:minListLength, sh:maxListLength, sh:uniqueMembers ; + sh:targetObjectsOf sh:memberShape ; # memberShape-node sh:targetObjectsOf sh:node ; # node-node sh:targetObjectsOf sh:not ; # not-node sh:targetObjectsOf sh:property ; # property-node @@ -223,6 +225,27 @@ shsh:ShapeShape sh:maxCount 1 ; # minLength-maxCount sh:minInclusive 0 ; # minLength-minInclusive ] ; + sh:property [ + sh:path sh:memberShape ; + sh:node shsh:NodeShapeShape ; # memberShape-node + ] ; + sh:property [ + sh:path sh:minListLength ; + sh:datatype xsd:integer ; # minListLength-datatype + sh:maxCount 1 ; # minListLength-maxCount + sh:minInclusive 0 ; # minListLength-minInclusive + ] ; + sh:property [ + sh:path sh:maxListLength ; + sh:datatype xsd:integer ; # maxListLength-datatype + sh:maxCount 1 ; # maxListLength-maxCount + sh:minInclusive 0 ; # maxListLength-minInclusive + ] ; + sh:property [ + sh:path sh:uniqueMembers ; + sh:datatype xsd:boolean ; # uniqueMembers-datatype + sh:maxCount 1 ; # uniqueMembers-maxCount + ] ; sh:property [ sh:path sh:nodeKind ; sh:in ( sh:BlankNode sh:IRI sh:Literal sh:BlankNodeOrIRI sh:BlankNodeOrLiteral sh:IRIOrLiteral ) ; # nodeKind-in diff --git a/shacl12-vocabularies/shacl.ttl b/shacl12-vocabularies/shacl.ttl index 67ee87b3..4223b768 100644 --- a/shacl12-vocabularies/shacl.ttl +++ b/shacl12-vocabularies/shacl.ttl @@ -894,6 +894,85 @@ sh:minLength rdfs:range xsd:integer ; rdfs:isDefinedBy sh: . +sh:MemberShapeConstraintComponent + a sh:ConstraintComponent ; + rdfs:label "Member shape constraint component"@en ; + rdfs:comment "Can be used to specify constraints on the members of a given SHACL list. A violation is reported for each member of the list that does not comply with the constraints specified by the given shape. A violation is reported if the value is not a valid SHACL list."@en ; + sh:parameter sh:MemberShapeConstraintComponent-memberShape ; + rdfs:isDefinedBy sh: . + +sh:MemberShapeConstraintComponent-memberShape + a sh:Parameter ; + sh:path sh:memberShape ; + sh:node sh:NodeShape ; + rdfs:isDefinedBy sh: . + +sh:MinListLengthConstraintComponent + a sh:ConstraintComponent ; + rdfs:label "Minimum list length constraint component"@en ; + rdfs:comment "Specifies the minimum length of a SHACL list. A violation is reported if the value is not a valid SHACL list."@en ; + sh:parameter sh:MinListLengthConstraintComponent-minListLength ; + rdfs:isDefinedBy sh: . + +sh:MinListLengthConstraintComponent-minListLength + a sh:Parameter ; + sh:path sh:minListLength ; + sh:datatype xsd:integer ; + rdfs:isDefinedBy sh: . + +sh:MaxListLengthConstraintComponent + a sh:ConstraintComponent ; + rdfs:label "Maximum list length constraint component"@en ; + rdfs:comment "Specifies the maximum length of a SHACL list. A violation is reported if the value is not a valid SHACL list."@en ; + sh:parameter sh:MaxListLengthConstraintComponent-maxListLength ; + rdfs:isDefinedBy sh: . + +sh:MaxListLengthConstraintComponent-maxListLength + a sh:Parameter ; + sh:path sh:maxListLength ; + sh:datatype xsd:integer ; + rdfs:isDefinedBy sh: . + +sh:UniqueMembersConstraintComponent + a sh:ConstraintComponent ; + rdfs:label "Unique list members constraint component"@en ; + rdfs:comment "Specifies that all members of a SHACL list must be unique. A violation is reported if the value is not a valid SHACL list."@en ; + sh:parameter sh:UniqueMembersConstraintComponent-uniqueMembers ; + rdfs:isDefinedBy sh: . + +sh:UniqueMembersConstraintComponent-uniqueMembers + a sh:Parameter ; + sh:path sh:uniqueMembers ; + sh:datatype xsd:boolean ; + rdfs:isDefinedBy sh: . + +sh:memberShape + a rdf:Property ; + rdfs:label "member shape"@en ; + rdfs:comment "Specifies the shape that all members of SHACL lists must conform to."@en ; + rdfs:range sh:NodeShape ; + rdfs:isDefinedBy sh: . + +sh:minListLength + a rdf:Property ; + rdfs:label "Minimum list length"@en ; + rdfs:comment "Specifies the minimum length that a given SHACL list must have."@en ; + rdfs:range xsd:integer ; + rdfs:isDefinedBy sh: . + +sh:maxListLength + a rdf:Property ; + rdfs:label "Maximum list length"@en ; + rdfs:comment "Specifies the maximum length that a given SHACL list must have."@en ; + rdfs:range xsd:integer ; + rdfs:isDefinedBy sh: . + +sh:uniqueMembers + a rdf:Property ; + rdfs:label "Unique list members"@en ; + rdfs:comment "Specifies that all members of a SHACL list must be unique."@en ; + rdfs:range xsd:boolean ; + rdfs:isDefinedBy sh: . sh:NodeConstraintComponent a sh:ConstraintComponent ;