This document describes Shapes Constraint Language (SHACL) Inference Rules.

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 Inference Rules specification provides a standardized way to express and evaluate rules that generate new data.

Terminology

Connect to definitions in RDF 1.2 Concepts.

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 Informal Name
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns# RDF
rdfs: http://www.w3.org/2000/01/rdf-schema# RDFS
srl: http://www.w3.org/ns/shacl-rules# SHACL Rules
shnex: http://www.w3.org/ns/shnex# SHACL Node Expressions
sh: http://www.w3.org/ns/shacl# SHACL
xsd: http://www.w3.org/2001/XMLSchema# XML Schema
ex: http://example.com/ns# Example

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 represents a data graph.
        # This box represents an output results graph

Formal definitions appear in blue boxes:

TEXTUAL DEFINITIONS
          # 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 .

TODO

RFC 2119 language should autmatically be inserted here.

Outline

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

Data:

   :A :fatherOf :X .
   :B :motherOf :X .
   :C :motherOf :A .

Rules:

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 }

will conclude that: `:X` is the `:childOf` `:A` and `:B`, and that `:X` is `:descendedFrom` `:C`

Shape Rules Abstract Syntax

The Shape Rules Abstract Syntax

?? Abstract Rules Syntax

variable
[ sh:var "name" ]
node expression
Link to shacl12-node-expr#? -- needs to be single value, list arguments. Often called an expression.
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). [=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). [=Triple patterns=] appear in the [=body=] of a [=rule=].
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=].
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
A rule is a pair of a [=rule head=] (often just "head") and a [=rule body=] (often just "body").
rule head
A rule head is a sequence where each element of the sequence is a [=triple template=].
rule body
A rule body is a sequence where each element of the sequence is a [=triple pattern=], a [=condition expression=], or an [=assignment=].
rule set
A rule set is a collection of zero or more [=rules=] and a collection of zero or more [=data blocks=].

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 shapes rules. Together, these rules 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, not 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".

Concrete Syntax forms for Shapes Rules

The compact syntax has an equivalent RDF syntax form. Well-formed RDF syntax can be translated to the compact syntax.

Change the name away from "compact" and leave that free for SHACL-C.

Compact:

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:

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

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

RDF Rules Syntax

Well-formed ness:

  • All RDF list 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

Alternative: 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 "sh:" predicates are allowed (??).

@@ link to SHACL constraints

Compact Rules Syntax

The grammar is given below.

Mapping the AST to the abstract syntax.

Compact Syntax Abbreviations

Additional helpers (short-hand abbreviations) @@which also allow specialised implementations for basic engines@@.

  • `TRANSITIVE`
  • `SYMMETRIC`
  • `INVERSE`

Shape Rules 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 and a rule set RS.
Output: an RDF graph GI of inferred triples

The inferred triples does not include any triple present in the set of triples of G.

Evaluation of an expression


Let F(arg1, arg2, ...) be an expression.
where arg1, arg2 are RDF terms.

Let [x/row] be
    if x is an RDF term, the [x/row] is x
    if x is a variable then [x/row] is the value of x in the row 
    ## 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 = (head, body) where
             H is the sequence of triple templates in the head
             B is the sequence of triple patterns, condition expressions,
                and assignments in the body

let R : map variable to RDF term as a set of pairs (variable, RDF term)

# "solution"
let T :list of B

Initial T = empty list

# Evaluate rule body
for each rule element rElt:
    if rElt is a triple pattern:
        T1 = empty list
    for each row in T:
      T1 = empty list
      for each matches m set of (var,term)
          row1 = row union (var, term)
          add row1 to T1
          endfor
    T = T1
    endif   

    if rElt is a condition expression F:
        T1 = empty list
        for each row in T:
            if ( eval(F,B) )
                add R to T1
                endif   
        endfor
    T = T1
    endif

    if rElt is an assignment(V, expr)
        T1 = empty list
        for each row in T:
            let x = eval(expr, row)
            let R1 = R union (V, x)
            add R1 to T1
            endfor
        T = T1
        endif
    endfor

# Evaluate rule head
let H = empty set
for each R in T:
    Let S = set of triples obtained by replacing variables 
            in the triple templates of the head with values from R
    define [head(R)/row]
    H = H union S
    endfor

result eval(R, G) is H

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

Evaluation of a Rule Set

Let G be the input RDF graph.
Let I be the set of triples generated by evaluation
Let RS be a rule set
Let finished = false

while !finished:
    finished = true
    foreach rule in RS
        let GI = G union I
        let X = eval(rule, GI)
        let Y = those triples in X that are not in GI
        if Y is not empty:
            finished = false
            endif
        let I = Y union I
        endfor
    endwhile

result is GI

Drafting Notes

Attaching Rules to Shapes

@@ Discussion

See SHACL AF `sh:rule`, which describes triple rules, with a special case of property value rules and SPARQL Rules (AKA "CONSTRUCT rules").

Core issue 517 : classification shapes

How much compatibility? At one level, nothing needs top done because they have separate evaluation and it is only a matter of whether an engine supports them or not. It might be helpful to say when they happen (before 1.2 Rules - seea also defaul values) and can infer if they generate infered triple.

Parameterization

@@ Discussion

Define a new rule that is another rule with some variables already set

  • Where do the setting come from?
  • Is is just one "row" or a data table?
  • Logically, some `BIND` steps at the start of the rule body

More on evaluation

@@ Discussion

The main evaluatiuon description creates all inferred triple using the datalog "naive" algorithm.

Do we need to talk about backward evaluation and stratification?

Negation as semi-positive datalog

@@ Discussion

Negation (e.g. via SPARQL `NOT EXISTS`/`EXISTS`) can allowed if the pattern is executed only one the base data graph, not including the inferred graph. i.e. inferred triples are not seen. Or stratification - not seeing inferred tripels from the current stratum.

Priority for this feature?

Assignment restrictions

@@ Discussion

Assignment takes the rule lanuage outside datalog. Can we define when it is "safe"? (e.g. triples involving the assignment are not mentioned in the body of any other rule).

Do we need "order" in the syntax?

Work space named tuples

@@ Discussion

Currently, SHACL Rules is, in datatlog-speak, only unnamed 3-tuples. To support "programming" in rules, should we allow transient (not part of the output, only during rulset evaluation) named n-tuples?
e.g. name(termOrVar, ...), possibly with a unique marker e.g. ` giving `name(termOrVar, ...).

Shapes Rules Language Grammar

[1]   RuleSet   ::=   ( Prologue ( Rule | Data ) )*
[2]   Rule   ::=   Rule1 | Rule2 | Rule3 | Declaration
[3]   Rule1   ::=   'RULE' HeadTemplate 'WHERE' BodyPattern
[4]   Rule2   ::=   'IF' BodyPattern 'THEN' HeadTemplate
[5]   Rule3   ::=   HeadTemplate ':-' BodyPattern
[6]   Declaration   ::=   ( 'TRANSITIVE' '(' iri ')' | 'SYMMETRIC' '(' iri ')' | 'INVERSE' '(' iri ',' iri ')' )
[7]   Data   ::=   'DATA' TriplesTemplateBlock
[8]   HeadTemplate   ::=   TriplesTemplateBlock
[9]   BodyPattern   ::=   '{' BodyPattern1? Assignment* '}'
[10]   BodyPattern1   ::=   ( Filter | BodyPatternSub ( Filter BodyPatternSub? )* )
[11]   BodyPatternSub   ::=   TriplesBlock
[12]   Prologue   ::=   ( BaseDecl | PrefixDecl | VersionDecl | ImportsDecl )*
[13]   BaseDecl   ::=   'BASE' IRIREF
[14]   PrefixDecl   ::=   'PREFIX' PNAME_NS IRIREF
[15]   VersionDecl   ::=   'VERSION' VersionSpecifier
[16]   VersionSpecifier   ::=   STRING_LITERAL1 | STRING_LITERAL2
[17]   ImportsDecl   ::=   'IMPORTS' iri
[18]   TriplesTemplateBlock   ::=   '{' TriplesTemplate? '}'
[19]   TriplesTemplate   ::=   TriplesSameSubject ( '.' TriplesTemplate? )?
[20]   TriplesBlock   ::=   TriplesSameSubjectPath ( '.' TriplesBlock? )?
[21]   ReifiedTripleBlock   ::=   ReifiedTriple PropertyList
[22]   ReifiedTripleBlockPath   ::=   ReifiedTriple PropertyListPath
[23]   Assignment   ::=   Bind
[24]   Bind   ::=   'BIND' '(' Expression 'AS' Var ')'
[25]   Let   ::=   'LET' '(' Var ':=' Expression ')'
[26]   Reifier   ::=   '~' VarOrReifierId?
[27]   VarOrReifierId   ::=   Var | iri | BlankNode
[28]   Filter   ::=   'FILTER' Constraint
[29]   Constraint   ::=   BrackettedExpression | BuiltInCall | FunctionCall
[30]   FunctionCall   ::=   iri ArgList
[31]   ArgList   ::=   NIL | '(' Expression ( ',' Expression )* ')'
[32]   ExpressionList   ::=   NIL | '(' Expression ( ',' Expression )* ')'
[33]   TriplesSameSubject   ::=   VarOrTerm PropertyListNotEmpty | TriplesNode PropertyList | ReifiedTripleBlock
[34]   PropertyList   ::=   PropertyListNotEmpty?
[35]   PropertyListNotEmpty   ::=   Verb ObjectList ( ';' ( Verb ObjectList )? )*
[36]   Verb   ::=   VarOrIri | 'a'
[37]   ObjectList   ::=   Object ( ',' Object )*
[38]   Object   ::=   GraphNode Annotation
[39]   TriplesSameSubjectPath   ::=   VarOrTerm PropertyListPathNotEmpty | TriplesNodePath PropertyListPath | ReifiedTripleBlockPath
[40]   PropertyListPath   ::=   PropertyListPathNotEmpty?
[41]   PropertyListPathNotEmpty   ::=   ( VerbPath | VerbSimple ) ObjectListPath ( ';' ( ( VerbPath | VerbSimple ) ObjectListPath )? )*
[42]   VerbPath   ::=   Path
[43]   VerbSimple   ::=   Var
[44]   ObjectListPath   ::=   ObjectPath ( ',' ObjectPath )*
[45]   ObjectPath   ::=   GraphNodePath AnnotationPath
[46]   Path   ::=   PathSequence
[47]   PathSequence   ::=   PathEltOrInverse ( '/' PathEltOrInverse )*
[48]   PathEltOrInverse   ::=   PathElt | '^' PathElt
[49]   PathElt   ::=   PathPrimary
[50]   PathPrimary   ::=   iri | 'a' | '(' Path ')'
[51]   TriplesNode   ::=   Collection | BlankNodePropertyList
[52]   BlankNodePropertyList   ::=   '[' PropertyListNotEmpty ']'
[53]   TriplesNodePath   ::=   CollectionPath | BlankNodePropertyListPath
[54]   BlankNodePropertyListPath   ::=   '[' PropertyListPathNotEmpty ']'
[55]   Collection   ::=   '(' GraphNode+ ')'
[56]   CollectionPath   ::=   '(' GraphNodePath+ ')'
[57]   AnnotationPath   ::=   ( Reifier | AnnotationBlockPath )*
[58]   AnnotationBlockPath   ::=   '{|' PropertyListPathNotEmpty '|}'
[59]   Annotation   ::=   ( Reifier | AnnotationBlock )*
[60]   AnnotationBlock   ::=   '{|' PropertyListNotEmpty '|}'
[61]   GraphNode   ::=   VarOrTerm | TriplesNode | ReifiedTriple
[62]   GraphNodePath   ::=   VarOrTerm | TriplesNodePath | ReifiedTriple
[63]   VarOrTerm   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL | TripleTerm
[64]   ReifiedTriple   ::=   '<<' ReifiedTripleSubject Verb ReifiedTripleObject Reifier? '>>'
[65]   ReifiedTripleSubject   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple
[66]   ReifiedTripleObject   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple | TripleTerm
[67]   TripleTerm   ::=   '<<(' TripleTermSubject Verb TripleTermObject ')>>'
[68]   TripleTermSubject   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode
[69]   TripleTermObject   ::=   Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTerm
[70]   TripleTermData   ::=   '<<(' TripleTermDataSubject ( iri | 'a' ) TripleTermDataObject ')>>'
[71]   TripleTermDataSubject   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral
[72]   TripleTermDataObject   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral | TripleTermData
[73]   VarOrIri   ::=   Var | iri
[74]   Var   ::=   VAR1 | VAR2
[75]   Expression   ::=   ConditionalOrExpression
[76]   ConditionalOrExpression   ::=   ConditionalAndExpression ( '||' ConditionalAndExpression )*
[77]   ConditionalAndExpression   ::=   ValueLogical ( '&&' ValueLogical )*
[78]   ValueLogical   ::=   RelationalExpression
[79]   RelationalExpression   ::=   NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )?
[80]   NumericExpression   ::=   AdditiveExpression
[81]   AdditiveExpression   ::=   MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )*
[82]   MultiplicativeExpression   ::=   UnaryExpression ( '*' UnaryExpression | '/' UnaryExpression )*
[83]   UnaryExpression   ::=     '!' PrimaryExpression
| '+' PrimaryExpression
| '-' PrimaryExpression
| PrimaryExpression
[84]   PrimaryExpression   ::=   BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[85]   ExprTripleTerm   ::=   '<<(' ExprTripleTermSubject Verb ExprTripleTermObject ')>>'
[86]   ExprTripleTermSubject   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var
[87]   ExprTripleTermObject   ::=   iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[88]   BrackettedExpression   ::=   '(' Expression ')'
[89]   BuiltInCall   ::=     'STR' '(' Expression ')'
| 'LANG' '(' Expression ')'
| 'LANGMATCHES' '(' Expression ',' Expression ')'
| 'LANGDIR' '(' Expression ')'
| 'DATATYPE' '(' Expression ')'
| 'BOUND' '(' Var ')'
| 'IRI' '(' Expression ')'
| 'URI' '(' Expression ')'
| 'BNODE' ( '(' Expression ')' | NIL )
| 'RAND' 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
| 'MD5' '(' Expression ')'
| 'SHA1' '(' Expression ')'
| 'SHA256' '(' Expression ')'
| 'SHA384' '(' Expression ')'
| 'SHA512' '(' Expression ')'
| 'COALESCE' ExpressionList
| '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 ')'
[90]   iriOrFunction   ::=   iri ArgList?
[91]   RDFLiteral   ::=   String ( LANG_DIR | '^^' iri )?
[92]   NumericLiteral   ::=   NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative
[93]   NumericLiteralUnsigned   ::=   INTEGER | DECIMAL | DOUBLE
[94]   NumericLiteralPositive   ::=   INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE
[95]   NumericLiteralNegative   ::=   INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE
[96]   BooleanLiteral   ::=   'true' | 'false'
[97]   String   ::=   STRING_LITERAL1 | STRING_LITERAL2 | STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2
[98]   iri   ::=   IRIREF | PrefixedName
[99]   PrefixedName   ::=   PNAME_LN | PNAME_NS
[100]   BlankNode   ::=   BLANK_NODE_LABEL | ANON

Productions for terminals:

[101]   IRIREF   ::=   '<' ([^<>"{}|^`\]-[#x00-#x20])* '>'
[102]   PNAME_NS   ::=   PN_PREFIX? ':'
[103]   PNAME_LN   ::=   PNAME_NS PN_LOCAL
[104]   BLANK_NODE_LABEL   ::=   '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
[105]   VAR1   ::=   '?' VARNAME
[106]   VAR2   ::=   '$' VARNAME
[107]   LANG_DIR   ::=   '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)* ('--' [a-zA-Z]+)?
[108]   INTEGER   ::=   [0-9]+
[109]   DECIMAL   ::=   [0-9]* '.' [0-9]+
[110]   DOUBLE   ::=   ( ([0-9]+ ('.'[0-9]*)? ) | ( '.' ([0-9])+ ) ) [eE][+-]?[0-9]+
[111]   INTEGER_POSITIVE   ::=   '+' INTEGER
[112]   DECIMAL_POSITIVE   ::=   '+' DECIMAL
[113]   DOUBLE_POSITIVE   ::=   '+' DOUBLE
[114]   INTEGER_NEGATIVE   ::=   '-' INTEGER
[115]   DECIMAL_NEGATIVE   ::=   '-' DECIMAL
[116]   DOUBLE_NEGATIVE   ::=   '-' DOUBLE
[117]   STRING_LITERAL1   ::=   "'" ( ([^#x27#x5C#xA#xD]) | ECHAR )* "'"
[118]   STRING_LITERAL2   ::=   '"' ( ([^#x22#x5C#xA#xD]) | ECHAR )* '"'
[119]   STRING_LITERAL_LONG1   ::=   "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR ) )* "'''"
[120]   STRING_LITERAL_LONG2   ::=   '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR ) )* '"""'
[121]   ECHAR   ::=   '\' [tbnrf\"']
[122]   NIL   ::=   '(' WS* ')'
[123]   WS   ::=   #x20 | #x9 | #xD | #xA
[124]   ANON   ::=   '[' WS* ']'
[125]   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]
[126]   PN_CHARS_U   ::=   PN_CHARS_BASE | '_'
[127]   VARNAME   ::=   ( PN_CHARS_U | [0-9] ) ( PN_CHARS_U | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] )*
[128]   PN_CHARS   ::=   PN_CHARS_U | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
[129]   PN_PREFIX   ::=   PN_CHARS_BASE ((PN_CHARS|'.')* PN_CHARS)?
[130]   PN_LOCAL   ::=   (PN_CHARS_U | ':' | [0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )?
[131]   PLX   ::=   PERCENT | PN_LOCAL_ESC
[132]   PERCENT   ::=   '%' HEX HEX
[133]   HEX   ::=   [0-9] | [A-F] | [a-f]
[134]   PN_LOCAL_ESC   ::=   '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?' | '#' | '@' | '%' )

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.