Skip to content
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

+ collection example #25

Open
wants to merge 5 commits into
base: main
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
234 changes: 233 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1365,8 +1365,240 @@ <h2>Value Sets</h2>
</tbody></table>
</div>
</div>
</section>

<section id="rdf-structures">
<h2>RDF Structures</h2>
<p>
RDF and RDFS specify some RDF structures.
This section describes how ShEx can be used to validate instances of those structures.
</p>

<section id="rdf-collections">
<h2>RDF Collections</h2>

<p>
RDF Collections are a way of creating an ordered list composed of a chain of <span class="predicate"><span class="type">rdf:</span><span class="constant">first</span></span> and <span class="predicate"><span class="type">rdf:</span><span class="constant">rest</span></span> properties.
In the Issue example below, fail0 example violates the constraint that the schema indicates that the list may not be empty. The failU1P1 example fails because the first element is out of range.
The failP1U1 example fails because the last item is out of range.
</p>
<div class="namespace">

<div class="example wrapper">
<!-- ShExC example -->
<pre class="nohighlight schema shexc" style="float:left;"><span class="prefixes"><span class="keyword">BASE</span> <span class="function-name">&lt;http://a.example/schema&gt;</span>
<span class="keyword">PREFIX</span> <span class="type">:</span> <span class="function-name">&lt;#&gt;</span><span class="comment">
</span><span class="keyword">PREFIX</span> <span class="type">xsd:</span> <span class="function-name">&lt;http://www.w3.org/2001/XMLSchema#&gt;</span><span class="comment">
</span><span class="keyword">PREFIX</span> <span class="type">rdf:</span> <span class="function-name">&lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#&gt;</span><span class="comment">
</span>
</span><span class="shape-name">&lt;#Issue&gt;</span><span class="comment"> { </span><span class="type">:</span><span class="constant">affects</span><span class="comment"> </span><span class="shape-name">@&lt;#List_Product&gt;</span><span class="comment"> }
</span>
<span class="shape-name">&lt;#List_Product&gt;</span><span class="comment"> </span><span class="keyword">CLOSED</span><span class="comment"> {
</span> <span class="type">rdf:</span><span class="constant">first</span> <span class="shape-name">@&lt;#Product&gt;</span><span class="comment"> ;
</span> <span class="type">rdf:</span><span class="constant">rest</span> [<span class="type">rdf:</span><span class="constant">nil</span>] <span class="keyword">OR</span> <span class="shape-name">@&lt;#List_Product&gt;</span><span class="comment">
</span>}

<span class="shape-name">&lt;#Product&gt;</span><span class="comment"> {
</span> <span class="type">:</span><span class="constant">number</span> <span class="type">xsd:</span><span class="constant">integer</span> ;
<span class="type">:</span><span class="constant">name</span> <span class="keyword">LITERAL</span>
}

<span class="shape-name">&lt;#User&gt;</span><span class="comment"> {
</span> <span class="type">:</span><span class="constant">name</span> <span class="keyword">LITERAL</span>
}</pre>

<!-- JSON example -->
<pre class="nohighlight schema json" style="float:left;">{
"type": "Schema",
"shapes": [
{
"type": "Shape",
"id": "http://a.example/schema#Issue",
"expression": {
"type": "TripleConstraint",
"predicate": "http://a.example/schema#affects",
"valueExpr": "http://a.example/schema#List_Product"
}
},
{
"type": "Shape",
"id": "http://a.example/schema#List_Product",
"closed": true,
"expression": {
"type": "EachOf",
"expressions": [
{
"type": "TripleConstraint",
"predicate": "http://www.w3.org/1999/02/22-rdf-syntax-ns#first",
"valueExpr": "http://a.example/schema#Product"
},
{
"type": "TripleConstraint",
"predicate": "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest",
"valueExpr": {
"type": "ShapeOr",
"shapeExprs": [
{
"type": "NodeConstraint",
"values": [
"http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"
]
},
"http://a.example/schema#List_Product"
]
}
}
]
}
},
{
"type": "Shape",
"id": "http://a.example/schema#Product",
"expression": {
"type": "EachOf",
"expressions": [
{
"type": "TripleConstraint",
"predicate": "http://a.example/schema#number",
"valueExpr": {
"type": "NodeConstraint",
"datatype": "http://www.w3.org/2001/XMLSchema#integer"
}
},
{
"type": "TripleConstraint",
"predicate": "http://a.example/schema#name",
"valueExpr": {
"type": "NodeConstraint",
"nodeKind": "literal"
}
}
]
}
},
{
"type": "Shape",
"id": "http://a.example/schema#User",
"expression": {
"type": "TripleConstraint",
"predicate": "http://a.example/schema#name",
"valueExpr": {
"type": "NodeConstraint",
"nodeKind": "literal"
}
}
}
]
}</pre>
<pre class="nohighlight instance turtle pass tryable"><span class="prefixes"><span class="keyword">BASE</span> <span class="function-name">&lt;http://a.example/data#&gt;</span><span class="comment">
</span><span class="keyword">PREFIX</span> <span class="type">:</span> <span class="function-name">&lt;http://a.example/schema#&gt;</span><span class="comment">
</span>
</span><span class="relativeURL">&lt;#passP1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">affects</span><span class="comment"> (</span><span class="relativeURL">&lt;#Product1&gt;</span><span class="comment">) </span><span class="keyword">.</span><span class="comment">
</span><span class="relativeURL">&lt;#passP1P2&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">affects</span><span class="comment"> (</span><span class="relativeURL">&lt;#Product1&gt;</span><span class="comment"> </span><span class="relativeURL">&lt;#Product2&gt;</span><span class="comment">) </span><span class="keyword">.</span><span class="comment">
</span>
<span class="fail inst-User6 lowlight2 top"><span class="relativeURL">&lt;#fail0&gt;</span> <span class="comment"> </span><span class="type">:</span><span class="constant">affects</span><span class="comment"> () </span><span class="keyword">.</span><!-- span class="comment"> # empty list not allowed</span --> </span>
<span class="fail inst-User6 lowlight2"><span class="relativeURL">&lt;#failU1P1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">affects</span><span class="comment"> (</span><span class="relativeURL">&lt;#User1&gt;</span><span class="comment"> </span><span class="relativeURL">&lt;#Product1&gt;</span><span class="comment">) </span><span class="keyword">.</span><!-- span class="comment"> # bad 1st element</span --></span>
<span class="fail inst-User6 lowlight2 bot"><span class="relativeURL">&lt;#failP1U1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">affects</span><span class="comment"> (</span><span class="relativeURL">&lt;#Product1&gt;</span><span class="comment"> </span><span class="relativeURL">&lt;#User1&gt;</span><span class="comment">) </span><span class="keyword">.</span><!-- span class="comment"> # bad last element</span --></span>

<span class="relativeURL">&lt;#Product1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">number</span><span class="comment"> 1 ; </span><span class="type">:</span><span class="constant">name</span><span class="comment"> </span><span class="string">"toaster"</span><span class="comment"> </span><span class="keyword">.</span><span class="comment">
</span><span class="relativeURL">&lt;#Product2&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">number</span><span class="comment"> 2 ; </span><span class="type">:</span><span class="constant">name</span><span class="comment"> </span><span class="string">"blender"</span><span class="comment"> </span><span class="keyword">.</span><span class="comment">
</span>
<span class="relativeURL">&lt;#User1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">name</span> <span class="string">"Alice"</span><span class="comment"> </span><span class="keyword">.</span>
<a class="tryit" href="" data-shape-map="&lt;#passP1&gt;@&lt;http://a.example/schema#Issue&gt;,
&lt;#passP1P2&gt;@&lt;http://a.example/schema#Issue&gt;,
&lt;#fail0&gt;@&lt;http://a.example/schema#Issue&gt;,
&lt;#failU1P1&gt;@&lt;http://a.example/schema#Issue&gt;,
&lt;#failP1U1&gt;@&lt;http://a.example/schema#Issue&gt;">try it</a></pre>
<div style="clear:both;"></div>
</div>
<table class="example results">
<tbody><tr><th class="data">Node</th><th class="schema">Shape</th><th>Result</th><th>Reason</th></tr>
<tr class="pass"><td class="relativeURL">passP1 </td><td class="shape-name">Issue</td><td>pass</td><td class="noreason"></td></tr>
<tr class="pass"><td class="relativeURL">passP1P2</td><td class="shape-name">Issue</td><td>pass</td><td class="noreason"></td></tr>
<tr class="fail"><td class="relativeURL">fail0</td> <td class="shape-name">Issue</td><td>fail</td><td class="fail">schema prohibits empty lists.</td></tr>
<tr class="fail"><td class="relativeURL">failU1P1</td> <td class="shape-name">Issue</td><td>fail</td><td class="fail">bad first element.</td></tr>
<tr class="fail"><td class="relativeURL">failP1U1</td> <td class="shape-name">Issue</td><td>fail</td><td class="fail">bad last element.</td></tr>
</tbody></table>
</div>
</section>

<section id="ambiguous-grammar">
<h2>Ambiguous Grammar</h2>

<p>
In the previous example, Products are distinct from Users in that they have a <span class="predicate"><span class="type">:</span><span class="constant">productNumber</span></span>.
Products can, however, masquerade as Users, so long as the User shape is not CLOSED.
Specifically, the Product instance (<span class="relativeURL">&lt;#Product1&gt;</span>) meets the criteria for a User, i.e. it has a <span class="type">:</span><span class="constant">name</span>.
When validated as a User, the extra <span class="type">:</span><span class="constant">productNumber</span> is irrelevant (so long as the User shape is not CLOSED).
</p>
<div class="namespace">

<div class="example wrapper">
<!-- ShExC example -->
<pre class="nohighlight schema shexc" style="float:left;"><span class="prefixes"><span class="keyword">BASE</span> <span class="relativeURL">&lt;http://a.example/schema&gt;</span>
<span class="keyword">PREFIX</span> <span class="type">:</span> <span class="relativeURL">&lt;#&gt;</span>
<span class="keyword">PREFIX</span> <span class="type">xsd:</span> <span class="relativeURL">&lt;http://www.w3.org/2001/XMLSchema#&gt;</span>
<span class="keyword">PREFIX</span> <span class="type">rdf:</span> <span class="relativeURL">&lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#&gt;</span>

</span><span class="relativeURL">&lt;#Issue&gt;</span><span class="comment"> { </span><span class="type">:</span><span class="constant">reporter</span><span class="comment"> </span><span class="relativeURL">@&lt;#List_User&gt;</span><span class="comment"> }
</span>
<span class="relativeURL">&lt;#List_User&gt;</span><span class="comment"> </span><span class="keyword">CLOSED</span><span class="comment"> {
</span> <span class="type">rdf:</span><span class="constant">first</span> <span class="relativeURL">@&lt;#User&gt;</span><span class="comment"> ;
</span> <span class="type">rdf:</span><span class="constant">rest</span> [<span class="type">rdf:</span><span class="constant">nil</span>] <span class="keyword">OR</span> <span class="relativeURL">@&lt;#List_User&gt;</span><span class="comment">
</span>}

<span class="relativeURL">&lt;#User&gt;</span><span class="comment"> </span><span class="comment">/*not CLOSED*/</span><span class="comment"> {
</span> <span class="type">:</span><span class="constant">name</span> <span class="keyword">LITERAL</span>
}

<span class="relativeURL">&lt;#Product&gt;</span><span class="comment"> {
</span> <span class="type">:</span><span class="constant">number</span> <span class="type">xsd:</span><span class="constant">integer</span> ;
<span class="type">:</span><span class="constant">name</span> <span class="keyword">LITERAL</span>
}</pre>

<!-- JSON example -->
<pre class="nohighlight schema json" style="float:left;"></pre>
<pre class="nohighlight instance turtle pass tryable"><span class="prefixes"><span class="keyword">BASE</span> <span class="relativeURL">&lt;http://a.example/data#&gt;</span><span class="comment">
</span><span class="keyword">PREFIX</span> <span class="type">:</span> <span class="relativeURL">&lt;http://a.example/schema#&gt;</span><span class="comment"></span>

</span><span class="relativeURL">&lt;#passU1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">reporter</span><span class="comment"> (</span><span class="relativeURL">&lt;#User1&gt;</span><span class="comment">) </span><span class="keyword">.</span><span class="comment">
</span><span class="relativeURL">&lt;#passU1U2&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">reporter</span><span class="comment"> (</span><span class="relativeURL">&lt;#User1&gt;</span><span class="comment"> </span><span class="relativeURL">&lt;#User2&gt;</span><span class="comment">) </span><span class="keyword">.</span>

<span class="comment"># Nodes that would fail if User <span title="note gratuitous use of subjunctive">were</span> CLOSED</span>
<span class="relativeURL">&lt;#failP1U1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">reporter</span><span class="comment"> (</span><span class="relativeURL">&lt;#Product1&gt;</span><span class="comment"> </span><span class="relativeURL">&lt;#User1&gt;</span><span class="comment">) </span><span class="keyword">.</span><span class="comment">
</span><span class="relativeURL">&lt;#failU1P1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">reporter</span><span class="comment"> (</span><span class="relativeURL">&lt;#User1&gt;</span><span class="comment"> </span><span class="relativeURL">&lt;#Product1&gt;</span><span class="comment">) </span><span class="keyword">.</span><span class="comment">
</span>
<span class="relativeURL">&lt;#User1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">name</span><span class="comment"> </span><span class="string">"Alice"</span><span class="comment"> </span><span class="keyword">.</span><span class="comment">
</span><span class="relativeURL">&lt;#User2&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">name</span><span class="comment"> </span><span class="string">"Alicia"</span><span class="comment"> </span><span class="keyword">.</span><span class="comment">
</span>
<span class="relativeURL">&lt;#Product1&gt;</span><span class="comment"> </span><span class="type">:</span><span class="constant">number</span><span class="comment"> 1 ; </span><span class="type">:</span><span class="constant">name</span><span class="comment"> </span><span class="string">"toaster"</span><span class="comment"> </span><span class="keyword">.</span><a class="tryit" href="" data-shape-map="&lt;#passU1&gt;@&lt;http://a.example/schema#Issue&gt;,
&lt;#passU1U2&gt;@&lt;http://a.example/schema#Issue&gt;,
&lt;#failP1U1&gt;@&lt;http://a.example/schema#Issue&gt;,
&lt;#failU1P1&gt;@&lt;http://a.example/schema#Issue&gt;">try it</a></pre>
<div style="clear:both;"></div>
</div>
<table class="example results">
<tbody><tr><th class="data">Node</th><th class="schema">Shape</th><th>Result</th><th>Reason</th></tr>
<tr class="pass"><td class="relativeURL">passU1 </td><td class="shape-name">Issue</td><td>pass</td><td class="noreason"></td></tr>
<tr class="pass"><td class="relativeURL">passU1U2</td><td class="shape-name">Issue</td><td>pass</td><td class="noreason"></td></tr>
<tr class="pass"><td class="relativeURL">failP1U1</td> <td class="shape-name">Issue</td><td>pass</td><td class="pass">first element "looks" like a User.</td></tr>
<tr class="pass"><td class="relativeURL">failU1P1</td> <td class="shape-name">Issue</td><td>pass</td><td class="pass">last element "looks" like a User.</td></tr>
</tbody></table>
</div>

<p>
If URLs in the data are expected to conform to some naming pattern, this can be enforced with regular expressions on the shape, e.g.
</p>
<div class="example wrapper">
<pre class="nohighlight schema shexc">
<span class="shape-name">&lt;#User&gt;</span> <span class="string">/User/</span> {
<span class="type">:</span><span class="constant">name</span> <span class="keyword">LITERAL</span>
}
</pre>
</div>
</section>
</section>
</section>
</section>

<section id="advanced">
<h2>Advanced Concepts</h2>
Expand Down
8 changes: 8 additions & 0 deletions local.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
/* font-lock-function-name-face */
color: #0000ff;
}
.relativeURL {
/* font-lock-function-name-face */
color: #0000ff;
}
.relativeURL:visited {
/* font-lock-function-name-face */
color: #0000ff;
}
.keyword, .schema .keyword.object {
/* font-lock-keyword-face */
color: #a020f0;
Expand Down