This document describes Shapes Constraint Language (SHACL) Node Expressions.
This specification is published by the Data Shapes Working Group .
Node expressions
Some examples in this document use Turtle [[rdf12-turtle]]. The reader is expected to be familiar with SHACL [[shacl12-core]] and SPARQL [[sparql12-query]].
Within this document, the following namespace prefix bindings are used:
Prefix | Namespace |
---|---|
rdf: |
http://www.w3.org/1999/02/22-rdf-syntax-ns# |
rdfs: |
http://www.w3.org/2000/01/rdf-schema# |
sh: |
http://www.w3.org/ns/shacl# |
shnex: |
http://www.w3.org/ns/shnex# |
skos: |
http://www.w3.org/2004/02/skos/core# |
sparql: |
http://www.w3.org/ns/sparql# |
xsd: |
http://www.w3.org/2001/XMLSchema# |
ex: |
http://example.com/ns# |
Grey boxes such as this include syntax rules that apply to the shapes graph.
true
denotes the RDF term
"true"^^xsd:boolean
.
false
denotes the RDF term
"false"^^xsd:boolean
.
TODO
This section is informative.
A SHACL shapes graph can declare node expressions as values of various properties where dynamic computation is useful,
such as sh:targetNode
, sh:values
and sh:deactivated
.
A node expression is represented by an RDF node and can be evaluated to produce a list of output nodes.
For example, when used at sh:targetNode
, a node expression produces the list
of target nodes of a shape.
When used at sh:values
, a node expression produces the derived values for the property specified by sh:path
.
The following example contains a node expression that states that the target nodes of
the shape ex:EstonianCompanyShape
are the instances of ex:Company
where
the ex:headQuarterCountry
is ex:Estonia
.
The following diagram illustrates how this node expression is interpreted, from a logical point of view.
During validation, a SHACL processor will determine the target nodes of the shape
by evaluating the filterShape expression.
However, the filterShape expression first evaluates its input expression, which is specified via sh:nodes
and is an instancesOf expression.
This will produce all instances of the given class, ex:Company
.
The shnex:filterShape
is then applied to all of these instances, to keep only the companies
that conform to the provided shape, by having their headquarters in Estonia.
The scenario above can also be expressed using SPARQL select expressions.
For performance reasons, for example, specific implementations of SHACL node expressions might
internally convert node expressions such as the shnex:filterShape
above to SPARQL.
The next example uses a node expression to compute the values of the property ex:employeeCount
as the number of values of the property ex:employee
at each instance of ex:Company
.
One difference between this example and the previous examples about sh:targetNode
is that these node expressions are evaluated against a given focus node.
This means that when a data visualization needs to render an instance of ex:Company
,
the currently displayed company is the focus node, for which the number of employees
will be fetched.
Clarify when these derived properties can be used (e.g. in sh:path expressions but not as triples elsewhere)
This section introduces the general syntax of SHACL node expressions.
The term node expression function refers to the kind or type
of a node expression.
For example, sh:FilterShapeExpression
is a node expression function,
while a specific instance of this function in the graph is the node expression itself.
The most basic node expression functions are constant node expressions, which are either literals or IRIs, and simply evaluate to these constants. All other node expressions are represented by blank nodes, and come in the following two variations:
The node expression functions in this section are called constant node expressions. They were introduced in the SHACL Core specification and are repeated here to keep this document self-contained.
A node expression that is an IRI is called an IRI expression with the function name
sh:IRIExpression
.
A node in an RDF graph is a well-formed IRI expression if it is an IRI.
The output nodes of an IRI expression are the list consisting of exactly the node expression itself:
evalExpr(expr, focusGraph, focusNode, scope) -> [expr]
A node expression that is a literal is called a literal expression with the function name
sh:LiteralExpression
.
A node in an RDF graph is a well-formed literal expression if it is a literal.
The output nodes of a literal expression are the list consisting of exactly the node expression itself:
evalExpr(expr, focusGraph, focusNode, scope) -> [expr]
A named parameter function is a node expression function that is represented by a blank node that is the subject of at least one triple where the predicate can be used to uniquely identify the function, which is known as the key parameter.
The evaluation of a named parameter function can produce any of the following:
For example, the named parameter function
shnex:FilterShapeExpression
has shnex:filterShape
as its key parameter.
In this document, key parameters are marked in bold face.
Expressions based on named parameter functions often take other node expressions as arguments, evaluate those input node expressions, and then produce a different list of nodes as output nodes.
The remainder of this section is informative.
This document includes many examples of named parameter functions, such as the Estonian Company Shape example.
A list parameter function is a node expression function that is represented by a blank node that is the subject of a single triple where the object is a SHACL list. The predicate of this triple is called the list parameter property.
The evaluation of a list parameter function can produce any of the following:
Furthermore, each argument of a list parameter function must evaluate to an individual, single node, not to a list of nodes. If an argument is a node expression, then this node expression must evaluate to a maximum of one output node. An evaluation failure must be produced if there is more than one output node. This is different from named parameter functions, where arguments may produce lists of multiple nodes.
The remainder of this section is informative.
Note that some named parameter functions โ such as shnex:IntersectionExpression
โ
also use a SHACL list as an object of the key parameter, similar to list parameter functions which always have a SHACL list as the object of their list parameter property.
However, these may produce more than one output nodes, and also accept lists as input nodes.
The following example uses multiple (imaginary) list parameter functions โ
ex:coalesce
and ex:concat
โ to compute the ex:displayName
of a person as either the value of ex:fullName
or (if that doesn't exist)
as a concatenation of ex:firstName
, a space, and ex:lastName
.
Node expressions may produce a failure instead of a list of output nodes.
Some node expressions evaluate other, nested node expressions.
For example, If Expressions evaluate nested expressions for
shnex:if
, shnex:then
and shnex:else
.
In general, if any such nested expressions produce a failure then the surrounding
expression also produces the same failure.
The remainder of this section is informative.
Note that this policy impacts the evaluation order of node expressions.
For example, shnex:if
expressions are evaluated first and shnex:then
will be evaluated only if the shnex:if
has returned ( true )
.
Even if the shnex:else
branch would produce a failure, the output would
still only be the output nodes of the shnex:then
branch.
This section defines all node expression functions that are built into SHACL engines that implement this specification.
The syntax definitions of node expression functions that are based on blank nodes typically use a table of properties that these blank nodes can or must have. Such blank nodes are only well-formed when they are not the subject of any other triples, and when none of these properties is used more than once. The tables may also list SHACL constraints with which the property values are required to conform. In the tables, mandatory properties are rendered in bold face.
A blank node that is the subject of the following properties
is called a var expression with the function name shnex:VarExpression
:
Property | Constraints | Description |
---|---|---|
shnex:var |
sh:datatype xsd:string sh:minLength 1
|
The variable name, e.g. "focusNode" .
|
Let var
be the value of shnex:var
in the var expression.
The output nodes of the var expression are computed as follows, in order:
var
is "focusNode"
then evalExpr(expr, focusGraph, focusNode, scope) -> [focusNode]
var
is in the scope
then evalExpr(expr, focusGraph, focusNode, scope) -> [ scope[var] ]
evalExpr(expr, focusGraph, focusNode, scope) -> []
The remainder of this section is informative.
The following example illustrates the use of a var expression pointing at the current focus node
to state that the default value of the ex:loves
relationship is the current instance of ex:Person
,
creating a self-reference.
A blank node that is the subject of the following properties
is called a list expression with the function name shnex:ListExpression
:
Property | Constraints | Description |
---|---|---|
rdf:first |
The first member of the list. | |
rdf:rest |
Must be a well-formed SHACL list. |
The rest of the list, e.g. rdf:nil .
|
The output nodes of a list expression are the members of the SHACL list.
The remainder of this section is informative.
Note that rdf:nil
itself is not a list expression because it will be interpreted
as a IRI expression.
As a result, all well-formed list expressions have at least one member.
The following example declares a property for instances of rdfs:Class
where the values are derived from the values of the path rdfs:subClassOf*
but with the constants from the list ( owl:Thing rdfs:Resource )
removed using
shnex:minus
.
A blank node that is the subject of the following properties
is called a path expression with the function name shnex:PathExpression
:
Property | Constraints | Description |
---|---|---|
shnex:path |
Must be a well-formed SHACL property path. | The path to get the values from. |
shnex:nodes |
Optional, must be a well-formed node expression. | A node expression producing the focus nodes, defaulting to the current focus node from the evaluation context. |
Let path
be the value of shnex:path
,
and nodes
be the value of shnex:nodes
in the path expression.
If shnex:nodes
is not given, nodes
is the list consistent of exactly the focus node.
Let N
be the nodes produced by evalExpr(nodes, focusGraph, focusNode, scope)
.
The output nodes of the path expression are the list of nodes produced by concatenating
the value nodes of the path
at each node in N
.
TODO: Clarify if those can contain duplicates.
The remainder of this section is informative.
The following example illustrates the use of a path expression to compute the value
of the property ex:topConceptCount
.
The path expression returns the values of skos:hasTopConcept
at each skos:ConceptScheme
and these are processed by the shnex:count
to return the
number of top concepts.
TODO: Add second example that uses shnex:nodes
A blank node that is the subject of the following properties
is called an exists expression with the function name shnex:ExistsExpression
:
Property | Constraints | Description |
---|---|---|
shnex:exists |
A well-formed node expression. |
A node expression. If this evaluates to a list with at least one member
then the output nodes are ( true ) ; otherwise, the output nodes are ( false ) .
|
Let exists
be the value of shnex:exists
in the exists expression.
Let N
be the list of nodes produced by evalExpr(exists, focusGraph, focusNode, scope)
.
The output nodes of the exists expression are ( true )
if and only if
N
has at least one member; otherwise, the output nodes are ( false )
.
The remainder of this section is informative.
The Example for shnex:if
uses shnex:exists
.
A blank node that is the subject of the following properties
is called an if expression with the function name shnex:IfExpression
:
Property | Constraints | Description |
---|---|---|
shnex:if |
A well-formed node expression. |
A node expression. The shnex:then branch is returned when the shnex:if expression
returns true as its only output node, in all other cases shnex:else .
|
shnex:then |
A well-formed node expression.
Optional but at least one of shnex:then or shnex:else is required.
|
The node expression that is returned when the shnex:if evaluated to [true] .
|
shnex:else |
A well-formed node expression.
Optional but at least one of shnex:then or shnex:else is required.
|
The node expression that is returned when the shnex:if did not evaluate to [true] .
|
Let if
be the value of shnex:if
,
then
be the value of shnex:then
, and
else
be the value of shnex:else
for the if expression.
Let IFs
be the nodes produced by evalExpr(if, focusGraph, focusNode, scope)
.
If IFs
is the list ( true )
, then the output nodes of the if expression
are the nodes produced by evalExpr(then, focusGraph, focusNode, scope)
, or the empty list if then
has no value.
Otherwise, the output nodes are the nodes produced by evalExpr(else, focusGraph, focusNode, scope)
, or the empty list if else
has no value.
Implementations MUST apply lazy evaluation techniques, so the shnex:then
or
shnex:else
branches are only evaluated when necessary.
The remainder of this section is informative.
The following example illustrates the use of shnex:if
to compute the
values of a derived property ex:fillColor
that may be queried to
compute the colors of cities on a map.
In the example, instances of ex:City
that have a value for ex:capitalOf
will be displayed in "blue"
, while the others will be "red"
.
A blank node that is the subject of the following properties
is called a distinct expression with the function name shnex:DistinctExpression
:
Property | Constraints | Description |
---|---|---|
shnex:distinct |
A well-formed node expression. | The node expression that shall be reduced to its distinct members. |
Let distinct
be the value of shnex:distinct
in the distinct expression.
Let input
be the output nodes of evalExpr(distinct, focusGraph, focusNode, scope)
.
The output nodes of the distinct expression are the list of nodes in input
in the same order but with duplicates eliminated (the first occurences of each node shall be kept, the others removed).
Nodes are compared using term equality, i.e. "01"^^xsd:integer
is distinct from "1"^^xsd:integer
.
The remainder of this section is informative.
The following example declares a derived property ex:superClassesIncludingRoot
that is computed as the union of the (transitive) values of rdfs:subClassOf
and the list expression ( rdfs:Resource )
.
Since the asserted values of rdfs:subClassOf
may already include rdfs:Resource
(for example, due to an active inference engine on the data graph), shnex:distinct
will make
sure that the output nodes do not include rdfs:Resource
twice.
A blank node that is the subject of the following properties
is called an intersection expression with the function name shnex:IntersectionExpression
:
Property | Constraints | Description |
---|---|---|
shnex:intersection |
A well-formed SHACL list where each member is a well-formed node expression. | The node expressions that shall be intersected. |
Let members
be the members of the value of shnex:intersection
in the intersection expression.
The output nodes of the intersection expression are the nodes that form the intersection of the output nodes
produced by each node expression NE
in members
, using evalExpr(NE, focusGraph, focusNode, scope)
.
Nodes must be equal using term equality, i.e. "01"^^xsd:integer
is distinct from "1"^^xsd:integer
.
The remainder of this section is informative.
The following example uses shnex:intersection
as a sh:targetNode
node expression.
This shape will target all nodes that are SHACL instances of ex:Australian
and
ex:German
at the same time.
A blank node that is the subject of the following properties
is called a union expression with the function name shnex:UnionExpression
:
Property | Constraints | Description |
---|---|---|
shnex:union |
A well-formed SHACL list where each member is a well-formed node expression. | The node expressions that shall be unioned. |
Let members
be the members of the value of shnex:union
in the union expression.
The output nodes of the union expression are the concatenation of all output nodes
for each node expression NE
in members
, using evalExpr(NE, focusGraph, focusNode, scope)
.
The order is preserved, evaluating the members
from left to right and keeping the order of each list of output nodes.
The remainder of this section is informative.
Note that a union expression may produce duplicate output nodes if the individual output nodes overlap. Use shnex:distinct to eliminate duplicates.
The Example for shnex:distinct
uses shnex:union
.
A blank node that is the subject of the following properties
is called a minus expression with the function name shnex:MinusExpression
:
Property | Constraints | Description |
---|---|---|
shnex:minus |
A well-formed node expression. |
The nodes that shall be removed from the shnex:nodes .
|
shnex:nodes |
A well-formed node expression. | The input nodes. |
Let minus
be the value of shnex:minus
and nodes
be the value of shnex:nodes
in the minus expression.
Let M
be the output nodes of evalExpr(minus, focusGraph, focusNode, scope)
.
Let N
be the output nodes of evalExpr(nodes, focusGraph, focusNode, scope)
.
The output nodes of the minus expression are the nodes in N
except those that are also in M
, preserving the order of N
.
Nodes must be equal using term equality, i.e. "01"^^xsd:integer
is distinct from "1"^^xsd:integer
.
The remainder of this section is informative.
The List Expression example uses shnex:minus
.
A blank node that is the subject of the following properties
is called a filterShape expression with the function name shnex:FilterShapeExpression
:
Property | Constraints | Description |
---|---|---|
shnex:filterShape |
A well-formed shape. | The shape that all input nodes need to conform to. |
shnex:nodes |
A well-formed node expression. | A node expression producing the nodes that are validated. |
Let filterShape
be the value of shnex:filterShape
,
and nodes
be the value of shnex:nodes
in a filterShape expression.
The output nodes of the filterShape expression are the output nodes of
evalExpr(nodes, focusGraph, focusNode, scope)
except those that do not conform to
the shape filterShape
, preserving the order in the list.
The remainder of this section is informative.
The following example illustrates the use of shnex:filterShape
to return a subset
of values of the ex:child
property where the ex:gender
property
has the value "male"
.
A blank node that is the subject of the following properties
is called a limit expression with the function name shnex:LimitExpression
:
Property | Constraints | Description |
---|---|---|
shnex:limit |
sh:datatype xsd:integer sh:minInclusive 0
|
The maximum number of nodes that shall be returned. |
shnex:nodes |
A well-formed node expression. | The input nodes. |
Let limit
be the value of shnex:limit
and nodes
be the value of shnex:nodes
in the limit expression.
Let N
be the output nodes of evalExpr(nodes, focusGraph, focusNode, scope)
.
The output nodes of the limit expression are the first limit
nodes in N
from left to right, in the same order.
The remainder of this section is informative.
The following example illustrates the use of shnex:limit
to compute the
values of a derived property ex:oldestChildren
to be a sub-list of
values of ex:child
at the current focus node (which is an instance of
the class ex:Person
).
The values are computed by first fetching the values of ex:child
, then
ordering them by their ex:dateOfBirth
, and finally getting only
2
of these children at most.
A blank node that is the subject of the following properties
is called an offset expression with the function name shnex:OffsetExpression
:
Property | Constraints | Description |
---|---|---|
shnex:offset |
sh:datatype xsd:integer sh:minInclusive 0
|
The number of nodes that shall be skipped from the shnex:nodes .
|
shnex:nodes |
A well-formed node expression. | The input nodes. |
Let offset
be the value of shnex:offset
and nodes
be the value of shnex:nodes
in the offset expression.
Let N
be the output nodes of evalExpr(nodes, focusGraph, focusNode, scope)
.
The output nodes of the offset expression are the nodes in N
except for the first offset
nodes from left to right, in the same order.
The remainder of this section is informative.
The following example illustrates the use of shnex:offset
to compute the
values of a derived property ex:remainingChildren
to be a sub-list of
values of ex:child
at the current focus node (which is an instance of
the class ex:Person
).
The values are computed by first fetching the values of ex:child
, then
ordering them by their ex:dateOfBirth
, and finally skipping the first
of these children.
TODO: This should be cleaned up from the SHACL-AF definition and requires thought
The Example of shnex:limit
also illustrates shnex:orderBy
.
A blank node that is the subject of the following properties
is called a count expression with the function name shnex:CountExpression
:
Property | Constraints | Description |
---|---|---|
shnex:count |
A well-formed node expression. | The input nodes that shall be counted. |
Let count
be the value of shnex:count
in the count expression.
Let N
be the output nodes of evalExpr(count, focusGraph, focusNode, scope)
.
The output nodes of the count expression is the list consisting of exactly one
xsd:integer
literal that is computed as the length of N
.
The remainder of this section is informative.
The following example illustrates the use of shnex:count
to derive a property
ex:topConceptCount
as the number of values of the skos:hasTopConcept
property in a skos:ConceptScheme
.
A blank node that is the subject of the following properties
is called a min expression with the function name shnex:MinExpression
:
Property | Constraints | Description |
---|---|---|
shnex:min |
A well-formed node expression. | The input nodes from which the minimum value shall be returned. |
Let min
be the value of shnex:min
in the min expression.
Let N
be the output nodes of evalExpr(min, focusGraph, focusNode, scope)
.
The output nodes of the min expression is the list consisting of at most one node
that is computed as the minimum value from N
.
Clarify exactly how that is computed, maybe via reference to SPARQL MIN
The remainder of this section is informative.
The following example illustrates the use of shnex:min
to derive a property
ex:minStartDate
as the smallest value of the values that can be reached using the
property path ex:exployee/ex:startDate
.
In other words, it walks through all employees of the given company and returns the earliest
date on which an employee started.
A blank node that is the subject of the following properties
is called a max expression with the function name shnex:MaxExpression
:
Property | Constraints | Description |
---|---|---|
shnex:max |
A well-formed node expression. | The input nodes from which the maximum value shall be returned. |
Let max
be the value of shnex:max
in the max expression.
Let N
be the output nodes of evalExpr(max, focusGraph, focusNode, scope)
.
The output nodes of the max expression is the list consisting of at most one node
that is computed as the maximum value from N
.
Clarify exactly how that is computed, maybe via reference to SPARQL MAX
The remainder of this section is informative.
The Example for shnex:min
can be easily adapted
for shnex:max
.
A blank node that is the subject of the following properties
is called a sum expression with the function name shnex:SumExpression
:
Property | Constraints | Description |
---|---|---|
shnex:sum |
A well-formed node expression. | The input nodes from which the sum shall be returned. |
Let sum
be the value of shnex:sum
in the sum expression.
Let N
be the output nodes of evalExpr(sum, focusGraph, focusNode, scope)
.
The output nodes of the sum expression is the list consisting of exactly one node
that is computed as the sum of all nodes from N
.
Clarify exactly how that is computed, maybe via reference to SPARQL SUM
The remainder of this section is informative.
Note that shnex:sum
needs to be used with care and may be often misunderstood,
when used with property paths.
The problem is that when a path expression is used as input to a sum expression,
the path expression will have eliminated duplicates before they can be processed by the shnex:sum
.
As a result, only the distinct values will be added up.
TODO: Find good example, or drop the feature if none makes sense
This section enumerates node expression functions that did not fit into other categories.
A blank node that is the subject of the following properties
is called an instancesOf expression with the function name shnex:InstancesOfExpression
:
Property | Constraints | Description |
---|---|---|
shnex:instancesOf |
sh:nodeKind sh:IRI
|
The class that the output nodes must be instances of. |
Let type
be the value of shnex:instancesOf
in an instancesOf expression.
The output nodes of the instancesOf expression are the nodes that are SHACL instances
of type
in the focus graph.
The remainder of this section is informative.
Note that the definition of SHACL instance
includes instances of subclasses of the given class.
So if the focus graph contains ex:SubClass rdfs:subClassOf ex:SuperClass
and ex:SubInstance a ex:SubClass
then ex:SubInstance
will also be returned as instance of ex:SuperClass
.
The interpretation of shnex:instancesOf
is similar to sh:targetClass
and sh:class
.
Users of this node expression function should be aware that the list of output nodes may be very large.
The Example for shnex:intersection
uses shnex:instanceOf
.
This section introduces SHACL constraint components that operate on node expressions.
Based on node expressions, this section introduces a constraint component called
expression constraints.
Expression constraints can be used in any shape to declare the condition that the
node expression specified via sh:expression
has true
as its only output node.
The evaluation of these node expressions is repeated for all value nodes of the shape
as the focus node.
Constraint Component IRI: sh:ExpressionConstraintComponent
Property | Summary and Syntax Rules |
---|---|
sh:expression |
The node expression that must return true .
The values of sh:expression at a
shape must be well-formed node expressions.
|
$expr
be a value of sh:expression
.
For each value node v
where evalExpr(expr, data graph, focusNode, {value: v})
does not return the list consisting of exactly true
as its output nodes,
there is a validation result that has v
as its sh:value
and a deep copy of $expr
in the results graph as its sh:sourceConstraint
.
The remainder of this section is informative.
Note that the scope in the evaluation of expression constraints contains the variable value
for the current value node while the variable focusNode
is the focus node.
The following example uses some SPARQL-based node expressions to declare
the constraint that the values of ex:ibanNumber
must start with the same two (upper-case) letters as
the values of the path ex:country/ex:code
.
sh:nodeByExpression
specifies the condition that each value node conforms to the
node shapes produced by a node expression.
The evaluation of these node expressions is repeated for all value nodes of the shape
as the focus node.
Constraint Component IRI: sh:NodeByExpressionConstraintComponent
Property | Summary and Syntax Rules |
---|---|
sh:nodeByExpression |
The node shapes that all value nodes need to conform to.
The values of sh:nodeByExpression in a shape must be well-formed node expressions.
|
$expr
be a value of sh:nodeByExpression
.
For each value node v
: perform a conformance check of
v
against each output node of evalExpr(expr,
data graph, v, {})
s
. A failure
MUST be produced if the conformance check of v
against
s
produces a failure. Otherwise, if v
does
not conform to s
, there is a validation result
with v
as sh:value
and a deep copy of
s
as sh:sourceConstraint
.
The remainder of this section is informative.
sh:nodeByExpression
functions similarly to sh:node
, but instead of referencing a fixed node shape,
a referenced node expression is used to dynamically compute the set of node shapes to which each value node must conform.
There are three key differences between sh:nodeByExpression
and sh:node
:
sh:nodeByExpression
references a node expression instead of a fixed node shape as sh:node
does.
sh:nodeByExpression
cannot reference a node shape that is a blank node as a value like sh:node
can,
as a blank node would be interpreted as a node expression.
sh:nodeByExpression
additionally include a value for `sh:sourceConstraint`.
Note that sh:node
and sh:nodeByExpression
exhibit the same behavior when given a value that is an IRI of a node shape.
In this case, sh:node
directly validates against the specified node shape, whereas sh:nodeByExpression
interprets the IRI
as an IRI expression that evaluates to a set containing the same node shape.
The following example demonstrates how sh:nodeByExpression
could be used in the context of the W3C Data Cube Vocabulary.
Building upon examples 5 and 6 from the Data Cube Vocabulary documentation, Data Structure Definition is extended with the property eg:hasShape
,
which links to an associated node shape to which relevant qb:Observation
instances must conform.
To validate that every qb:Observation
instance conforms to the appropriate shape, sh:nodeByExpression
with a Path Expression
is used to locate the shape at the property path qb:dataSet/qb:structure/eg:hasShape
from each qb:Observation
instance.
{ "@graph": [ { "@id": "eg:dsd1-shape", "@type": "sh:NodeShape", "sh:property": [ { "@id": "_:b1", "sh:path": { "@id": "sdmx-dimension:refTime" }, "sh:datatype": { "@id": "xsd:date" }, "sh:minCount": { "@type": "xsd:integer", "@value": "1" }, "sh:maxCount": { "@type": "xsd:integer", "@value": "1" } }, { "@id": "_:b2", "sh:path": { "@id": "eg-measure:quantity" }, "sh:datatype": { "@id": "xsd:integer" }, "sh:minCount": { "@type": "xsd:integer", "@value": "1" }, "sh:maxCount": { "@type": "xsd:integer", "@value": "1" }, "sh:minInclusive": { "@type": "xsd:integer", "@value": "0" } }, { "@id": "_:b3", "sh:path": { "@id": "eg-measure:weight" }, "sh:datatype": { "@id": "xsd:decimal" }, "sh:minCount": { "@type": "xsd:integer", "@value": "1" }, "sh:maxCount": { "@type": "xsd:integer", "@value": "1" }, "sh:minInclusive": { "@type": "xsd:decimal", "@value": "0.0" } } ] }, { "@id": "eg:ObservationShape", "@type": "sh:NodeShape", "sh:targetClass": { "@id": "qb:Observation" }, "sh:nodeByExpression": { "shnex:path": { "@list": [ { "@id": "qb:dataSet" }, { "@id": "qb:structure" }, { "@id": "eg:hasShape" } ] } } } ] }
{ "@graph": [ { "@id": "eg:dataset1", "@type": "qb:DataSet", "qb:structure": { "@id": "eg:dsd1" } }, { "@id": "eg:dsd1", "@type": "qb:DataStructureDefinition", "rdfs:comment": { "@language": "en", "@value": "shipments by time (multiple measures approach)" } "eg:hasShape": { "@id": "eg:dsd1-shape" }, "qb:component": [ { "qb:dimension": { "@id": "sdmx-dimension:refTime" } }, { "qb:measure": { "@id": "eg-measure:quantity" } }, { "qb:measure": { "@id": "eg-measure:weight" } } ] }, { "@id": "eg:obs1a", "@type": "qb:Observation", "qb:dataSet": { "@id": "eg:dataset1" }, "sdmx-dimension:refTime": { "@type": "xsd:date", "@value": "2010-07-30" }, "eg-measure:quantity": { "@type": "xsd:integer", "@value": "42" }, "eg-measure:weight": { "@type": "xsd:decimal", "@value": "1.3" } }, { "@id": "eg:obs1b", "@type": "qb:Observation", "qb:dataSet": { "@id": "eg:dataset1" }, "sdmx-dimension:refTime": { "@type": "xsd:dateTime", "@value": "2010-07-31T12:00:00" } "eg-measure:weight": { "@type": "xsd:decimal", "@value": "1.4" }, } ] }
{ "@type": "sh:ValidationReport", "sh:conforms": { "@type": "xsd:boolean", "@value": "false" }, "sh:result": { "@type": "sh:ValidationResult", "sh:resultSeverity": { "@id": "sh:Violation" }, "sh:focusNode": { "@id": "eg:obs1b" }, "sh:value": { "@id": "eg:obs1b" }, "sh:resultMessage": "Value does not conform to shape eg:dsd1-shape.", "sh:sourceConstraint": { "@id": "eg:dsd1-shape" }, "sh:sourceConstraintComponent": { "@id": "sh:NodeByExpressionConstraintComponent" }, "sh:sourceShape": { "@id": "eg:ObservationShape" }, "sh:detail": [ { "@type": "sh:ValidationResult", "sh:resultSeverity": { "@id": "sh:Violation" }, "sh:focusNode": { "@id": "eg:obs1b" }, "sh:resultPath": { "@id": "sdmx-dimension:refTime" }, "sh:value": { "@type": "xsd:dateTime", "@value": "2010-07-31T12:00:00" }, "sh:resultMessage": "Value does not have datatype xsd:date", "sh:sourceConstraintComponent": { "@id": "sh:DatatypeConstraintComponent" }, "sh:sourceShape": { "@id": "_:b1" } }, { "@type": "sh:ValidationResult", "sh:resultSeverity": { "@id": "sh:Violation" }, "sh:focusNode": { "@id": "eg:obs1b" }, "sh:resultPath": { "@id": "eg-measure:quantity" }, "sh:resultMessage": "Less than 1 values", "sh:sourceConstraintComponent": { "@id": "sh:MinCountConstraintComponent" }, "sh:sourceShape": { "@id": "_:b2" } } ] } }
TODO
TODO
Many people contributed to this document, including members of the RDF Data Shapes Working Group.
TODO