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.