This document defines SHACL Rules.

SHACL, the Shapes Constraint Language, is a language for describing the structure of RDF graphs. SHACL may be used for a variety of purposes such as validating, inferencing, modeling domains, generating ontologies to inform other agents, building user interfaces, generating code, and integrating data.

SHACL Rules provides inferencing with the generation of new RDF data from a combination of a set of rules and a base data graph. Rules can be expressed as RDF or in the SHACL Rules Language (SRL).

This specification is published by the Data Shapes Working Group.

Introduction

This document introduces the concept of inference rules for SHACL 1.2, a mechanism for deriving new RDF triples from existing data using declarative rules defined in shapes graphs. This extends SHACL’s capabilities beyond validation, enabling reasoning and data enrichment.

This document complements other SHACL 1.2 specifications, such as SHACL Core, by defining the syntax and semantics of rule-based inference. While SHACL Core focuses on constraint validation, the SHACL Rules specification provides a standardized way to express and evaluate rules that generate new data.

Terminology

Connect to definitions in RDF 1.2 Concepts.

The following definitions from other specifications are used in this document: @@

Document Conventions

Some examples in this document use Turtle [[turtle]]. The reader is expected to be familiar with SHACL [[shacl]] and SPARQL [[sparql-query]].

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#
shrl: http://www.w3.org/ns/shacl-rules#
shnex: http://www.w3.org/ns/shacl-node-expr#
xsd: http://www.w3.org/2001/XMLSchema#
ex: http://example.com/

Throughout the document, color-coded boxes containing RDF graphs in Turtle will appear. These fragments of Turtle documents use the prefix bindings given above.

TODO

RFC 2119 language should be automatically inserted here.

SHACL Rules

SHACL rules infer new triples. The input is a data graph and a set of rules. The output is a graph of inferred triples that do not occur in the data graph.

Basic Usage

   :A :fatherOf :X .
   :B :motherOf :X .
   :C :motherOf :A .
RULE { ?x :childOf ?y } WHERE { ?y :fatherOf ?x }
RULE { ?x :childOf ?y } WHERE { ?y :motherOf ?x }

RULE { ?x :descendedFrom ?y } WHERE { ?x :childOf ?y }
RULE { ?x :descendedFrom ?y } WHERE { ?x :childOf ?z . ?z :childOf ?y }

The above rules, applied to the data, will conclude that: `:X` is the `:childOf` `:A` and `:B`, and that `:X` is `:descendedFrom` `:C`.

Recursion

RULE { ?x :ancestorOf ?y } WHERE { ?y :descendedFrom ?x }
RULE { ?a :ancestorOf ?b } WHERE { ?a :ancestorOf ?c . ?c :ancestorOf ?b }

Negation

# Default value - calculate a name
RULE { ?x :name ?FN } WHERE { 
    ?x rdf:type :Person 
    NOT { ?x :name ?someName }
    ?x :givenName ?name1 ;
       :familyName ?name2 .
    BIND(concat(?name1, " ", ?name2) AS ?FN)
}

Importing rules

`IMPORTS`

Gives some modularity/sharing of rules.

"IMPORTS" vs "IMPORT" (c.f. `owl:imports`)

Assignment and Creating RDF Terms

Generating new terms without restriction can lead to unbounded inferred triples. There are function-like forms that do not have repeatable results: `BNODE`, `UUID`. Blank nodes in the rule head behave like SPARQL `CONSTRUCT`. Assignment can be used to have an incrementing counter.

Rule Tuples

At risk:

Rule tuples are workspace elements and are disjoint from triples. They are tuples of RDF terms (no variables).

Syntax of tuple patterns, templates and tuples:

  • `TUPLE(termOrVar , ...)`
  • Shorthand: `$(termOrVar , ...)`

Often, the first argument will be a fixed name.

There is a tuple store which holds tuples for the lifetime of the evaluation. The tuple store holds duplicate data tuples (unlike an RDF graph which is a set).

Attaching Rules To Shapes

Should we include attaching SHACL (1.2) Rules to shapes? If so, what does it mean given the difference in execution semantics?

In practice, how often are constriants and AF-rules written on the same shape? If they are, how are the rules being used, in practice, to influence the validation?

Sketch:

[] rdf:type sh:NodeShape ;
    sh:rule                   ## Different property?
      [ a srl:SHACLRule ;
        srl:ruleSet "...";    ## SRL syntax
        sh:prefixes ... ;
      ];
[] rdf:type sh:NodeShape ;
    sh:rule
      [ a srl:SHACLRule ;
        srl:ruleSet [ ... RDF syntax ... ] ;
      ];

Relationship between `RULE` and SPARQL `CONSTRUCT`

Shape Rules Abstract Syntax

The Shape Rules Abstract Syntax

Elements of the Abstract Syntax

Variable
A [=variable=] represents a possible [=RDF term=] in a triple pattern. Variables are also used in expressions.
Expression

An [=expression=] is a function, or functional form. It's arguments are [=RDF terms=]. An expression is evaluated with respect to a [=solution mapping=] to give an [=RDF term=] as the result. Expressions are compatible with SHACL list parameter functions and with SPARQL expressions.

Data block
A [=data block=] is a set of triples. These form extra facts that are included in the inference process.
Triple template
A [=triple template=] is 3-tuple where each element is either a [=variable=] or an [=RDF term=] (which might be a [=triple term=]). The second element of the tuple must be an [=IRI=] or a [=variable=]. [=Triple templates=] appear in the [=head=] of a [=rule=].
Triple pattern
A [=triple pattern=] is 3-tuple where each element is either a [=variable=] or an [=RDF term=] (which might be a triple term). The second element of the tuple must be an [=IRI=] or a [=variable=]. [=Triple patterns=] can appear as [=triple pattern elements=] as well as inside [=negation elements=].
Condition expression
A [=condition expression=] is a function, or functional form, that evaluates to true or false. [=Condition expressions=] appear in the [=body=] of a [=rule=].
Triple pattern element
A [=triple pattern element=] is a [=triple pattern=] used as a [=rule body element=].
Negation element
A [=negation element=] is a [=rule body element=]. It takes a sequence of [=triple patterns=] and [=condition expressions=].
Assignment
An [=assignment=] is a pair of a variable, called the assignment variable, and an expression, called the assignment expression. [=Assignments=] appear in the [=body=] of a [=rule=].
Rule body element
A [=rule body element=] (often just "rule element") is any element that can appear in a [=rule body=], a [=triple pattern=], a [=condition expression=], a [=negation element=], or an [=assignment=].
Rule head
A [=rule head=] is a sequence of [=triple templates=].
Rule body
A [=rule body=] is a sequence of [=rule body elements=].
Rule
A [=rule=] is a pair of a [=rule head=] (often just "head") and a [=rule body=] (often just "body").
Rule set
A [=rule set=] is a collection of zero or more [=rules=] and a collection of zero or more [=data blocks=].
Base graph
The [=base graph=] is the [=RDF Graph=] given as input to the evaluation process.
Inference graph
The [=inference graph=] is an [=RDF Graph=] that is the outcome of rule set evaluation. It contains all triples not found in the [=base graph=] that are inferred from evaluation of the [=rule set=] on the [=base graph=].

In a [=triple pattern=] or a [=triple template=], position 1 of the tuple is informally called the subject, position 2 is informally called the predicate, and position 3 is informally called the object.

Well-formedness Conditions

Well-formedness is a set of conditions on the abstract syntax of SHACL rules. Together, these conditions ensure that a [=variable=] in the [=head=] of a rule has a value defined in the [=body=] of the rule; that each variable in an [=condition expression=] or [=assignment expression=] has a value at the point of evaluation; and that each assignment in a rule introduces a new variable, one that has not been used earlier in the rule body.

A [=rule=] is a well-formed rule if all of the following conditions are met:

A [=rule set=] is "well-formed" if and only if all of the [=rules=] of the rule set are "well-formed".

Rule Dependency

Triple pattern dependency
A [=triple pattern=] in the rule body of rule `R1` depends on a rule `R2` if the head of `R2` can possibly generate triples that match the [=triple pattern=] in `R1`. The dependency is positive if the [=triple pattern=] is a [=rule body element=] and the dependency is negative if the [=triple pattern=] appears in a [=negation element=].
Rule dependency
A rule `R1` depends on rule `R2` if any rule element of `R1` depends on `R2`. The dependency is negative if any of the rule elements have a negative dependency on `R2`; otherwise the dependency is positive.
Dependency graph
A [=dependency graph=] of a [=rule set=] is a graph where the vertices are rules and an edge exists where one rule R1 depends on rule R2. An edge is labeled either positive or negative according to the [=rule dependency=].
Transitive rule dependency
A rule `R1` has a [=transitive dependency=] on rule `R2` if there is a path in the [=dependency graph=] from `R1` to `R2`.
Recursive rule dependency
A rule `R` has a [=recursive dependency=] if there is a cyclic path in the [=dependency graph=] involving `R`.

Notes:

Examples:

            @@ Examples of triple patttern dependencies.
          
            @@ Examples of rule dependencies.
          

Stratification

[=Stratification=] is the process of partitioning a [=rule set=] into an ordered sequence of [=stratification layers=] (also known as "strata", singular "stratum="), forming a [=stratification=]. Rules in lower [=strata=] are evaluated before rules in higher [=strata=].

[=Stratification=] imposes constraints on dependencies between [=rules=] to ensure that [=negation elements=] depend only on results computed in earlier [=strata=], guaranteeing a single, well-defined outcome from the evaluation of a [=rule set=] over a given [=base graph=].

A stratification process may also be used to make other evaluation decisions. This document describes the necessary conditions for consistent evaluation and gives one possible way to form a stratification. Implementations need to meet the conditions described here in order to get compatible behavior but are not required to implement the algorithm as presented.

Stratification
A [=stratification=] of a [=rule set=] is a sequence of sets of rules. Each rule in a [=rule set=] appears in exactly one [=stratification layer=].
Stratification layer
Each set of rules in a [=stratification=] is called a [=stratification layer=], also called a "stratum".

Stratification Condition

[=Stratification=] is only defined when the following condition is satisfied. If a [=rule set=] does not meet this condition, then this specification does not define the outcome of [=rule set=] evaluation.

Stratification Condition
The [=stratification Condition=] requires that there is no [=recursive dependency=] involving a negative dependency in the [=dependency graph=] for a [=rule set=].

In other words, there is no `NOT` used in any rule that transitively depends on itself.

Stratification Algorithm

The following algorithm gives one possible stratification based solely on the rule set.

              @@ one possible stratification algorithm
            

A consequence of the [=stratification condition=] is that when a rule containing a [=negation element=] is evaluated, the data used to determine the outcome of that [=negation element=], whether in the [=base graph=] or the [=inference graph=], is fixed and will not change during evaluation.

Concrete Syntax forms for Shapes Rules

There are two concrete syntaxes.

Shape Rules Language:

PREFIX : <http://example/>

DATA { :x :p 1 ; :q 2 . }

RULE { ?x :bothPositive true . }
WHERE { ?x :p ?v1  FILTER ( ?v1 > 0 )  ?x :q ?v2  FILTER ( ?v2 > 0 )  }

RULE { ?x :oneIsZero true . }
WHERE { ?x :p ?v1 ;  :q ?v2  FILTER ( ( ?v1 = 0 ) || ( ?v2 = 0 ) )  }

RDF Rules syntax:

PREFIX :       <http://example/>
PREFIX rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX sh:     <http://www.w3.org/ns/shacl#>
PREFIX shrl:   <http://www.w3.org/ns/shacl-rules#>
PREFIX sparql: <http://www.w3.org/ns/sparql#>

:ruleSet-1
  rdf:type shrl:RuleSet;
  shrl:data (
    <<( :x :p 1 )>>
    <<( :x :q 2 )>>
  );
  shrl:ruleSet (
    [
      rdf:type shrl:Rule;
      shrl:head (
        [ shrl:subject [ shrl:var "x" ] ; shrl:predicate :bothPositive; shrl:object true ]
      ) ;
      shrl:body (
        [ shrl:subject [ shrl:var "x" ]; shrl:predicate :p; shrl:object [ shrl:var "v1" ] ]
        [ shrl:expr [ sparql:greaterThan ( [ shrl:var "v1" ] 0 ) ] ]
        [ shrl:subject [ shrl:var "x" ] ; shrl:predicate :q; shrl:object [ shrl:var "v2" ] ]
        [ shrl:expr [ sparql:greaterThan ( [ shrl:var "v2" ] 0 ) ] ]
      );
    ]
    [
      rdf:type shrl:Rule;
      shrl:head (
        [ shrl:subject [ shrl:var "x" ] ; shrl:predicate :oneIsZero ; shrl:object true ]
      ) ;
      shrl:body (
        [ shrl:subject [ shrl:var "x" ] ; shrl:predicate :p ; shrl:object [ shrl:var "v1" ] ]
        [ shrl:subject [ shrl:var "x" ] ; shrl:predicate :q ; shrl:object [ shrl:var "v2" ] ]
        [ shrl:expr [ sparql:function-or (
              [ sparql:equals ( [ shrl:var "v1" ] 0 ) ]
              [ sparql:equals ( [ shrl:var "v2" ] 0 ) ]
            ) ]
        ]
      );
    ]
  ) .

Shape Rules Language syntax

The grammar is given below.

Mapping the AST to the abstract syntax.

Shape Rules Language Abbreviations

Additional helpers (short-hand abbreviations):

These allow for well-known rule patterns and also specialised implementations in basic engines.

  • TRANSITIVE(uri)
  • SYMMETRIC(uri)
  • INVERSE(uri)

At risk:

`TRANSITIVE` has both implementation and concise expression advantages. Implementation advantages for `SYMMETRIC` and `INVERSE` are not clear.

RDF Rules Syntax

Vocabulary: shacl-rules.ttl.

Well-formedness:

  • All RDF lists are well-formed
  • exactly one of subject - predicate - object, per body of head element
  • Well-formed, single-valued,list-argument node expressions
  • well-formed abstract syntax

Describe how the abstract model maps to triples.

Process : accumulators, bottom up/ Walk the structure.

  • Collect data triples
  • Map expressions
  • Map triple-patterns
  • Map triple-templates
  • Map assignments
  • Map to rule
  • Rule set

All triples not in the syntax are ignored. No other "shrl:" predicates are allowed (??).

Rule Set Evaluation

This section defines the outcome of evaluating a rule set on given data. It does not prescribe the algorithm as the method of implementation. An implementation can use any algorithm that generates the same outcome.

Inputs: data graph G, called the base graph, and a rule set RS.
Output: an RDF graph GI of inferred triples

The inferred triples do not include triples present in the set of triples of the [=base graph=].

Evaluation Definitions

solution mapping
A solution mapping, μ, is a partial function μ : VT, where V is the set of all variables and T is the set of all [=RDF terms=]. The domain of μ is denoted by dom(μ), and it is the subset of V for which μ is defined. We use the term [=solution=] where it is clear that a [=solution mapping=] is meant. Write μ0 for the solution mapping such that dom(μ0) is the empty set.
substitution function
A substitution function, or just substitution, is a function subst(μ, [=triple pattern=]) that returns a [=triple pattern=] where each occurrence in the [=triple pattern=] of a variable that is in the dom(μ) is replaced by the [=RDF term=] given by the [=solution mapping=] for var. If the triple pattern result has no variables, then it is an [=RDF Triple=].
evaluation graph
A [=evaluation graph=] is an [=RDF Graph=] that combines the [=base graph=] and all triples produced during the evaluation of a rule set.
graph match
A [=graph match=] finds the ways to map a triple pattern onto triples in an [=RDF Graph=].

Let G be an [=RDF graph=] and TP be a triple pattern. The function `graphMatch(G, TP)` returns a set of all possible solutions that, when applied to the triple pattern, produce a triple that is in the [=evaluation graph=]

Let G be an [=RDF graph=] and TP be a triple pattern.

graphMatch(G, TP) = { μ | subst(μ, TP) is a triple in G }
solution compatible
Two solutions S1 and S2 are [=compatible=] if they agree on the variables in common.

Let S1 and S2 be solutions.

compatible(μ1, μ2) = true
                      if forall v in dom(μ1) intersection dom(μ2)
                          μ1(v) = μ2(v)
compatible(μ1, μ2) = false otherwise
              
solution sequence
A [=solution sequence=] is a multi-set of solutions. There is no defined order to the sequence. It is equivalent to an unordered list and it can contain duplicates.
solution merge
If two solutions are compatible, the merge of two solutions is the solution that maps variables of each solution to the [=RDF term=] from one or other of the solutions.
Let μ1, μ2 be solution mappings, and S1 and S2 be solution sequences.
merge(μ1, μ2) = { μ |
                    μ(v) = μ1(v) if v in dom(μ1)
                    μ(v) = μ2(v) otherwise }
merge(S1, S2) = { μ |
                    μ1 in S1, μ2 in S2
                    and compatible(μ1, μ2)
                    μ(v) = merge(μ1, μ2)

Say the domain is `dom(S1) ∪︀ dom(S2)`.

Say that two solutions that have no variables in common are compatible.

Evaluation of an Expression

Sketch

@@ Reference SPARQL expression evaluation Expression Evaluation
@@ Reference SPARQL EBV Effective Boolean Value (EBV)

define evalFunction(F, μ):
    Let [x/μ] be
        if x is an RDF term, then [x/row] is x
        if x is a variable, then [x/row] is μ(x)
        ## By well-formedness, it is an error if x is not in the row.
    eval(F(expr1, expr2 ...), row) = F(eval(expr1, row), eval(expr2, row), ...)
    eval(FF(expr1, expr2) , row) = ... things that are not functions like `IF`

Evaluation of a Rule

let R be a well-formed rule.

let rule R = (H, B) where
             H is the sequence of triple templates in the head
             B is the sequence of triple patterns,
                condition expressions, negation elements,
                and assignments in the body

# Solution sequence of one solution that does not map any variables.
let SEQ0: Solution sequence = { μ0 }

let G = evaluation graph

# Evaluate rule body
# This function returns a sequence of solutions
define evalRuleElements(B, SEQ, G):

    for each rule element rElt in B:

        if rElt is a triple pattern TP:
            X = graphMatch(G, TP)
            SEQ1 = {}
            for each μ1 in X:
                for each μ2 in SEQ:
                  if compatible(μ1, μ2)
                    μ3 = merge(μ1, μ2)
                    add μ3 to SEQ1
                endfor
            endif

        if rElt is a condition expression with expression F:
            SEQ1 = {}
            for each solution μ in SEQ:
                if evalFunction(F, μ) is true:
                    add μ to SEQ1
                    endif
                endfor
            endif

        if rElt is a negation expression with body elements N:
            SEQ1 = {}
            for each solution μ in SEQ:
                S = sequence{ μ }
                NEG = evalRuleElements(N, S, G)
                if NEG is empty
                    add μ to SEQ1
                    endif
                endfor
            endif

        if rElt is an assignment with variable V and expression expr
            SEQ1 = {}
            for each solution S in SEQ:
                let x = eval(expr, S)
                add(V, x) to S
                add S to SEQ1
                endfor
            endif

        if SEQ1 is empty
            SEQ = {}
            return SEQ
            endif

        SEQ = SEQ1
        endfor

     return SEQ
     enddefine

let SEQ = evalRuleElements(B, SEQ0, G)

# Evaluate rule head
let H = empty set
for each μ in SEQ:
    let S = {}
    for each triple template TT in head
        let triple = subst(μ, TT)
        Add triple to S
    H = H union S
    endfor

result eval(R, G) is H

Note that `H` may contain triples that are also in the data graph.

Evaluation of a Rule Set

Sketch

let G0 be the input base graph
let RS be the rule set
let D be the graph of all DATA triples in RS

Apply stratification to RS

let L be the sequence of layers after stratification

# Inference graph
let GI = { t ∈D  | t ∉ in G0 }

# Evaluation graph.
let GE = G0 ∪︀ D

for each layer in L:
    let finished = false
    while !finished:
        finished = true
        for each rule in layer:
            let X = eval(rule, GE)
            let Y = { t ∈ X | t ∉ in GE }
            if Y is not empty:
                finished = false
                GI = Y ∪︀ GI
                GE = Y ∪︀ GE
                endif
            endfor
        endwhile
    endfor
the result is GI

Shapes Rules Language Grammar

[1]   RuleSet   ::=   RuleOrDataBlock
[2]   RuleOrDataBlock   ::=   Prologue ( ( Rule | Data )+ ( Prologue1 ( Rule | Data )? )* )?
[3]   Prologue   ::=   Prologue1*
[4]   Prologue1   ::=   BaseDecl | PrefixDecl | VersionDecl | ImportsDecl
[5]   BaseDecl   ::=   'BASE' IRIREF
[6]   PrefixDecl   ::=   'PREFIX' PNAME_NS IRIREF
[7]   VersionDecl   ::=   'VERSION' VersionSpecifier
[8]   VersionSpecifier   ::=   STRING_LITERAL1 | STRING_LITERAL2
[9]   ImportsDecl   ::=   'IMPORTS' iri
[10]   Rule   ::=   Rule1 | Rule2 | Declaration
[11]   Rule1   ::=   'RULE' HeadTemplate 'WHERE' BodyPattern
[12]   Rule2   ::=   'IF' BodyPattern 'THEN' HeadTemplate
[13]   Declaration   ::=   ( 'TRANSITIVE' '(' iri ')' | 'SYMMETRIC' '(' iri ')' | 'INVERSE' '(' iri ',' iri ')' )
[14]   Data   ::=   'DATA' TriplesTemplateBlock
[15]   HeadTemplate   ::=   TriplesTemplateBlock
[16]   BodyPattern   ::=   '{' BodyPattern1 '}'
[17]   BodyPattern1   ::=   BodyTriplesBlock? ( BodyNotTriples BodyTriplesBlock? )*
[18]   BodyNotTriples   ::=   Filter | Negation | Assignment
[19]   BodyTriplesBlock   ::=   TriplesBlock
[20]   Negation   ::=   'NOT' '{' BodyBasic '}'
[21]   BodyBasic   ::=   BodyTriplesBlock? ( Filter BodyTriplesBlock? )*
[22]   TriplesTemplateBlock   ::=   '{' TriplesTemplate? '}'
[23]   TriplesTemplate   ::=   TriplesSameSubject ( '.' TriplesTemplate? )?
[24]   TriplesBlock   ::=   TriplesSameSubjectPath ( '.' TriplesBlock? )?
[25]   ReifiedTripleBlock   ::=   ReifiedTriple PropertyList
[26]   ReifiedTripleBlockPath   ::=   ReifiedTriple PropertyListPath
[27]   Assignment   ::=   'BIND' '(' Expression 'AS' Var ')'
[28]   Reifier   ::=   '~' VarOrReifierId?
[29]   VarOrReifierId   ::=   Var | iri | BlankNode
[30]   Filter   ::=   'FILTER' Constraint
[31]   Constraint   ::=   BrackettedExpression | BuiltInCall | FunctionCall
[32]   FunctionCall   ::=   iri ArgList
[33]   ArgList   ::=   NIL | '(' Expression ( ',' Expression )* ')'
[34]   ExpressionList   ::=   NIL | '(' Expression ( ',' Expression )* ')'
[35]   TriplesSameSubject   ::=   VarOrTerm PropertyListNotEmpty | TriplesNode PropertyList | ReifiedTripleBlock
[36]   PropertyList   ::=   PropertyListNotEmpty?
[37]   PropertyListNotEmpty   ::=   Verb ObjectList ( ';' ( Verb ObjectList )? )*
[38]   Verb   ::=   VarOrIri | 'a'
[39]   ObjectList   ::=   Object ( ',' Object )*
[40]   Object   ::=   GraphNode Annotation
[41]   TriplesSameSubjectPath   ::=   VarOrTerm PropertyListPathNotEmpty | TriplesNodePath PropertyListPath | ReifiedTripleBlockPath
[42]   PropertyListPath   ::=   PropertyListPathNotEmpty?
[43]   PropertyListPathNotEmpty   ::=   ( VerbPath | VerbSimple ) ObjectListPath ( ';' ( ( VerbPath | VerbSimple ) ObjectListPath )? )*
[44]   VerbPath   ::=   Path
[45]   VerbSimple   ::=   Var
[46]   ObjectListPath   ::=   ObjectPath ( ',' ObjectPath )*
[47]   ObjectPath   ::=   GraphNodePath AnnotationPath
[48]   Path   ::=   PathSequence
[49]   PathSequence   ::=   PathEltOrInverse ( '/' PathEltOrInverse )*
[50]   PathEltOrInverse   ::=   PathElt | '^' PathElt
[51]   PathElt   ::=   PathPrimary
[52]   PathPrimary   ::=   iri | 'a' | '(' Path ')'
[53]   TriplesNode   ::=   Collection | BlankNodePropertyList
[54]   BlankNodePropertyList   ::=   '[' PropertyListNotEmpty ']'
[55]   TriplesNodePath   ::=   CollectionPath | BlankNodePropertyListPath
[56]   BlankNodePropertyListPath   ::=   '[' PropertyListPathNotEmpty ']'
[57]   Collection   ::=   '(' GraphNode+ ')'
[58]   CollectionPath   ::=   '(' GraphNodePath+ ')'
[59]   AnnotationPath   ::=   ( Reifier | AnnotationBlockPath )*
[60]   AnnotationBlockPath   ::=   '{|' PropertyListPathNotEmpty '|}'
[61]   Annotation   ::=   ( Reifier | AnnotationBlock )*
[62]   AnnotationBlock   ::=   '{|' PropertyListNotEmpty '|}'
[63]   GraphNode   ::=   VarOrTerm | TriplesNode | ReifiedTriple
[64]   GraphNodePath   ::=   VarOrTerm | TriplesNodePath | ReifiedTriple
[65]   VarOrTerm   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL | TripleTerm
[66]   ReifiedTriple   ::=   '<<' ReifiedTripleSubject Verb ReifiedTripleObject Reifier? '>>'
[67]   ReifiedTripleSubject   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple
[68]   ReifiedTripleObject   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple | TripleTerm
[69]   TripleTerm   ::=   '<<(' TripleTermSubject Verb TripleTermObject ')>>'
[70]   TripleTermSubject   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode
[71]   TripleTermObject   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTerm
[72]   TripleTermData   ::=   '<<(' TripleTermDataSubject ( iri | 'a' ) TripleTermDataObject ')>>'
[73]   TripleTermDataSubject   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral
[74]   TripleTermDataObject   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral | TripleTermData
[75]   VarOrIri   ::=   Var | iri
[76]   Var   ::=   VAR1 | VAR2
[77]   Expression   ::=   ConditionalOrExpression
[78]   ConditionalOrExpression   ::=   ConditionalAndExpression ( '||' ConditionalAndExpression )*
[79]   ConditionalAndExpression   ::=   ValueLogical ( '&&' ValueLogical )*
[80]   ValueLogical   ::=   RelationalExpression
[81]   RelationalExpression   ::=   NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )?
[82]   NumericExpression   ::=   AdditiveExpression
[83]   AdditiveExpression   ::=   MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )*
[84]   MultiplicativeExpression   ::=   UnaryExpression ( '*' UnaryExpression | '/' UnaryExpression )*
[85]   UnaryExpression   ::=     '!' PrimaryExpression
| '+' PrimaryExpression
| '-' PrimaryExpression
| PrimaryExpression
[86]   PrimaryExpression   ::=   BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[87]   ExprTripleTerm   ::=   '<<(' ExprTripleTermSubject Verb ExprTripleTermObject ')>>'
[88]   ExprTripleTermSubject   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var
[89]   ExprTripleTermObject   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[90]   BrackettedExpression   ::=   '(' Expression ')'
[91]   BuiltInCall   ::=     'STR' '(' Expression ')'
| 'LANG' '(' Expression ')'
| 'LANGMATCHES' '(' Expression ',' Expression ')'
| 'LANGDIR' '(' Expression ')'
| 'DATATYPE' '(' Expression ')'
| 'IRI' '(' Expression ')'
| 'URI' '(' Expression ')'
| 'BNODE' ( '(' Expression ')' | NIL )
| 'ABS' '(' Expression ')'
| 'CEIL' '(' Expression ')'
| 'FLOOR' '(' Expression ')'
| 'ROUND' '(' Expression ')'
| 'CONCAT' ExpressionList
| 'SUBSTR' '(' Expression ',' Expression ( ',' Expression )? ')'
| 'STRLEN' '(' Expression ')'
| 'REPLACE' '(' Expression ',' Expression ',' Expression ( ',' Expression )? ')'
| 'UCASE' '(' Expression ')'
| 'LCASE' '(' Expression ')'
| 'ENCODE_FOR_URI' '(' Expression ')'
| 'CONTAINS' '(' Expression ',' Expression ')'
| 'STRSTARTS' '(' Expression ',' Expression ')'
| 'STRENDS' '(' Expression ',' Expression ')'
| 'STRBEFORE' '(' Expression ',' Expression ')'
| 'STRAFTER' '(' Expression ',' Expression ')'
| 'YEAR' '(' Expression ')'
| 'MONTH' '(' Expression ')'
| 'DAY' '(' Expression ')'
| 'HOURS' '(' Expression ')'
| 'MINUTES' '(' Expression ')'
| 'SECONDS' '(' Expression ')'
| 'TIMEZONE' '(' Expression ')'
| 'TZ' '(' Expression ')'
| 'NOW' NIL
| 'UUID' NIL
| 'STRUUID' NIL
| 'IF' '(' Expression ',' Expression ',' Expression ')'
| 'STRLANG' '(' Expression ',' Expression ')'
| 'STRLANGDIR' '(' Expression ',' Expression ',' Expression ')'
| 'STRDT' '(' Expression ',' Expression ')'
| 'sameTerm' '(' Expression ',' Expression ')'
| 'isIRI' '(' Expression ')'
| 'isURI' '(' Expression ')'
| 'isBLANK' '(' Expression ')'
| 'isLITERAL' '(' Expression ')'
| 'isNUMERIC' '(' Expression ')'
| 'hasLANG' '(' Expression ')'
| 'hasLANGDIR' '(' Expression ')'
| 'REGEX' '(' Expression ',' Expression ( ',' Expression )? ')'
| 'isTRIPLE' '(' Expression ')'
| 'TRIPLE' '(' Expression ',' Expression ',' Expression ')'
| 'SUBJECT' '(' Expression ')'
| 'PREDICATE' '(' Expression ')'
| 'OBJECT' '(' Expression ')'
[92]   iriOrFunction   ::=   iri ArgList?
[93]   RDFLiteral   ::=   String ( LANG_DIR | '^^' iri )?
[94]   NumericLiteral   ::=   NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative
[95]   NumericLiteralUnsigned   ::=   INTEGER | DECIMAL | DOUBLE
[96]   NumericLiteralPositive   ::=   INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE
[97]   NumericLiteralNegative   ::=   INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE
[98]   BooleanLiteral   ::=   'true' | 'false'
[99]   String   ::=   STRING_LITERAL1 | STRING_LITERAL2 | STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2
[100]   iri   ::=   IRIREF | PrefixedName
[101]   PrefixedName   ::=   PNAME_LN | PNAME_NS
[102]   BlankNode   ::=   BLANK_NODE_LABEL | ANON

Productions for terminals:

[103]   IRIREF   ::=   '<' ([^<>"{}|^`\]-[#x00-#x20])* '>'
[104]   PNAME_NS   ::=   PN_PREFIX? ':'
[105]   PNAME_LN   ::=   PNAME_NS PN_LOCAL
[106]   BLANK_NODE_LABEL   ::=   '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
[107]   VAR1   ::=   '?' VARNAME
[108]   VAR2   ::=   '$' VARNAME
[109]   LANG_DIR   ::=   '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)* ('--' [a-zA-Z]+)?
[110]   INTEGER   ::=   [0-9]+
[111]   DECIMAL   ::=   [0-9]* '.' [0-9]+
[112]   DOUBLE   ::=   ( ([0-9]+ ('.'[0-9]*)? ) | ( '.' ([0-9])+ ) ) [eE][+-]?[0-9]+
[113]   INTEGER_POSITIVE   ::=   '+' INTEGER
[114]   DECIMAL_POSITIVE   ::=   '+' DECIMAL
[115]   DOUBLE_POSITIVE   ::=   '+' DOUBLE
[116]   INTEGER_NEGATIVE   ::=   '-' INTEGER
[117]   DECIMAL_NEGATIVE   ::=   '-' DECIMAL
[118]   DOUBLE_NEGATIVE   ::=   '-' DOUBLE
[119]   STRING_LITERAL1   ::=   "'" ( ([^#x27#x5C#xA#xD]) | ECHAR )* "'"
[120]   STRING_LITERAL2   ::=   '"' ( ([^#x22#x5C#xA#xD]) | ECHAR )* '"'
[121]   STRING_LITERAL_LONG1   ::=   "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR ) )* "'''"
[122]   STRING_LITERAL_LONG2   ::=   '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR ) )* '"""'
[123]   ECHAR   ::=   '\' [tbnrf\"']
[124]   NIL   ::=   '(' WS* ')'
[125]   WS   ::=   #x20 | #x9 | #xD | #xA
[126]   ANON   ::=   '[' WS* ']'
[127]   PN_CHARS_BASE   ::=   [A-Z] | [a-z] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | [#x00F8-#x02FF] | [#x0370-#x037D] | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
[128]   PN_CHARS_U   ::=   PN_CHARS_BASE | '_'
[129]   VARNAME   ::=   ( PN_CHARS_U | [0-9] ) ( PN_CHARS_U | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] )*
[130]   PN_CHARS   ::=   PN_CHARS_U | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
[131]   PN_PREFIX   ::=   PN_CHARS_BASE ((PN_CHARS|'.')* PN_CHARS)?
[132]   PN_LOCAL   ::=   (PN_CHARS_U | ':' | [0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )?
[133]   PLX   ::=   PERCENT | PN_LOCAL_ESC
[134]   PERCENT   ::=   '%' HEX HEX
[135]   HEX   ::=   [0-9] | [A-F] | [a-f]
[136]   PN_LOCAL_ESC   ::=   '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?' | '#' | '@' | '%' )

Internet Media Type, File Extension and Macintosh File Type

@@see the Turtle registration for format

The Internet Media Type (formerly known as MIME Type) for @@ is "text/shape-rules".

The information that follows has been submitted to the Internet Engineering Steering Group (IESG) for review, approval, and registration with IANA.

Type name:
application
Subtype name:
shape-rules
Required parameters:
None
Optional parameters:
@@version, @@profile
Encoding considerations:
The syntax of the SHACL Rules Language is expressed over code points in Unicode [[UNICODE]]. The encoding is always UTF-8 [[RFC3629]].
Unicode code points may also be expressed using an \uXXXX (U+0 to U+FFFF) or \UXXXXXXXX syntax (for U+10000 onwards) where X is a hexadecimal digit [0-9A-F]
Security considerations:
See appendix C, Security Considerations as well as [[[RFC3629]]] [[RFC3629]] section 7, Security Considerations.
Interoperability considerations:
There are no known interoperability issues.
Published specification:
This specification.
Applications which use this media type:
@@
Additional information:
Magic number(s):
A SHACL rules file may have the string 'PREFIX' (case independent) near the beginning of the document.
File extension(s):
".srl"
Base URI:
The SHACL Rules 'BASE <IRIref>' term can change the current base URI for relative IRIrefs in the query language that are used sequentially later in the document.
Macintosh file type code(s):
"TEXT"
Person & email address to contact for further information:
Data Shapes Working Group <public-shacl@w3.org;
Intended usage:
COMMON
Restrictions on usage:
None
Author/Change controller:
The SHACL 1.2 Rules specification is a work product of the World Wide Web Consortium's Data Shapes Working Group. The W3C has change control over these specifications.

Security Considerations

TODO

Privacy Considerations

TODO

Internationalization Considerations

TODO

Acknowledgements

Many people contributed to this document, including members of the RDF Data Shapes Working Group.