Skip to content

Commit a62647f

Browse files
HolgerKnublauchajnelson-nistTallTed
authored
#288: Added sh:SelectExpression, with test cases and TTL changes (#297)
* #288: Added sh:SelectExpression, with test cases and TTL changes * #222, #288: Update SHACL-SHACL for general NodeExpression and SelectExpression Signed-off-by: Alex Nelson <[email protected]> * #222, #288: Undo update SHACL-SHACL for general NodeExpression and SelectExpression This patch undoes commit 8632a3e. This was done manually instead of with `git revert`. Signed-off-by: Alex Nelson <[email protected]> * Update shacl12-vocabularies/shacl.ttl Co-authored-by: Ted Thibodeau Jr <[email protected]> --------- Signed-off-by: Alex Nelson <[email protected]> Co-authored-by: Alex Nelson <[email protected]> Co-authored-by: Ted Thibodeau Jr <[email protected]>
1 parent 258fcee commit a62647f

File tree

8 files changed

+339
-1
lines changed

8 files changed

+339
-1
lines changed

shacl12-core/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1658,7 +1658,7 @@ <h3>Node Expressions</h3>
16581658
</p>
16591659
<aside class="example" title="A dynamically computed property using a node expression based on a SPARQL query">
16601660
<p>
1661-
Here is an example use of a node expression based on <a href="shacl12-sparql">SHACL-SPARQL</a>, computing
1661+
Here is an example use of a node expression based on <a data-cite="shacl12-sparql#SelectExpression">SHACL-SPARQL</a>, computing
16621662
the values of a property shape for the property "full name" as the concatenation of <code>ex:firstName</code>,
16631663
a space and the <code>ex:lastName</code>.
16641664
</p>

shacl12-sparql/index.html

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ <h3>Terminology</h3>
383383
<dfn data-cite="rdf12-concepts#dfn-literal" data-lt="literal|literals">literal</dfn>,
384384
<dfn data-cite="rdf12-concepts#dfn-blank-node" data-lt="blank node|blank nodes">blank node</dfn>,
385385
<dfn data-cite="rdf12-concepts#dfn-node" data-lt="node|nodes">node</dfn> of an RDF graph,
386+
<dfn data-cite="rdf12-concepts#dfn-datatype" data-lt="datatype|datatypes">datatype</dfn>,
386387
<dfn data-cite="rdf12-concepts#dfn-rdf-term" data-lt="term|terms">RDF term</dfn>, and
387388
<dfn data-cite="rdf12-concepts#dfn-subject" data-lt="subject|subjects">subject</dfn>,
388389
<dfn data-cite="rdf12-concepts#dfn-predicate" data-lt="predicate|predicates">predicate</dfn>, and
@@ -410,6 +411,11 @@ <h3>Terminology</h3>
410411
<dfn data-cite="shacl12-core#dfn-shapes-graph" data-lt="shapes graph">shapes graph</dfn>,
411412
<dfn data-cite="shacl12-core#dfn-target" data-lt="target|targets">target</dfn>,
412413
<dfn data-cite="shacl12-core#dfn-validators" data-lt="validator|validators">validator</dfn>,
414+
<dfn data-cite="shacl12-core#dfn-node-expression" data-lt="node expression|node expresssions">node expression</dfn>,
415+
<dfn data-cite="shacl12-core#dfn-node-expression-function" data-lt="node expression function|node expresssion functions">node expression function</dfn>,
416+
<dfn data-cite="shacl12-core#dfn-function-name" data-lt="node expression function name">function name</dfn>,
417+
<dfn data-cite="shacl12-core#dfn-key-parameter" data-lt="key parameter">key parameter</dfn>,
418+
<dfn data-cite="shacl12-core#dfn-output-nodes" data-lt="output nodes">output nodes</dfn>,
413419
<dfn data-cite="shacl12-core#dfn-conform" data-lt="conform|conforms">conform</dfn>,
414420
<dfn data-cite="shacl12-core#dfn-failure" data-lt="failure|failures">failure</dfn>,
415421
<dfn data-cite="shacl12-core#dfn-shacl-instance" data-lt="shacl instance">SHACL instance</dfn>,
@@ -1206,6 +1212,118 @@ <h3>Validation with SPARQL-based Constraint Components</h3>
12061212
</section>
12071213
</section>
12081214

1215+
<section id="sparql-node-expressions">
1216+
<h2>SPARQL-based Node Expressions</h2>
1217+
<p>
1218+
This section introduces <a>node expression functions</a> based on SPARQL.
1219+
</p>
1220+
1221+
<section id="SelectExpression">
1222+
<h3>Select Expressions</h3>
1223+
<p>
1224+
A <a>node expression</a> that has a <a>value</a> for <code>sh:select</code> is called a <dfn>select expression</dfn> with the <a>function name</a>
1225+
<code>sh:SelectExpression</code>.
1226+
</p>
1227+
<p class="syntax">
1228+
<span data-syntax-rule="SelectExpression-syntax">A node in an RDF graph is a <a>well-formed</a> <a>select expression</a> if it is a <a>blank node</a>
1229+
that is the <a>subject</a> of exactly one <a>triple</a> with <code>sh:select</code> as <a>predicate</a> and a <a>literal</a> as <a>object</a>
1230+
with <a>datatype</a> <code>xsd:string</code>.</span>
1231+
<span data-syntax-rule="SelectExpression-query-valid">Using the <a href="#sparql-prefixes">prefix handling rules</a>, the value of <code>sh:select</code> is a valid SPARQL 1.2 SELECT query.</span>
1232+
<span data-syntax-rule="SelectExpression-query-output-nodes">The SPARQL query derived from the value of <code>sh:select</code> <a data-cite="sparql12-query/#selectproject">projects</a> exactly one variable in the SELECT clause.</span>
1233+
</p>
1234+
<div class="def" id="LiteralExpression-evaluation">
1235+
<div class="def-header">EVALUATION OF SELECT EXPRESSIONS</div>
1236+
<p>
1237+
The <a>output nodes</a> of a <a>select expression</a> are the list <code>resultNodes</code> consisting of exactly the bindings of the (only)
1238+
variable that is projected from the SELECT clause.
1239+
If present in the <a>scope</a>, the value of the scope variable <code>focusNode</code> MUST be <a>pre-bound</a> as the value of the SPARQL variable <code>this</code>.
1240+
<br/>
1241+
<br/>
1242+
<code>eval(expr, activeGraph, scope) -> resultNodes</code>
1243+
</p>
1244+
</div>
1245+
<p><em>The remainder of this section is informative.</em></p>
1246+
<aside class="example" title="A dynamically computed property using a node expression based on a SPARQL query">
1247+
<p>
1248+
Here is an example use of a <a>select expression</a>, computing the values of a property shape for the property
1249+
"full name" as the concatenation of <code>ex:firstName</code>, a space and the <code>ex:lastName</code>.
1250+
</p>
1251+
<div class="shapes-graph">
1252+
<div class="turtle">
1253+
ex:Person-fullName
1254+
a sh:PropertyShape ;
1255+
sh:name "full name" ;
1256+
sh:path <b>[
1257+
sh:prefixes &lt;http://example.org/ns&gt; ;
1258+
sh:select """
1259+
SELECT ?fullName
1260+
WHERE {
1261+
$this ex:firstName ?firstName .
1262+
$this ex:lastName ?lastName .
1263+
BIND (CONCAT(?firstName, " ", ?lastName) AS ?fullName) .
1264+
}
1265+
"""
1266+
]</b> ;
1267+
sh:datatype xsd:string .
1268+
1269+
&lt;http://example.org/ns&gt;
1270+
a owl:Ontology ;
1271+
sh:declare [
1272+
sh:prefix "ex" ;
1273+
sh:namespace "http://example.org/ns#"^^xsd:anyURI ;
1274+
] .
1275+
</div>
1276+
</div>
1277+
<p>
1278+
This example also illustrates the use of <code>sh:prefixes</code> to insert PREFIX declarations into the beginning of the query before parsing.
1279+
Note that the query is executed with the current <a>focus node</a> <a>pre-bound</a> to the variable <code>this</code>.
1280+
</p>
1281+
</aside>
1282+
<aside class="example" title="Dynamically computed target nodes using a node expression based on a SPARQL query">
1283+
<p>
1284+
Here is an example use of a <a>select expression</a>, computing the target nodes of a shape to consist of all instances of
1285+
<code>ex:Person</code> where the <code>ex:age</code> is less than <code>18</code>.
1286+
</p>
1287+
<div class="shapes-graph">
1288+
<div class="turtle">
1289+
ex:ChildShape
1290+
a sh:NodeShape ;
1291+
rdfs:label "Child shape" ;
1292+
rdfs:comment "This shape applies to all persons under 18 years of age." ;
1293+
sh:targetNode <b>[
1294+
sh:select """
1295+
PREFIX ex: &lt;http://example.org/ns#&gt;
1296+
SELECT ?person
1297+
WHERE {
1298+
?person a/rdfs:subClassOf* ex:Person .
1299+
?person ex:age ?age .
1300+
FILTER (?age &lt; 18) .
1301+
}
1302+
"""
1303+
]</b> .
1304+
</div>
1305+
</div>
1306+
<p>
1307+
From the following data graph, only <code>ex:Benjamin</code> is a target node.
1308+
</p>
1309+
<div class="data-graph">
1310+
<div class="turtle">
1311+
<span class="focus-node-selected">ex:Benjamin</span>
1312+
a ex:Person ;
1313+
ex:age 17 .
1314+
1315+
ex:Klaus
1316+
a ex:Person ;
1317+
ex:age 48 .
1318+
1319+
ex:Bernd
1320+
a ex:Person .
1321+
</div>
1322+
</div>
1323+
</aside>
1324+
</section>
1325+
</section>
1326+
12091327
<div style="padding-top: 30px">
12101328
<h1 id="appendix" style="font-size: 160%; font-weight: bold">Appendix</h1>
12111329
</div>
@@ -1535,6 +1653,13 @@ <h2>Revision History</h2>
15351653
<li><b>2024-02-14</b>: New work started by cloning the main SHACL spec and splitting it into SHACL Core and SHACL-SPARQL</li>
15361654
</ul>
15371655
</section>
1656+
1657+
<section class="appendix informative" id="changes-12">
1658+
<h2>Changes between SHACL 1.0 SPARQL and SHACL 1.2 SPARQL Extensions</h2>
1659+
<ul>
1660+
<li>Added the <a>node expression function</a> <a href="#SelectExpression"><code>sh:SelectExpression</code></a>, see <a href="https://github.com/w3c/data-shapes/issues/288">Issue 288</a></li>
1661+
</ul>
1662+
</section>
15381663

15391664
</body>
15401665

shacl12-test-suite/tests/sparql/manifest.ttl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
mf:include <node/manifest.ttl> ;
99
mf:include <property/manifest.ttl> ;
1010
mf:include <pre-binding/manifest.ttl> ;
11+
mf:include <targets/manifest.ttl> ;
1112
.

shacl12-test-suite/tests/sparql/property/manifest.ttl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
<>
66
a mf:Manifest ;
77
rdfs:label "Tests converted from http://datashapes.org/sh/tests/tests/sparql/property" ;
8+
mf:include <property-select-001.ttl> ;
89
mf:include <sparql-001.ttl> ;
910
.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
@prefix dash: <http://datashapes.org/dash#> .
2+
@prefix ex: <http://example.org/ns#> .
3+
@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
4+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
5+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
6+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
7+
@prefix sh: <http://www.w3.org/ns/shacl#> .
8+
@prefix sht: <http://www.w3.org/ns/shacl-test#> .
9+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
10+
11+
ex:Person-fullName
12+
a sh:PropertyShape ;
13+
sh:targetClass ex:Person ;
14+
sh:name "full name" ;
15+
sh:path [
16+
sh:prefixes <http://example.org/ns> ;
17+
sh:select """
18+
SELECT ?fullName
19+
WHERE {
20+
$this ex:firstName ?firstName .
21+
$this ex:lastName ?lastName .
22+
BIND (CONCAT(?firstName, " ", ?lastName) AS ?fullName) .
23+
}
24+
"""
25+
] ;
26+
sh:datatype xsd:string ;
27+
sh:hasValue "John Muir" .
28+
29+
<http://example.org/ns>
30+
a owl:Ontology ;
31+
sh:declare [
32+
sh:prefix "ex" ;
33+
sh:namespace "http://example.org/ns#"^^xsd:anyURI ;
34+
] .
35+
36+
ex:JohnMuir
37+
a ex:Person ;
38+
ex:firstName "John" ;
39+
ex:lastName "Muir" .
40+
41+
ex:JohnWayne
42+
a ex:Person ;
43+
ex:firstName "John" ;
44+
ex:lastName "Wayne" .
45+
46+
<>
47+
rdf:type mf:Manifest ;
48+
mf:entries (
49+
<property-select-001>
50+
) ;
51+
.
52+
<property-select-001>
53+
rdf:type sht:Validate ;
54+
rdfs:label "Test of a sh:property with a sh:select expression 001" ;
55+
mf:action [
56+
sht:dataGraph <> ;
57+
sht:shapesGraph <> ;
58+
] ;
59+
mf:result [
60+
rdf:type sh:ValidationReport ;
61+
sh:conforms "false"^^xsd:boolean ;
62+
sh:result [
63+
rdf:type sh:ValidationResult ;
64+
sh:focusNode ex:JohnWayne ;
65+
sh:resultPath [
66+
sh:prefixes <http://example.org/ns> ;
67+
sh:select """
68+
SELECT ?fullName
69+
WHERE {
70+
$this ex:firstName ?firstName .
71+
$this ex:lastName ?lastName .
72+
BIND (CONCAT(?firstName, " ", ?lastName) AS ?fullName) .
73+
}
74+
"""
75+
] ;
76+
sh:resultSeverity sh:Violation ;
77+
sh:sourceConstraintComponent sh:HasValueConstraintComponent ;
78+
sh:sourceShape ex:Person-fullName ;
79+
] ;
80+
] ;
81+
mf:status sht:approved ;
82+
.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
2+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
3+
@prefix sht: <http://www.w3.org/ns/shacl-test#> .
4+
5+
<>
6+
a mf:Manifest ;
7+
rdfs:label "Tests for SPARQL-based targets" ;
8+
mf:include <targetNode-select-001.ttl> ;
9+
.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
@prefix dash: <http://datashapes.org/dash#> .
2+
@prefix ex: <http://example.org/ns#> .
3+
@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
4+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
5+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
6+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
7+
@prefix sh: <http://www.w3.org/ns/shacl#> .
8+
@prefix sht: <http://www.w3.org/ns/shacl-test#> .
9+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
10+
11+
ex:ChildShape
12+
a sh:NodeShape ;
13+
rdfs:label "Child shape" ;
14+
rdfs:comment "This shape applies to all persons under 18 years of age." ;
15+
sh:targetNode [
16+
sh:select """
17+
PREFIX ex: <http://example.org/ns#>
18+
SELECT ?person
19+
WHERE {
20+
?person a/rdfs:subClassOf* ex:Person .
21+
?person ex:age ?age .
22+
FILTER (?age < 18) .
23+
}
24+
"""
25+
] ;
26+
sh:property ex:ChildShape-driversLicense .
27+
28+
ex:ChildShape-driversLicense
29+
a sh:PropertyShape ;
30+
sh:path ex:driversLicense ;
31+
sh:maxCount 0 .
32+
33+
ex:Benjamin
34+
a ex:Person ;
35+
ex:driversLicense "123" ;
36+
ex:age 17 .
37+
38+
ex:Klaus
39+
a ex:Person ;
40+
ex:driversLicense "456" ;
41+
ex:age 48 .
42+
43+
ex:Bernd
44+
a ex:Person ;
45+
ex:driversLicense "789" .
46+
47+
<>
48+
rdf:type mf:Manifest ;
49+
mf:entries (
50+
<targetNode-select-001>
51+
) ;
52+
.
53+
<targetNode-select-001>
54+
rdf:type sht:Validate ;
55+
rdfs:label "Test of sh:targetNode with a sh:select expression 001" ;
56+
mf:action [
57+
sht:dataGraph <> ;
58+
sht:shapesGraph <> ;
59+
] ;
60+
mf:result [
61+
rdf:type sh:ValidationReport ;
62+
sh:conforms "false"^^xsd:boolean ;
63+
sh:result [
64+
rdf:type sh:ValidationResult ;
65+
sh:focusNode ex:Benjamin ;
66+
sh:resultPath ex:driversLicense ;
67+
sh:resultSeverity sh:Violation ;
68+
sh:sourceConstraintComponent sh:MaxCountConstraintComponent ;
69+
sh:sourceShape ex:ChildShape-driversLicense ;
70+
] ;
71+
] ;
72+
mf:status sht:approved ;
73+
.

0 commit comments

Comments
 (0)