SHACL JavaScript Extensions (original) (raw)
Abstract
This document defines a JavaScript-based extension mechanism for the Shapes Constraint Language (SHACL). It defines a syntax for declaring constraints, constraint components, functions, rules and targets in JavaScript. Using this syntax, SHACL shapes can benefit from the rich expressive power of JavaScript. In order to ensure that the resulting JavaScript code can be executed across platforms, this document defines a (minimalistic) JavaScript API that needs to be implemented by supporting engines.
Status of This Document
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
Future revisions of this document may be produced by a SHACL W3C Community Group.
This document was published by the RDF Data Shapes Working Group as a First Public Working Group Note. Comments regarding this document are welcome. Please send them topublic-rdf-shapes@w3.org (subscribe,archives).
Publication as a Working Group Note does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the5 February 2004 W3C Patent Policy.W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes containsEssential Claim(s) must disclose the information in accordance withsection 6 of the W3C Patent Policy.
This document is governed by the 1 March 2017 W3C Process Document.
Table of Contents
- 1. Introduction
- 2. Conformance
- 3. JavaScript API for RDF
- 4. Representing JavaScript in RDF
- 5. Executing JavaScript
- 6. JavaScript-based Constraints
- 7. JavaScript-based Constraint Components
- 8. JavaScript-based Functions
- 9. JavaScript Rules
- 10. JavaScript-based Custom Targets
- 10.1 JavaScript-based Targets (sh:JSTarget)
- 10.2 JavaScript-based Target Types (sh:JSTargetType)
- A. Summary of SHACL-JS Syntax Rules
- B. Security and Privacy Considerations
- C. References
- C.1 Normative references
- C.2 Informative references
Document Conventions
Some examples in this document use Turtle [turtle]. The reader is expected to be familiar with SHACL [shacl] and the SHACL Advanced Features [shacl-af].
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# |
xsd: | http://www.w3.org/2001/XMLSchema# |
ex: | http://example.com/ns# |
Throughout the document, color-coded boxes containing RDF graphs in Turtle will appear. These fragments of Turtle documents use the prefix bindings given above.
This box represents a shapes graph
.
// This box contains JavaScript code
This box represents a data graph.
This box represents an output results graph
Formal definitions appear in blue boxes:
This box contains textual definitions.
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
.
Terminology
The terminology used throughout this document is consistent with the definitions in the main SHACL [shacl] specification, which references terms from RDF [rdf11-concepts]. This includes the termsblank node,conformance,constraint,constraint component,data graph,datatype,failure,focus node,RDF graph,ill-formed,IRI,literal,local name,node,node shape,object,parameter,predicate,property shape,RDF term,SHACL instance,shape,shapes graph,subject,target,triple,validation,validation report,validation result,validator,value,value node. Additional terms are defined in the SHACL Advanced Features document [shacl-af]:custom target,rule type,rule,SHACL function.
1. Introduction
The Shapes Constraint Language (SHACL) [shacl] is a language for validating RDF graphs against a set of conditions. These conditions are provided as shapes and other constructs expressed in the form of an RDF graph. SHACL is represented in RDF and consists of a SHACL Core RDF vocabulary with terms such as sh:minCount
to express the most frequently needed constraint kinds. However, in order to express more complex constraints, the SHACL Core vocabulary is often not sufficient. SHACL-SPARQL [shacl] is one extension mechanism for SHACL to express constraints in SPARQL, allowing shape definitions to point at executable SPARQL [sparql11-query] queries to perform the validation checks. This document defines the SHACL JavaScript Extensions (SHACL-JS), allowing users to express SHACL constraints and the advanced features of custom targets, functions and rules with the help of JavaScript.
SHACL-JS is based on a similar design to SHACL-SPARQL, but for JavaScript instead of SPARQL. The basic idea is that SHACL shapes can point at JavaScript functions in specified JavaScript files that can be resolved from the web. When shapes get evaluated, a SHACL-JS engine calls those functions with a predefined set of arguments and constructs validation results from the values and objects returned by these JavaScript function calls. The JavaScript code can access RDF triples from both the shapes graph and the data graph where needed, through the JavaScript API that is defined in this document, or a higher-level JavaScript API that uses the specified API under the hood.
As a result of this design, SHACL shape definitions can be augmented with JavaScript and executed either within web browsers (assuming the SHACL engine operates on the client), or on servers that support JavaScript execution.
2. Conformance
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MUST and MUST NOT are to be interpreted as described in [RFC2119].
3. JavaScript API for RDF
This section defines an API that JavaScript-based SHACL functions can use to operate onRDF terms and to query triples in graphs. The JavaScript code behind SHACL-JS constraints and constraint components can directly access those functions or go through a higher-level layer of convenience functions that use these functions under the hood.
Note that the API expects these JavaScript Objects to be immutable, i.e. neither the values of an RDF term nor triples norgraphs can be modified during SHACL validation.
3.1 RDF Terms
All RDF terms (IRIs, blank nodes and literals) are represented using JavaScript Objects that have attributes as described in the following three subsections. The following table summarizes key functions to create and operate on RDF term Objects:
Node Kind | Factory Function | Test Function | Attributes |
---|---|---|---|
IRIs | TermFactory.namedNode(uri) | .isURI() | uri |
Blank Nodes | TermFactory.blankNode(id) or TermFactory.blankNode() | .isBlankNode() | id |
Literals | TermFactory.literal(lex, languageOrDatatype) | .isLiteral() | datatype, language, lex |
Note that the attributes in the table above are only defined for Objects that have matching types. For example, the result of querying the uri
of a blank node is undefined.
Each of these Objects must have a function .equals(other)
that takes another term Object as its only parameter and returns true
exactly if the underlying RDF terms are equal, and false
otherwise.
3.1.1 IRIs / Named Nodes
An IRI is represented by a JavaScript NamedNode
Object where .isURI()
returns true
while .isBlankNode()
and .isLiteral()
return false
. The value of the read-only attribute uri
is the IRI string.
3.1.2 Blank Nodes
A blank node is represented by a JavaScript BlankNode
Object where .isBlankNode()
returns true
while .isURI()
and .isLiteral()
return false
. The value of the read-only attribute id
is the blank node identifier as a string. That string is must be consistent for the same RDF node for the duration of a SHACL validation and processing of validation results.
3.1.3 Literals
A literal is represented by a JavaScript Literal
Object where .isLiteral()
returns true
while .isURI()
and .isBlankNode()
return false
. The value of the read-only attribute language
is a lowercase BCP-47 [BCP47] string (for example, en
, en-gb
), or an empty string if the literal has no language. The value of the read-only attribute datatype
is a NamedNode representing the datatype IRI of the literal. Note that this datatype
is never undefined, and language-tagged strings have rdf:langString
as their datatype. The value of the read-only attribute lex
is the lexical form of the literal, e.g. "042"
for the RDF node "042"^^xsd:integer
.
3.1.4 The TermFactory
During the execution of JavaScript code, the SHACL engine MUST provide an Object accessible via the variable TermFactory
that can be used to create JavaScript Objects for RDF terms. The TermFactory
provides the following three functions:
namedNode(uri)
returns a NamedNode with theIRI provided as a string viauri
.blankNode(id)
returns a BlankNode with an optional identifier provided as a string viaid
. If theid
is omitted then the system generates a unique identifier.literal(lex, languageOrDatatype)
returns a Literal with the lexical form provided as a string vialex
. The second argumentlanguageOrDatatype
must be either a non-empty string, in which case the literal will have that value as its language tag, or a JavaScript NamedNode Object representing a datatype other thanrdf:langString
.
3.2 Triples
An RDF triple is represented by a JavaScript Triple
Object with three read-only attributes subject
, predicate
and object
, each of which has exactly one RDF term as its value. Furthermore, triples must provide an equals
function that takes an Object other
as its only parameter and returns a boolean.equals
returns true
exactly if other
has values for its attributes subject
, predicate
and object
that return true
when compared using equals()
against the corresponding attribute values of the first triple, and false
otherwise.
3.3 Graphs
An RDF graph is represented by a JavaScript Graph
Object that has a function find
which takes three parameters of type Object, all of which are optional. The result of the find
function is an Iterator object with two functions:
next()
either returns aTriple
ornull
if the iteration has been exhausted.close()
terminates the Iterator and releases any resources allocated by it. Onceclose()
has been called, further calls tonext()
cause an exception. Theclose()
function MUST always be called unless the iterator has already been walked to completion.
The following JavaScript snippet assumes that the current data graph is represented by the variable $data
and gets the first label of a given resource where the label is an english literal.
function getEnglishLabel(resource) { var labelProperty = TermFactory.namedNode("http://www.w3.org/2000/01/rdf-schema#label"); var labels = $data.find(resource, labelProperty, null); for(;;) { var labelTriple = labels.next(); if(!labelTriple) { return null; } var label = labelTriple.object; if(label.isLiteral() && label.language.startsWith("en")) { labels.close(); return label.value; } } }
3.3.1 Accessing the Data Graph via $data
During a validation process, the variable $data
points at the JavaScript Graph Object representing the SHACL data graph.
3.3.2 Accessing the Shapes Graph via $shapes
During a validation process, the variable $shapes
points at the JavaScript Graph Object representing the SHACL shapes graph. This may be identical to the data graph.
3.3.3 Synchronous versus Asynchronous Queries
This section is non-normative.
The iterators produced by the find
function described in this section are expected to be operating synchronously, i.e. the triples are available immediately to the caller. Since many of the constraints that users want to express in SHACL can be quite complex, a synchronous API contract typically leads to more maintainable code than an asynchronous one (with callbacks or promises). If data needs to be loaded on demand from a remote server, then solutions such as pre-caching or the await
keyword may be used as a work-around. More sophisticated handling of asynchronous query scenarios may be defined by future versions of SHACL-JS.
3.4 Validating Nodes via JavaScript
SHACL-JS processors must provide a JavaScript function with the following signature:
SHACL.nodeConformsToShape(node, shape)
node
: The RDF term Object of the node to validateshape
: The RDF term Object of the shape to validate the node against
The result of this function is true
if and only if node
conforms to the shape
, and false
otherwise.
This function is needed because the implementation of some of the constraint components such as sh:NotConstraintComponent
requires the ability to spawn off a new SHACL validation process. It may also be used as entry point into the validation engine by custom code.
4. Representing JavaScript in RDF
This section defines some general RDF terms used by SHACL-JS to represent JavaScript code and libraries as part of a declarative shapes graph.
The SHACL-JS vocabulary includes the class sh:JSExecutable
. SHACL instances of this class are called JavaScript executables and may have values for the properties sh:jsFunctionName
and sh:jsLibrary
.
4.1 sh:jsFunctionName
Every JavaScript executable must have exactly one value for the property sh:jsFunctionName
. The values of sh:jsFunctionName
are literals with datatype xsd:string
.
The semantics of how arguments are passed into the provided function depend on the specific type of executable, as described in later sections.
4.2 sh:jsLibrary
Every JavaScript executable must have at least one value for the property sh:jsLibrary
. The values of the property sh:jsLibrary
are IRIs or blank nodes. The values of the property sh:jsLibrary
are well-formed SHACL instances of the class sh:JSLibrary
.
4.3 sh:JSLibrary
The class sh:JSLibrary
can be used to declare JavaScript libraries. A library can be understood as a pointer to zero or more JavaScript files that need to be executed before a JavaScript executable can be evaluated. Libraries may depend on each other by declaring further sh:jsLibrary
triples.
The values of the property sh:jsLibraryURL
are literals with datatype xsd:anyURI
.
5. Executing JavaScript
This section defines general rules for the execution of JavaScript declared in RDF, by a SHACL engine.
Let args
be a mapping of variable names to RDF nodes. The result of the execution of a JavaScript function using args
is the result of the invocation of the JavaScript function, matching each variable name in args
to parameter values in the function's signature. A JavaScript parameter matches a variable name if its name is equal to the concatenation of "$"
and the variable name.
For the above definition, consider an example function myFunction($arg1, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mi>r</mi><mi>g</mi><mn>2</mn><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">arg2, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8389em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord">2</span><span class="mpunct">,</span></span></span></span>arg3) { ... }
and a variable mapping { "arg1" : ex:Instance1, "arg2" : 42 }
. The JavaScript function would be called with the JavaScript NamedNode object representing ex:Instance1
as value for $arg1
, the JavaScript Literal object representing 42
as value for $arg2
, and undefined
as value for $arg3
.
The execution of a JavaScript executable consists of executing any JavaScript libraries that are values of sh:jsLibrary
(including the libraries referenced by those libraries), followed by the execution of the JavaScript function that has the same name as thevalue of sh:jsFunctionName
. The result of the latter is the result of executing the executable.
Within the same JavaScript engine, the same JavaScript library MUST NOT be executed more than once. When a JavaScript library is executed, all its values for sh:jsLibraryURL
must be resolved into JavaScript code. By default this resolution mechanism MUST be performing an HTTP GET request against the given script URL. A failure MUST be reported if the SHACL processor encounters a cyclic dependency between libraries.
In practice, SHACL implementations may redirect the resolution of URLs to local files or cached copies.
6. JavaScript-based Constraints
SHACL-JS supports constraints that can be used to express restrictions based on JavaScript. In a nutshell, whenever a SHACL validation engine encounters a shape with a sh:js
constraint, it will execute the provided JavaScript function and use the returned result to create validation results.
Constraint Component IRI: sh:JSConstraintComponent
Parameters:
Property | Summary |
---|---|
sh:js | A JavaScript-based constraint declaring the JavaScript function to evaluate. |
The values of sh:js
at a shape are called JavaScript-based constraints. Each JavaScript-based constraint is also a JavaScript executable. The syntax rules and validation process for JavaScript-based constraints are defined in the rest of this section.
6.1 An Example JavaScript-based Constraint
This section is non-normative.
The following example illustrates the syntax of a JavaScript-based constraint.
ex:ValidCountry a ex:Country ; ex:germanLabel "Spanien"@de .
ex:InvalidCountry a ex:Country ; ex:germanLabel "Spain"@en .
function validateGermanLabel($this) { var results = []; var p = TermFactory.namedNode("http://example.org/ns#germanLabel"); var s = data.find(data.find(data.find(this, p, null); for(var t = s.next(); t; t = s.next()) { var object = t.object; if(!object.isLiteral() || !object.language.startsWith("de")) { results.push({ value : object }); } } return results; }
ex:LanguageExampleShape a sh:NodeShape ; sh:targetClass ex:Country ; sh:js [ # _:b1 a sh:JSConstraint ; # This triple is optional sh:message "Values are literals with German language tag." ; sh:jsLibrary [ sh:jsLibraryURL "http://example.org/js/germanLabel.js" ] ; sh:jsFunctionName "validateGermanLabel" ; ] .
The target of the shape above includes all SHACL instances of ex:Country
. For those nodes (represented by the variable $this
), the JavaScript code walks through the values of the property ex:germanLabel
at $this
and verifies that they are literals with a German language tag. The validation report for the aforementioned data graph is shown below:
[ a sh:ValidationReport ; sh:conforms false ; sh:result [ a sh:ValidationResult ; sh:resultSeverity sh:Violation ; sh:focusNode ex:InvalidCountry ; sh:resultMessage "Values are literals with German language tag." ; sh:resultPath ex:germanLabel ; sh:value "Spain"@en ; sh:sourceConstraint _:b1 ; sh:sourceConstraintComponent sh:JSConstraintComponent ; sh:sourceShape ex:LanguageExampleShape ; ] ] .
6.2 Validation with JavaScript-based Constraints
This section defines the validator of sh:JSConstraintComponent
.
There are no validation results if the JavaScript-based constraint has true
as a value for the property sh:deactivated
. Otherwise, for each focus node F
and each value node V
for F
,execute the constraint's JavaScript function using the argument mapping { "this" : F, "value" : V }
.Construct validation results for each result returned by these function calls. Report a failure if the execution of the JavaScript function results in an exception.
6.3 Mapping of JavaScript Results to Result Properties
The following rules define how to construct validation results from a given JavaScript function result R
in the context of a given constraint C
in a shape S
, a focus node F
and a value node V
.
- If
R
is a JavaScriptString
:Create a validation result?r
. Add a triple?r sh:resultMessage ?s
where?s
is anxsd:string
literal with the JavaScriptString
as its lexical form. Add a triple?r sh:value ?v
where?v
is the current value nodeV
. - If
R
is a JavaScript Array: For each member of the ArrayR
apply the rule for JavaScript Objects. - If
R
is a JavaScriptObject
(not aString
):Create a validation result?r
. IfR.value
is an RDF term object?v
, add a triple?r sh:value ?v
. IfR.message
is a JavaScriptString
, add a triple?r sh:resultMessage ?s
where?s
is anxsd:string
literal with the givenString
as its lexical form. Otherwise, add triples?r sh:resultMessage ?m
from the shapeS
following the rules defined by [shacl]. If the shapeS
is anode shape
andR.path
is an RDFNamedNode object?path
, add a triple?r sh:resultPath ?path
. - If
R
is the JavaScriptBoolean
false
:Create a validation result?r
. Add a triple?r sh:value ?v
where?v
is the current value nodeV
. Add triples?r sh:resultMessage ?m
from the shapeS
following the rules defined by [shacl].
To create a validation result ?r
, create a triple ?r rdf:type sh:ValidationResult
using the provided focus node F
as value for sh:focusNode
, deriving sh:resultSeverity
from the sh:severity
of the shape S
in theshapes graph (using sh:Violation
as default), and setting the sh:resultPath
, sh:sourceConstraintComponent
and sh:sourceShape
following the rules defined by [shacl]. If the result is produced by a JavaScript-based constraint, then set sh:sourceConstraint
to the value of sh:js
of the constraint C
in the shapes graph.
7. JavaScript-based Constraint Components
SHACL is based on constraint components, which can be used to express constraints in a declarative, high-level vocabulary. For example, the constraint component sh:MinCountConstraintComponent
defines a parameter sh:minCount
. When a shape uses one of these constraint parameters, a SHACL engine finds a suitable validator that can produce validation results. SHACL-SPARQL [shacl] defines how SPARQL queries can be used as validators. SHACL-JS defines a class sh:JSValidator
which can be used to declare validators using JavaScript.
7.1 An Example JavaScript-based Constraint Component
This section is non-normative.
The following example demonstrates how JavaScript can be used to specify new constraint components using SHACL-JS. The example implements sh:maxLength using a JavaScript-based validator to validate that the string representation of each value node has at most a given number of characters. Note that this is only an example implementation and should not be considered normative.
function hasMaxLength($value, $maxLength) { if($value.isLiteral()) { return value.lex.length<=value.lex.length <= value.lex.length<=maxLength.lex; } else if($value.isURI()) { return value.uri.length<=value.uri.length <= value.uri.length<=maxLength.lex; } else { // Blank node return false; } }
sh:MaxLengthConstraintComponent a sh:ConstraintComponent ; sh:parameter [ sh:path sh:maxLength ; sh:datatype xsd:integer ; ] ; sh:validator ex:hasMaxLength .
ex:hasMaxLength a sh:JSValidator ; sh:message "Value has more than {$maxLength} characters" ; rdfs:comment """ Note that valueandvalue and valueandmaxLength are RDF nodes expressed in JavaScript Objects. Their string value is accessed via the .lex and .uri attributes. The function returns true if no violation has been found. """ ; sh:jsLibrary [ sh:jsLibraryURL "http://example.org/ns/hasMaxLength.js"^^xsd:anyURI ] ; sh:jsFunctionName "hasMaxLength" .
7.2 Syntax of JavaScript-based Constraint Components
The declaration of JavaScript-based Constraint Components in a shapes graph is very similar to SPARQL-based Constraint Components. In particular, components declare their parameters using sh:parameter
. In fact, the same constraint component may serve as a declaration of both a SPARQL-based and a JavaScript-based constraint component, assuming that validators have been declared for both cases. Where SHACL-SPARQL uses the classes sh:SPARQLSelectValidator
and sh:SPARQLAskValidator
, SHACL-JS uses the class sh:JSValidator
, which is a subclass of sh:JSExecutable
. Each SHACL-JS validator is also a JavaScript executable and therefore has a value for sh:jsFunctionName
.
7.3 Validation of JavaScript-based Constraint Components
This section defines the validator of JavaScript-based constraint components.
Let ?E
be the JavaScript executable selected for the constraint component ?C
based on the rules outlined insection 6.2.3 of [shacl]. If the shape is a property shape and the shapes graph contains a triple ?C sh:propertyValidator ?E
then let path
be the value of sh:path
at the shape in the shapes graph, and execute ?E
for each focus node F
using a mapping { "this" : F, "path" : path }
. (The validator's JavaScript function can access the path
structure in the shapes graph $shapes
, assuming the function declares $path
as one of its parameters.) Otherwise, for each focus node F
and each value node V
,execute ?E
using a mapping { "this" : F, "value" : V }
.Construct validation results for each result returned by these function calls. Report a failure if the execution of the JavaScript function results in an exception.
8. JavaScript-based Functions
The SHACL Advanced Features includes a generic mechanism to declare new SHACL functions. In particular this is used to declare new SPARQL functions, using the class sh:SPARQLFunction
. SHACL-JS includes a very similar mechanism, allowing users to declare new functions in an RDF vocabulary so that certain engines can use them. Functions declared using the SHACL-JS vocabulary can, among others, be used by function calls in SPARQL FILTER or BIND clauses and in SHACL rules.
8.1 An Example JavaScript-based Function
This section is non-normative.
The following example demonstrates how JavaScript can be used to specify new SHACL function. The function can be used, for example in SPARQL using BIND (ex:square(4) AS ?s)
.
function square($number) { return number.lex∗number.lex * number.lex∗number.lex; }
ex:square a sh:JSFunction ; sh:parameter [ sh:path ex:number ; sh:datatype xsd:integer ; ] ; sh:returnType xsd:integer ; sh:jsLibrary [ sh:jsLibraryURL "http://example.org/js/square.js"^^xsd:anyURI ] ; sh:jsFunctionName "square" .
8.2 Syntax and Semantics of JavaScript-based Functions
The syntax of JavaScript-based functions is very similar to SPARQL-based functions. Each SHACL instance of sh:JSFunction
in a shapes graph, that is an IRI, declares one function. The IRI identifies the function, for example, in SPARQL queries. The function parameters are declared using sh:parameter
in the same way as the parameters of constraint components are declared. The optional property sh:returnType
can be used to specify the type of results produced by the function. Finally, sh:JSFunction
is a subclass of sh:JSExecutable
, and the syntax rules of JavaScript executables apply to functions, too. In particular, each JavaScript-based function has one value of sh:jsFunctionName
. This is the name of the JavaScript function that is executed whenever the (SHACL) function is called.
The JavaScript result R
of the execution of the function is turned into an RDF node using the following rules:
- If
R
is aString
: return anxsd:string
literal with the string as its lexical form - If
R
is anObject
representing an RDF node: returnR
- If
R
is aNumber
and the function declares ash:returnType
T
and the Number can be converted to a well-formed literal with datatypeT
: return a literal with datatypeT
and the given value as lexical form - If
R
is aNumber
that can be converted to a well-formed literal with datatypexsd:decimal
: return anxsd:decimal
literal with the given value as lexical form - If
R
is a Boolean: return anxsd:boolean
literal with the given value as lexical form - Otherwise: return no result
During the execution of a JavaScript function, the variable $data
can be used to access the current query graph, while the variable $shapes
is undefined.
9. JavaScript Rules
The SHACL Advanced Features document introduced the concept of SHACL-based rules which included an extension mechanism that can be used to define new rule types. This section defines a rule type called JavaScript rules.
Rule Type IRI | Key Property | Other Properties |
---|---|---|
sh:JSRule | sh:jsFunctionName | sh:jsLibrary |
9.1 An Example JavaScript Rule
This section is non-normative.
The following example illustrates the use of a JavaScript rule to compute the area of a rectangle, by multiplying width and height.
var NS = "http://datashapes.org/js/tests/rules/rectangle.test#";
function computeArea($this) { var width = getProperty($this, "width"); var height = getProperty($this, "height"); var area = TermFactory.literal(width.lex * height.lex, width.datatype); var areaProperty = TermFactory.namedNode(NS + "area"); return [ [$this, areaProperty, area] ]; }
function getProperty($this, name) { var it = data.find(data.find(data.find(this, TermFactory.namedNode(NS + name), null); var result = it.next().object; it.close(); return result; }
Note that this code is quite verbose because it uses only the very basic SHACL JavaScript API. In real-world examples, a higher level API with convenience methods is likely used.
ex:RectangleShape a sh:NodeShape ; sh:targetClass ex:Rectangle ; sh:rule [ a sh:JSRule ; # This triple is optional sh:jsFunctionName "computeArea" ; sh:jsLibrary [ sh:jsLibraryURL "http://example.org/js/rectangle.js"^^xsd:anyURI ] ; ] .
For the following data graph, the triples below would be produced.
ex:ExampleRectangle a ex:Rectangle ; ex:width 7 ; ex:height 8 .
Inferred triples:
ex:ExampleRectangle ex:area 56 .
9.2 Execution Instructions for JavaScript Rules
Prior to execution, ensure that all JavaScript libraries for the rule (specified via sh:jsLibrary
) have been executed. For each focus node, execute the JavaScript function specified as the value ofsh:jsFunctionName
at the rule in the shapes graph, using the focus node as the first (and only) argument into the function. If the result R
of the function call is an Array then for each member O
of this Array apply the instructions below.
- If
O
is an Array: Infer a new triple with subjectO[0]
,predicateO[1]
and objectO[2]
. - If
O
is anotherObject
: Infer a new triple with subjectO.subject
, predicateO.predicate
and objectO.object
.
In other words, each member of the Array returned by the JavaScript function must either be another Array with three members (for subject, predicate and object), of a JavaScript Object with three fields subject
, predicate
and object
.
10. JavaScript-based Custom Targets
As one of the SHACL Advanced Features, custom targets define a mechanism to compute target nodes by more flexible means than the built-in target types. Similar to SPARQL-based targets, this section introduces custom targets based on JavaScript.
10.1 JavaScript-based Targets (sh:JSTarget)
Custom targets that are SHACL instances of sh:JSTarget
are calledJavaScript-based targets.
JavaScript-based targets have the same syntax rules asJavaScript executables (e.g., requires a sh:jsFunctionName
). The function must return a JavaScript Array where each member is an RDF term Object.
Let T
be a JavaScript-based target. The target nodes of T
are the nodes in the Array returned by itsexecution against the data graph.
10.2 JavaScript-based Target Types (sh:JSTargetType)
Very similar to SPARQL-based target types, there is a class sh:JSTargetType
declared as rdfs:subClassOf sh:TargetType
for JavaScript-based target types.
JavaScript-based target types have the same syntax rules asJavaScript executables (e.g., requires a sh:jsFunctionName
). The function must return a JavaScript Array where each member is an RDF term Object.
Let T
be a JavaScript-based target of target type Y
. The target nodes of T
are the nodes in the Array returned by theexecution of Y
against the data graph. Similar to JavaScript-based constraint components, for the execution of the JavaScript function, all parameter values of T
are mapped to the JavaScript arguments by the local name of the parameter property (for example, ex:country
is passed into the function as values of $country
).
Appendix
A. Summary of SHACL-JS Syntax Rules
This section enumerates all normative syntax rules of SHACL-JS. This section is automatically generated from other parts of this spec and hyperlinks are provided back into the prose if the context of the rule in unclear. Nodes that violate these rules in a shapes graph are ill-formed.
Syntax Rule Id | Syntax Rule Text |
---|---|
jsFunctionName-count | Every JavaScript executable must have exactly one value for the property sh:jsFunctionName. |
jsFunctionName-datatype | The values of sh:jsFunctionName are literals with datatype xsd:string. |
jsLibrary-minCount | Every JavaScript executable must have at least one value for the property sh:jsLibrary. |
jsLibrary-nodeKind | The values of the property sh:jsLibrary are IRIs or blank nodes. |
jsLibrary-class | The values of the property sh:jsLibrary are well-formed SHACL instances of the class sh:JSLibrary. |
jsLibraryURL-datatype | The values of the property sh:jsLibraryURL are literals with datatype xsd:anyURI. |
JSTarget | JavaScript-based targets have the same syntax rules asJavaScript executables (e.g., requires a sh:jsFunctionName). The function must return a JavaScript Array where each member is an RDF term Object. |
JSTargetType | JavaScript-based target types have the same syntax rules asJavaScript executables (e.g., requires a sh:jsFunctionName). The function must return a JavaScript Array where each member is an RDF term Object. |
B. Security and Privacy Considerations
This section is non-normative.
SHACL-JS shares certain security and privacy considerations with those mentioned in [shacl]. In addition, JavaScript opens a whole new range of topics that are outside of the scope of this document. The general advice is for users to only use trusted and controlled shape graphs.
C. References
C.1 Normative references
[BCP47]
Tags for Identifying Languages. A. Phillips; M. Davis. IETF. September 2009. IETF Best Current Practice. URL: https://tools.ietf.org/html/bcp47
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[rdf11-concepts]
RDF 1.1 Concepts and Abstract Syntax. Richard Cyganiak; David Wood; Markus Lanthaler. W3C. 25 February 2014. W3C Recommendation. URL: https://www.w3.org/TR/rdf11-concepts/
[shacl]
Shapes Constraint Language (SHACL). Holger Knublauch; Dimitris Kontokostas. W3C. 11 April 2017. W3C Candidate Recommendation. URL: https://www.w3.org/TR/shacl/
[shacl-af]
SHACL Advanced Features. Holger Knublauch; Dean Allemang; Simon Steyskal. W3C. W3C Working Group Note. URL: https://www.w3.org/TR/shacl-af/
[turtle]
RDF 1.1 Turtle. Eric Prud'hommeaux; Gavin Carothers. W3C. 25 February 2014. W3C Recommendation. URL: https://www.w3.org/TR/turtle/
C.2 Informative references
[sparql11-query]
SPARQL 1.1 Query Language. Steven Harris; Andy Seaborne. W3C. 21 March 2013. W3C Recommendation. URL: https://www.w3.org/TR/sparql11-query/