The DASH namespace includes a collection of SHACL constraint components that extend the Core of SHACL with new constraint types. This document introduces these additional constraint components.
This document uses the prefix dash
which represents the DASH Data Shapes
namespace http://datashapes.org/dash#
which is accessible via its URL http://datashapes.org/dash
.
SHACL [[shacl]] includes an extension mechanism that provides an RDF meta-language to represent new types of constraints as constraint components. The DASH namespace uses this extension mechanism to define new kinds of constraints that did not make it into the Core of SHACL itself, yet may be of general interest. As new use cases are explored, DASH will be continuously extended. Contributions and suggestions are more than welcome!
The constraint components in this section have in common that they define restrictions on the type of the nodes.
For properties that take classes (e.g. instances of rdfs:Class
) as their values,
the property dash:rootClass
can be used to express that all value nodes must be
subclasses of the specified root class.
This check includes transitive subclasses and the root class itself.
Constraint Component: dash:RootClassConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:rootClass |
rdfs:Class |
The class all value nodes must be a subclass of |
dash:rootClass
nor a (transitive) subclass of that class.
ASK { $value rdfs:subClassOf* $rootClass . }
In the following example scenario, instances of the class ex:Country
must point at
a subclass of ex:Address
using the property ex:addressType
.
ex:Country a rdfs:Class, sh:NodeShape ; sh:property [ sh:path ex:addressType ; dash:rootClass ex:Address ; ] .
In the following data graph, only ex:Germany
is violating the ex:Country
shape, because its value for ex:addressType
is not declared to be a subclass of
ex:Address
.
ex:Address
a rdfs:Class .
ex:AustralianAddress
a rdfs:Class ;
rdfs:subClassOf ex:Address .
ex:USAddress
a rdfs:Class ;
rdfs:subClassOf ex:Address .
ex:Country
a rdfs:Class .
ex:Australia
a ex:Country ;
ex:addressType ex:AustralianAddress .
ex:USA
a ex:Country ;
ex:addressType ex:USAddress .
ex:Germany
a ex:Country ;
ex:addressType ex:GermanAddress .
The constraint components in this section have in common that they specify conditions on the string representation of value nodes.
The property dash:stem
can be used to state that all value nodes must be IRIs
starting with a given string.
Constraint Component: dash:StemConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:stem |
xsd:string |
The start of the IRIs |
$stem
.
ASK { FILTER (isIRI($value) && STRSTARTS(str($value), $stem)) }
The property dash:singleLine
can be used to state that all value nodes that are literals must have a
lexical form that contains no line breaks ('\n' or '\r').
User interfaces may use the dash:singleLine
flag to prefer a text field over a (multi-line) text area.
Constraint Component: dash:SingleLineConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:singleLine |
xsd:boolean |
True to state that the lexical form of literal value nodes must not contain any line breaks. False to state that line breaks are explicitly permitted. |
$singleLine
is true
then
a validation result must be produced for each value node that is a literal that contains at least one of the
line break characters \n
or \r
.
ASK { FILTER (!$singleLine || !isLiteral($value) || (!contains(str($value), '\n') && !contains(str($value), '\r'))) }
schema:PersonShape a sh:NodeShape ; sh:targetClass schema:Person ; sh:property [ sh:path schema:givenName ; sh:name "given name" ; sh:description "A person's first/given name." ; sh:datatype xsd:string ; dash:singleLine true ; # Cannot contain line breaks -> Text field for input ] ; sh:property [ sh:path schema:description ; sh:name "description" ; sh:datatype xsd:string ; dash:singleLine false ; # Explicitly may have multiple lines -> Text area for input ] .
The constraint components in this section restrict the sets of value nodes in relation to other properties.
The property dash:coExistsWith
can be used to state that if there are any value nodes
(for the given path in the property shape) then there must also be values for a specified property,
and if there are no value nodes then there cannot be any values for a specified property either.
Constraint Component: dash:CoExistsWithConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:coExistsWith |
rdf:Property |
The property that must co-exist with the given path |
$coExistsWith
at the focus node, or if there is no
value node but there is at least one value for $coExistsWith
at the focus node.
SELECT $this WHERE { { FILTER (EXISTS { $this $PATH ?any } && NOT EXISTS { $this $coExistsWith ?any }) } UNION { FILTER (NOT EXISTS { $this $PATH ?any } && EXISTS { $this $coExistsWith ?any }) } }
In the following example scenario, if an instance of the class ex:Measurement
has any value
for the property ex:minValue
then it must also have value(s) for ex:maxValue
.
ex:Measurement a rdfs:Class, sh:NodeShape ; sh:property [ sh:path ex:minValue ; dash:coExistsWith ex:maxValue ; ] .
The property dash:subSetOf
can be used to state that all value nodes must also be
values of a specified other property at the same focus node.
Constraint Component: dash:SubSetOfConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:subSetOf |
rdf:Property |
The property that must also have all values of the given path |
dash:subSetOf
) for the same focus node as subject.
ASK { $this $subSetOf $value . }
In the following example scenario, instances of the class ex:Person
can have values
for the properties ex:child
and ex:favoriteChild
, but the favorite child
must also be one of the children.
ex:Person a rdfs:Class, sh:NodeShape ; sh:property [ sh:path ex:favoriteChild ; dash:subSetOf ex:child ; ] .
The constraint components in this section define constraints on relationships between nodes.
The property dash:nonRecursive
can be used to express that a property or path must not point back to itself.
For example, "a person cannot have itself as parent" can be expressed by setting dash:nonRecursive
to true
for a given property ex:parent
.
To express that a person cannot have itself among any of its (recursive) parents, use a sh:path
with the +
operator such as ex:parent+
.
Constraint Component: dash:NonRecursiveConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:nonRecursive |
xsd:boolean |
True to specify that the property must be non-recursive |
dash:nonRecursive
is true
, then a validation result must be produced
for each focus node where the set of value nodes includes the focus node itself.
SELECT $this ($this AS ?value) WHERE { { FILTER (?nonRecursive) } $this $PATH $this . }
ex:Person a rdfs:Class, sh:NodeShape ; sh:property [ dash:nonRecursive true ; sh:path [ sh:oneOrMorePath ex:parent ; ] ; ] .
The property dash:symmetric
can be used to express that a property is symmetric.
For symmetric properties, if A relates to B then B must relate to A.
Constraint Component: dash:SymmetricConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:symmetric |
xsd:boolean |
True to specify that the property is symmetric |
dash:symmetric
is true
, then a validation result must be produced
for each value node ?value
where there exists no match ?value $PATH $this
for the given focus node $this
and the path $PATH
.
SELECT $this ?value { FILTER ($symmetric) . $this $PATH ?value . FILTER NOT EXISTS { ?value $PATH $this . } }
The constraint components in this section do not fit into the other categories.
The property dash:closedByTypes
can be used to declare that focus nodes are "closed" based on
their value of rdf:type
, meaning that focus nodes may only have values for the properties that are
explicitly enumerated via sh:property/sh:path
in property shapes at their types and the superclasses of those.
This assumes that the type classes are also shapes.
Constraint Component: dash:ClosedByTypesConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:closedByTypes |
xsd:boolean |
True to specify that instances of the shape are closed by their types |
dash:closedByTypes
is true
, a validation result must be produced
for each value v
of property p
of the focus node where p
is not defined as the sh:path
of any sh:property
constraints attached
to any of the SHACL types of the focus node, and p
is not rdf:type
.
In the produced validation results, p
is the value for sh:resultPath
and v
is the value for sh:value
.
SELECT $this (?predicate AS ?path) ?value WHERE { FILTER ($closedByTypes) . $this ?predicate ?value . FILTER (?predicate != rdf:type) . FILTER NOT EXISTS { $this rdf:type ?type . ?type rdfs:subClassOf* ?class . GRAPH $shapesGraph { ?class sh:property/sh:path ?predicate . } } }
In the following example, note that the classes are also declared to be node shapes.
ex:SuperClass a rdfs:Class, sh:NodeShape ; dash:closedByTypes true ; sh:property [ sh:path ex:superProperty ; ] . ex:MiddleClass a rdfs:Class, sh:NodeShape ; rdfs:subClassOf ex:SuperClass ; sh:property [ sh:path ex:middleProperty ; ] . ex:SubClass a rdfs:Class, sh:NodeShape ; rdfs:subClassOf ex:MiddleClass ; sh:property [ sh:path ex:subProperty ; ] .
With the following data graph, ex:InvalidInstance1
is violating the
sh:closedByTypes
constraint because it has a value sub
for ex:subProperty
but it is only declared to have type ex:MiddleClass
while ex:subProperty
is defined outside of the shapes associated with the types
of ex:InvalidInstance1
.
ex:ValidInstance1
does not produce validation results because it only uses
properties that are either rdf:type
or declared in the shapes associated with either
ex:MiddleClass
or its superclass.
ex:SuperClass a rdfs:Class . ex:MiddleClass a rdfs:Class ; rdfs:subClassOf ex:SuperClass . ex:SubClass a rdfs:Class ; rdfs:subClassOf ex:MiddleClass . ex:InvalidInstance1 a ex:MiddleClass ; ex:subProperty "sub" . ex:ValidInstance1 a ex:MiddleClass ; ex:middleProperty "A" ; ex:superProperty "A" .
The property dash:hasValueIn
can be used to state that at least one value node
must be a member of a provided SHACL list.
This constraint component only makes sense for property shapes.
It takes a list argument similar to sh:in
but is "open" like sh:hasValue
since it allows values outside of the list.
Constraint Component: dash:HasValueInConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:hasValueIn |
SHACL list | At least one of the value nodes must be a member of this list |
Note that matching of literals needs to be exact, e.g. "04"^^xsd:byte
does not match "4"^^xsd:integer
.
SELECT $this WHERE { FILTER NOT EXISTS { $this $PATH ?value . GRAPH $shapesGraph { $hasValueIn (rdf:rest*)/rdf:first ?value } } }
ex:ExampleShape a sh:NodeShape ; sh:targetClass ex:Agent ; sh:property [ sh:path ex:type ; dash:hasValueIn ("person" "organization") ; ].
With the following data graph, the first two nodes conform although they have extra values for ex:type
.
The last two nodes do not conform because no ex:type
literal matches exactly one of the list members.
ex:Person1 a ex:Agent; ex:type "person", "investor". ex:Org1 a ex:Agent; ex:type "organization", "investor". ex:Person2 a ex:Agent; ex:type "person"@en. ex:Org2 a ex:Agent; ex:type "organisation".
The property dash:hasValueWithClass
can be used to state that one of the value nodes
must be an instance of a given class.
This constraint component only really makes sense for property shapes.
Constraint Component: dash:HasValueWithClassConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:hasValueWithClass |
rdfs:Class |
The class that at least one of the value nodes must have |
$hasValueWithClass
.
SELECT $this WHERE { FILTER NOT EXISTS { $this $PATH ?value . ?value a ?type . ?type rdfs:subClassOf* $hasValueWithClass . } }
ex:ExampleShape a sh:NodeShape ; sh:targetNode ex:InvalidInstance1, ex:ValidInstance1 ; sh:property [ sh:path ex:property ; dash:hasValueWithClass ex:SuperClass ; ] .
With the following data graph, only ex:InvalidInstance1
is violated
because none of its values for ex:property
are instances of ex:SuperClass
.
ex:SuperClass a rdfs:Class . ex:SubClass a rdfs:Class ; rdfs:subClassOf ex:SuperClass . ex:SubClassInstance a ex:SubClass . ex:InvalidInstance1 ex:property ex:SomeInstance . ex:ValidInstance1 ex:property ex:SomeInstance, ex:SubClassInstance .
Note that the property dash:hasValueWithClass
is primarily syntactic sugar for the
following qualified value constraint. It is also very similar to owl:someValuesFrom
.
ex:ExampleShape a sh:NodeShape ; sh:property [ sh:path ex:property ; sh:qualifiedMinCount 1 ; sh:qualifiedValueShape [ sh:class ex:SuperClass ] ; ] .
In some cases, property values must be unique for all members of a class.
Examples include Social Security Numbers.
The property dash:uniqueValueForClass
can be used to enforce such constraints.
Constraint Component: dash:UniqueValueForClassConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:uniqueValueForClass |
rdfs:Class |
The class for which the property values must be unique. |
$uniqueValueForClass
.
SELECT DISTINCT $this ?value ?other WHERE { { $this $PATH ?value . ?other $PATH ?value . FILTER (?other != $this) . } ?other a ?type . ?type rdfs:subClassOf* $uniqueValueForClass . }
Note that this constraint type can only be used in property shapes. It will always produce pairs of constraint violations for each duplicate value.
The following example declares that all values of the property ex:ssn
must be unique among instances of ex:Person
.
ex:PersonShape a sh:NodeShape ; sh:targetClass ex:Person ; sh:property [ sh:path ex:ssn ; sh:datatype xsd:string ; sh:maxCount 1 ; dash:uniqueValueForClass ex:Person ; ] .
Enforces a constraint that the given property (sh:path
) serves as primary key for all focus nodes of the shape.
If a property has been declared to be the primary key then each focus node must have exactly one value for that property.
Furthermore, the URIs of those focus nodes must start with a given string (dash:uriStart
),
followed by the URL-encoded primary key value.
For example if dash:uriStart
is "http://example.org/country-"
and the primary key for an
instance is "de"
then the URI must be "http://example.org/country-de"
.
Finally, as a result of the URI policy, there can not be any other focus node with the same value under the same primary key policy.
Constraint Component: dash:PrimaryKeyConstraintComponent
Property | Value Type | Summary |
---|---|---|
dash:uriStart |
xsd:string |
The start of URIs of the focus nodes. Can only be used in property shapes. |
$uriStart
,
or where the focus node does not have exactly one value for the path property,
or where the IRI is not equal to the concatenation of $uriStart
and the
string representation of the value of the property path.