SPIN JavaScript Functions (SPINx)

March 24, 2010

Holger Knublauch <holger@topquadrant.com>


This document describes the SPINx vocabulary, an extension of the SPIN framework that can be used to define new SPARQL functions based on JavaScript code. This makes it possible to extend SPARQL engines with new functions that execute JavaScript at run-time. The SPINx framework is very light-weight and is easy to implement and use.

Status of This Document


This document is an optional part of the SPARQL Inferencing Notation (SPIN) specification.

As of 2017, SPINx has further evolved into SHACL-JS, which provides very similar capabilities. SPINx should no longer be used and will be removed in a future TopBraid version.

Table of Contents


1 Introduction

While SPARQL is an immensely powerful language, many real-world use cases require extensions that are not covered by the official standards. Examples include complex string operations or mathematical computations. SPARQL provides a built-in extension point, allowing anyone to define custom functions, identified by a function URI. The SPIN framework makes it possible to define and share such functions in a machine-readable format, fully compliant with the Semantic Web stack. SPIN includes an RDF vocabulary for defining the arguments and return value types of a function, as well as other useful information such as comments. SPIN also has a built-in property (spin:body) to define how a SPARQL function is to be executed, based on another SPARQL query.

Those user-defined SPIN functions are a very powerful way of extending SPARQL, but they are still limited by whatever features are natively supported by the executing SPARQL engine. The SPINx framework described in this document makes it possible to define new SPARQL functions that are backed by JavaScript/ECMAScript code. Whenever such SPINx functions are invoked, a SPINx-aware SPARQL engine can look up the function's body and execute it using a JavaScript interpreter.

The following sections introduce the two properties of the SPINx vocabulary. You should already be familiar with user-defined SPIN functions.


2 spinx:javaScriptCode

The simplest way of defining a JavaScript-based SPIN function is by using the property spinx:javaScriptCode. This property can be used to link a SPIN function (subject) with a JavaScript snippet (string object). This is illustrated in the following example (in Turtle notation), which defines a new SPARQL function distance:squareInline that takes one argument (?arg1) and computes the square of this argument (?arg1 * ?arg1).

      a       spin:Function ;
      rdfs:label "square inline"^^xsd:string ;
      rdfs:subClassOf spin:Functions ;
              [ a       spl:Argument ;
                rdfs:comment "The value to compute the square of"^^xsd:string ;
                spl:predicate sp:arg1 ;
                spl:valueType xsd:float
              ] ;
      spin:returnType xsd:float ;
              "return arg1 * arg1;"^^xsd:string .

When executed, the function's JavaScript code snippet will be converted into a JavaScript function that has the snippet as its body.

The function's JavaScript code can access the arguments using the pre-defined variables arg1, arg2 etc. The values of those arguments depend on their type:

The return value of a SPINx function will be automatically converted to a RDF node using the following policy:


3 spinx:javaScriptFile

While spinx:javaScriptCode is suitable for small snippets of simple JavaScript code, the property spinx:javaScriptFile provides greater flexibility to link a SPIN function with larger bodies of JavaScript code. The subject of the spinx:javaScriptFile property is a SPIN function, and the object is the URL of a JavaScript file, encoded as a string.

The following example (in Turtle notation) declares a similar function as above, but with the JavaScript code stored in a file distance.js. Since this is a relative path name, the engine should look up this file in the same location as the SPIN file (i.e. the distance namespace). Alternatively, the file location can also be an absolute URL.

      a       spin:Function ;
      rdfs:comment "Computes the square of a numeric value, backed by a JavaScript implementation." ;
      rdfs:label "square"^^xsd:string ;
      rdfs:subClassOf spin:Functions ;
              [ a       spl:Argument ;
                rdfs:comment "The number to compute the square of."^^xsd:string ;
                spl:predicate sp:arg1 ;
                spl:valueType rdfs:Literal
              ] ;
      spin:returnType xsd:float ;
              "distance.js"^^xsd:string .

The contents of the file distance.js is shown below:

function square(x) { 
	return x * x; 

By default, the SPINx engine assumes that the JavaScript file contains a function with the same name as the local name of the SPIN function (here: distance:square is mapped to the JavaScript function square). Alternatively, a SPINx function can contain a value for spinx:javaScriptCode which is executed on top of the file, and may contain any other combination of function calls.


Appendix: Reference

The URL of the SPINx schema is http://spinrdf.org/spinx