Skip to content

Issue 189: Add sh:nodeByExpression Constraint Component #408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: gh-pages
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 216 additions & 0 deletions shacl12-core/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2520,6 +2520,7 @@ <h2>Node Expressions</h2>
<ul>
<li>At <a href="#property-shapes"><code>sh:values</code> and <code>sh:defaultValue</code></a> to derive the value nodes of a property shape.</li>
<li>At <a href="#targetNode"><code>sh:targetNode</code></a> to dynamically compute the targets of a shape.</li>
<li>At <a href="#NodeByExpressionConstraintComponent"><code>sh:nodeByExpression</code></a> to validate nodes against a dynamically computed set of node shapes.</li>
<li>At <a href="#ExpressionConstraintComponent"><code>sh:expression</code></a> to validate nodes against a condition.</li>
<li>At <a href="#deactivated"><code>sh:deactivated</code></a> to deactivate certain shapes under specific conditions.</li>
</ul>
Expand Down Expand Up @@ -6074,6 +6075,220 @@ <h4>sh:reifierShape, sh:reificationRequired</h4>
</div>
</aside>
</section>

<section id="NodeByExpressionConstraintComponent">
<h4>sh:nodeByExpression</h4>
<p>
<code>sh:nodeByExpression</code> specifies the condition that each <a>value node</a> conforms to the
<a>node shapes</a> produced by a <a>node expression</a>.
The evaluation of these node expressions is repeated for all <a>value nodes</a> of the <a>shape</a>
as the <a>focus node</a>.
</p>
<p>
<span class="component-class">Constraint Component IRI</span>: <code>sh:NodeByExpressionConstraintComponent</code>
</p>

<div class="parameters">Parameters:</div>
<table class="term-table">
<tr>
<th>Property</th>
<th>Summary and Syntax Rules</th>
</tr>
<tr>
<td><code>sh:nodeByExpression</code></td>
<td>
The <a>node shapes</a> that all value nodes need to conform to.
<span data-syntax-rule="nodeByExpression-scope">The <a>values</a> of <code>sh:nodeByExpression</code> in a shape must be <a>well-formed</a> <a>node expressions</a>.</span>
</td>
</tr>
</table>
<div class="def def-text">
<div class="def-header">TEXTUAL DEFINITION</div>
<div class="def-text-body" data-validator="NodeByExpression">
Let <code>$expr</code> be a <a>value</a> of <code>sh:nodeByExpression</code>.
For each <a>value node</a> <code>v</code>: perform <a>conformance checking</a> of <code>v</code> against each <a>output node</a>
of <code>evalExpr(expr, <a>data graph</a>, v, {})</code> <code>s</code> that is a <a>node shape</a> in the <a>shapes graph</a>.
For each conformance check, a <a>failure</a> MUST be produced if the <a>conformance checking</a> of <code>v</code> against <code>s</code> produces a <a>failure</a>.
Otherwise, if <code>v</code> does not <a>conform</a> to <code>s</code>,
there is a <a>validation result</a> with <code>v</code> as <code>sh:value</code> and a <a>deep copy</a> of <code>s</code> as <code>sh:sourceConstraint</code>.
</div>
</div>
<p><em>The remainder of this section is informative.</em></p>
<p>
<code>sh:nodeByExpression</code> functions similarly to <code>sh:node</code>, but instead of referencing a fixed <a>node shape</a>,
a referenced <a>node expression</a> is used to dynamically compute the set of <a>node shapes</a> to which each <a>value node</a> must conform.
</p>
<p>
Note that `sh:node` and `sh:nodeByExpression` exhibit the same behavior when given a <a>value</a> that is an <a>IRI</a> of a <a>node shape</a>.
In this case, `sh:node` directly validates against the specified <a>node shape</a>, whereas `sh:nodeByExpression` interprets the <a>IRI</a>
as an <a>IRI expression</a> that evaluates to a set containing the same <a>node shape</a>.
</p>
<p>
In the following example, all values of the property <code>ex:address</code> must fulfill the
constraints expressed by the <a>shape</a> <code>ex:AddressShape</code>.
</p>
<aside class="example">
<div class="shapes-graph">
<div class="turtle">
ex:AddressShape
a sh:NodeShape ;
sh:property [
sh:path ex:postalCode ;
sh:datatype xsd:string ;
sh:maxCount 1 ;
] .

ex:PersonShape
a sh:NodeShape ;
<span class="target-can-be-skipped">sh:targetClass ex:Person ;</span>
sh:property [ # _:b1
sh:path ex:address ;
sh:minCount 1 ;
sh:node ex:AddressShape ;
] .
</div>
<div class="jsonld">
<pre class="jsonld">{
"@graph": [
{
"@id": "ex:AddressShape",
"@type": "sh:NodeShape",
"sh:property": {
"sh:datatype": {
"@id": "xsd:string"
},
"sh:maxCount": {
"@type": "xsd:integer",
"@value": "1"
},
"sh:path": {
"@id": "ex:postalCode"
}
}
},
{
"@id": "ex:PersonShape",
"@type": "sh:NodeShape",
"sh:property": {
"sh:minCount": {
"@type": "xsd:integer",
"@value": "1"
},
"sh:node": {
"@id": "ex:AddressShape"
},
"sh:path": {
"@id": "ex:address"
}
},
"sh:targetClass": {
"@id": "ex:Person"
}
}
]
}</pre>
</div>
</div>
<div class="data-graph">
<div class="turtle">
ex:Bob a ex:Person ;
ex:address ex:BobsAddress .

ex:BobsAddress
ex:postalCode "1234" .

<span class="focus-node-error">ex:Reto</span> a ex:Person ;
ex:address ex:RetosAddress .

ex:RetosAddress
ex:postalCode 5678 .
</div>
<div class="jsonld">
<pre class="jsonld">{
"@graph": [
{
"@id": "ex:Bob",
"@type": "ex:Person",
"ex:address": {
"@id": "ex:BobsAddress"
}
},
{
"@id": "ex:BobsAddress",
"ex:postalCode": "1234"
},
{
"@id": "ex:Reto",
"@type": "ex:Person",
"ex:address": {
"@id": "ex:RetosAddress"
}
},
{
"@id": "ex:RetosAddress",
"ex:postalCode": {
"@type": "xsd:integer",
"@value": "5678"
}
}
]
}</pre>
</div>
</div>
<div class="results-graph">
<div class="turtle">
[ a sh:ValidationReport ;
sh:conforms false ;
sh:result [
a sh:ValidationResult ;
sh:resultSeverity sh:Violation ;
sh:focusNode ex:Reto ;
sh:resultPath ex:address ;
sh:value ex:RetosAddress ;
sh:resultMessage "Value does not conform to shape ex:AddressShape." ;
sh:sourceConstraint ex:AddressShape ;
sh:sourceConstraintComponent sh:NodeByExpressionConstraintComponent ;
sh:sourceShape _:b1 ;
]
] .
</div>
<div class="jsonld">
<pre class="jsonld">{
"@type": "sh:ValidationReport",
"sh:conforms": {
"@type": "xsd:boolean",
"@value": "false"
},
"sh:result": {
"@type": "sh:ValidationResult",
"sh:focusNode": {
"@id": "ex:Reto"
},
"sh:resultMessage": "Value does not conform to shape ex:AddressShape.",
"sh:resultPath": {
"@id": "ex:address"
},
"sh:resultSeverity": {
"@id": "sh:Violation"
},
"sh:sourceConstraint": {
"@id": "ex:AddressShape"
},
"sh:sourceConstraintComponent": {
"@id": "sh:NodeByExpressionConstraintComponent"
},
"sh:sourceShape": {
"@id": "_:b66_b1"
},
"sh:value": {
"@id": "ex:RetosAddress"
}
}
}</pre>
</div>
</div>
</aside>
</section>
</section>

<section id="core-components-others">
Expand Down Expand Up @@ -6938,6 +7153,7 @@ <h2>Changes between SHACL 1.0 Core and SHACL 1.2 Core</h2>
<li>Added the new class <a href="#ShapeClass"><code>sh:ShapeClass</code></a> for implicit class targets; see <a href="https://github.com/w3c/data-shapes/issues/212">Issue 212</a></li>
<li>Moved SPARQL-based validators from Core to an Appendix of SHACL-SPARQL; see <a href="https://github.com/w3c/data-shapes/issues/271">Issue 271</a></li>
<li>Added the new constraint component <a href="#ExpressionConstraintComponent"><code>sh:expression</code></a>; see <a href="https://github.com/w3c/data-shapes/issues/357">Issue 357</a></li>
<li>Added the new constraint component <a href="#NodeByExpressionConstraintComponent"><code>sh:nodeByExpression</code></a>, see <a href="https://github.com/w3c/data-shapes/issues/408">Issue 408</a></li>
<li>The values of <a href="#ClassConstraintComponent"><code>sh:class</code></a> and <a href="#DatatypeConstraintComponent"><code>sh:datatype</code></a> can now also be lists, indicating a union of choices; see <a href="https://github.com/w3c/data-shapes/issues/160">Issue 160</a></li>
</ul>
</section>
Expand Down
1 change: 1 addition & 0 deletions shacl12-test-suite/tests/core/node/manifest.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
mf:include <minInclusive-003.ttl> ;
mf:include <minLength-001.ttl> ;
mf:include <node-001.ttl> ;
mf:include <nodeByExpression-001.ttl> ;
mf:include <nodeKind-001.ttl> ;
mf:include <not-001.ttl> ;
mf:include <not-002.ttl> ;
Expand Down
59 changes: 59 additions & 0 deletions shacl12-test-suite/tests/core/node/nodeByExpression-001.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@prefix dash: <http://datashapes.org/dash#> .
@prefix ex: <http://datashapes.org/sh/tests/core/node/nodeByExpression-001.test#> .
@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix sht: <http://www.w3.org/ns/shacl-test#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ex:InvalidInstance
rdf:type ex:TestClass ;
rdfs:label "Invalid instance" ;
.
ex:TestClass
rdf:type rdfs:Class ;
rdf:type sh:NodeShape ;
rdfs:label "Test class" ;
rdfs:subClassOf rdfs:Resource ;
# Only using an IRI Expression here because Core doesn't define interesting node expressions
sh:node ex:TestNodeShape ;
.
ex:TestNodeShape
rdf:type sh:NodeShape ;
sh:class ex:OtherClass ;
.
ex:ValidInstance
rdf:type ex:OtherClass ;
rdf:type ex:TestClass ;
rdfs:label "Valid instance" ;
.
<>
rdf:type mf:Manifest ;
mf:entries (
<nodeByExpression-001>
) ;
.
<nodeByExpression-001>
rdf:type sht:Validate ;
rdfs:label "Test of sh:nodeByExpression at 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:InvalidInstance ;
sh:resultSeverity sh:Violation ;
sh:sourceConstraint ex:TestNodeShape ;
sh:sourceConstraintComponent sh:NodeConstraintComponent ;
sh:sourceShape ex:TestClass ;
sh:value ex:InvalidInstance ;
] ;
] ;
mf:status sht:approved ;
.
1 change: 1 addition & 0 deletions shacl12-test-suite/tests/core/property/manifest.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
mf:include <minLength-001.ttl> ;
mf:include <node-001.ttl> ;
mf:include <node-002.ttl> ;
mf:include <nodeByExpression-001.ttl> ;
mf:include <nodeKind-001.ttl> ;
mf:include <not-001.ttl> ;
mf:include <or-001.ttl> ;
Expand Down
Loading