The ShEx SHACL-SPARQL extension, http://shex.io/extensions/SHACL-SPARQL/, runs SHACL-SPARQL queries as semantic actions. A query means what it means in SHACL-SPARQL — a SELECT reports one violation per solution, an ASK passes when it answers true, and $this and $value are pre-bound — so a query written for a sh:SPARQLConstraint or a sh:SPARQLAskValidator can be used as it is. What surrounds it is ShEx: recursive shapes, CLOSED over triple expressions, and actions that take part in deciding which triple matches which constraint rather than being reported after the fact.

Example

Events and the parts they're made of must each end no earlier than they start:

PREFIX : <http://a.example/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX shacl-sparql: <http://shex.io/extensions/SHACL-SPARQL/>

:Event {
  :start xsd:date ;
  :end xsd:date ;
  :part @:Event *
} %shacl-sparql:{
  SELECT $this ?start ?end
         ("the event ends before it starts" AS ?message)
  WHERE { $this :start ?start ; :end ?end .
          FILTER (?end < ?start) }
%}
PREFIX : <http://a.example/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

:conf :start "2026-10-05"^^xsd:date ;
      :end   "2026-10-07"^^xsd:date ;
      :part  :keynote .
:keynote :start "2026-10-05"^^xsd:date ;
         :end   "2026-10-04"^^xsd:date .

:conf doesn't conform to :Event. Its own dates pass, but :keynote, reached through the recursive :part @:Event, fails the action with the message "the event ends before it starts", and so the :part triple has no constraint to satisfy.

Evaluation

ShEx leaves the evaluation of a semantic action to its extension and defines what a failure means (semActsSatisfied). For an action named http://shex.io/extensions/SHACL-SPARQL/, the evaluation is:

  1. Parse the action's code as a SPARQL query.
  2. Pre-bind $this and $value, according to where the action is.
  3. Evaluate the query over the data being validated.
  4. Judge the result: success, or failure with one error per violation.

Parsing the query

The code is parsed as a SPARQL 1.1 Query. The schema's PREFIX and BASE declarations are in scope, as if they were the query's prologue: a query needs no prefix declarations of its own, which is the job sh:prefixes does in SHACL. A declaration in the query's own prologue takes precedence.

The query has to be a SELECT or an ASK. A query that doesn't parse, a CONSTRUCT or a DESCRIBE, or an action with no code (and no code supplied from outside the schema) is an invocation error: the validation stops with an error rather than reporting a failure.

ShExC reserves % and \ in code blocks, so a query writes them \% and \\; the parser unescapes them before the extension sees the query.

Pre-binding $this and $value

Which variables are pre-bound depends on the schema element the action is attached to:

the action is on$this$value
a Shapethe focus node—
a NodeConstraintthe node being tested—
a TripleConstraintthe focus node: the matched triple's subject, or its object for an inverse (^) constraintthe other end of the matched triple
an EachOf or OneOfthe node every triple it matched shares—
the schema's start actions——

In ShExC an action written after a triple constraint's value expression belongs to the triple constraint (:v xsd:integer %shacl-sparql:{…%} binds $this to the subject and $value to the object). To put an action on the value's own node constraint, label it (:v @:Positive … :Positive xsd:integer %shacl-sparql:{…%}).

Pre-binding follows SHACL's definition: each occurrence of a pre-bound variable in the query stands for its term. In SPARQL $this and ?this are the same variable. A pre-bound variable in a SELECT's projection is still projected, with its pre-bound value.

What the query is evaluated over

The query is evaluated over the data the validation reads, not only the neighborhood of the node being validated. A query can look anywhere in that data: "no other book has this ISBN" is a question about the other books.

The answer depends only on the query, the pre-bound terms and the data, so an implementation may ask each distinct question once per validation.

The verdict

querysucceeds whenotherwiseas in SHACL
SELECT there are no solutions fails, with one error per solution sh:SPARQLConstraint
ASK it answers true fails, with one error sh:SPARQLAskValidator

A solution's ?message, where it binds one, is that error's message; otherwise the message names the extension and lists the solution's bindings. An implementation should report the solution's bindings with the error, as SHACL reports ?value and ?path in a validation result.

An expression error inside the query (comparing a date with an IRI, say) is SPARQL's business: a FILTER whose expression errs rejects the solution, as SPARQL defines it. It isn't an invocation error.

What a failure does

A failure is a semantic-action failure as ShEx defines one, and it means what that means where the action is:

Differences from SHACL-SPARQL

Implementations