This document defines the translation of Shape Expressions to SHACL.

This is a working document. The contents are expected to go to some other document. For the moment, keeping this document short minimizes respec race conditions.

This document defines a mapping from the ShEx JSON syntax to the SHACL abstract syntax. The input schema is expressed in this style:

Schema{ shapes:{shapeLabel->shapeExpr}? }

and the output schema in this style:

Schema := shapes:Set[Shape]

Examples provide mappings from ShExC to SHACL schemas.

Mapping to SHACL

A ShEx schema is translated to a SHACL schema by recursively applying the construction rules below:

Schema{ shapes:{shapeLabel->shapeExpr}? }
shapeLabel=IRI | BNODE ;

Shape Expressions

Schema := shapes:Set[Shape]
Shape := label:IRI|BNode, targets:Set[Target], filters:Set[Shape], constraints:Set[Test]
Test := Constraint|Algebraic
Algebraic := And|Or|Not
Constraint := NodeConstraint|PathConstraint

The map ShEx shapes is treated as a set of (shapeLabel, shapeExpr) pairs. The label is used as the subject node of SHACL/RDF Shape constructions.

ShEx:

<IssueShape> { ... }

SHACL:

<IssueShape> a sh:Shape ...
ShapeOr{shapeExprs:[shapeExpr] }
Or := shapes:Set[Shape]

Each shapeExpr in shapeExprs is consructed as a Shape in shapes.

ShEx:

<User> @<Person> OR <Customer>

SHACL:

<User> sh:constraint [ sh:or (<Person> <Customer>) ]
ShapeAnd{shapeExprs:[shapeExpr] }
And := shapes:Set[Shape]

Each shapeExpr in shapeExprs is consructed as a Shape in shapes.

ShEx:

<User> @<Person> AND <Customer>

SHACL:

<User> sh:constraint [ sh:and (<Person> <Customer>) ]
ShapeNot{shapeExpr:shapeExpr }
Not := shape:Shape

The shapeExpr shape is consructed as the Shape shapes.

ShEx:

<User> @<Person> AND NOT <Customer>

SHACL:

<User> sh:constraint [ sh:and (<Person> [ sh:not <Customer> ]) ]
ShapeRef{reference:shapeLabel }

The construction of a ShapeRef is the construction of the shapeExpr for shapeLabel in the ShEx Schema's shapes map.

ShEx:

<User> @<Person>
<Person> <X> AND <Y>

SHACL:

<User> sh:constraint [ sh:and (<X> <Y> ) ]
ShapeExternal{/* empty */ }

A schemas with a ShapeExternal has no translation to SHACL.

Node Constraints

NodeConstraint{nodeKind:("iri" | "bnode" | "nonliteral" | "literal")? datatype:IRI? xsFacet* values:[valueSetValue]? }
NodeConstraint := parms:Set[Parameter]
Parameter := UnaryParameter | NaryParameter

A ShEx NodeConstraint constructs a set of SHACL Parameters.

NodeKind := kind:"IRI"|"blank node"|"nonliteral"|"literal"

A ShEx nodeKind translates to:

ShEx:

<IssueShape> { ex:state [ex:Resolved, ex:Rejected] }

SHACL:

<IssueShape> sh:property [ sh:predicate ex:state; sh:in (ex:Resolved, ex:Rejected) ] .

Object Values

objectValue=IRI | STRING | DATATYPE_STRING | LANG_STRING ;
valueSetValue=objectValue | Stem | StemRange ;
Stem{stem:IRI }
StemRange{stem:(IRI | Wildcard) exclusions:[objectValue|Stem]? }
Wildcard{/* empty */ }
In := vals:Set[RDF term]
Stem := str:RDFLiteral

A ShEx values translates as follows: Construct a list l of RDF terms and a list ors of NodeConsraints. For valueSetValue v in vals:

  • if v is an objectValue, l = l+l.
  • if v is a Stem, ors = ors+NodeConstraint(Stem(v.stem)).
  • if v is a StemRange, construct a set of exclusions ex as follows: For each objectValue or Stem t in exclusions,
    • if t is an objectValue, ex = ex+l.
    • if t is a Stem, ors = ors+NodeConstraint(Stem(v.stem)).
    ors = ors+And(NodeConstraint(Stem(v.stem)), Not(Or(ex))).

A ShEx values translates to:

  • if ors is empty, In(l)

    ShEx:

    <Issue> { ex:status [ex:Unassigned ex:Assigned ex:Resolved] }

    SHACL:

    <Issue> [ ex:property ex:status; sh:in (ex:Unassigned ex:Assigned ex:Resolved)
  • otherwise, Or(In(l),Or(ors))

    ShEx:

    <Issue> { ex:status [ex:Unassigned ex:Assigned-by~ ex:Resolved-by~ - ex:Resolved-by-dismissal - ex:Resolved-by-dismissal-for~] }

    SHACL:

    <Issue> [ ex:property ex:status;
      sh:shape [ sh:or (
        [ sh:in (ex:Unassigned) ]
        [ sh:stem ex:Assigned-by ]
        [ sh:and (
          [ sh:stem ex:Resolved-by~ ]
          [ not [ sh:in (ex:Resolved-by-dismissal) ] ]
          [ not [ sh:stem (ex:Resolved-by-dismissal-for) ] ] ) ] ) ] ]

Datatypes

Datatype := dt:IRI

A ShEx datatype of t translates to a Datatype(t)

ShEx:

<DateShape> xsd:dateTime

SHACL:

<Dateshape> sh:datatype xsd:dateTime

XML Schema Facets

xsFacet=stringFacet | numericFacet ;
stringFacet=("length"|"minlength"|"maxlength"):INTEGER | pattern:STRING ;
MinLength := ref:numeric
MaxLength := ref:numeric
Pattern := pat:RDFLiteral, flagstr:RDFLiteral
numericFacet=("mininclusive"|"minexclusive"|"maxinclusive"|"maxexclusive"):numericLiteral
|("totaldigits"|"fractiondigits"):INTEGER ;
numericLiteral=INTEGER | DECIMAL | DOUBLE ;
MinInclusive := ref:RDFLiteral
MinExclusive := ref:RDFLiteral
MaxInclusive := ref:RDFLiteral
MaxExclusive := ref:RDFLiteral

Shapes

Shape{closed:BOOL? extra:[IRI]? expression:tripleExpr?]? }

Triple Expressions

PartitionConstraint := expression:Sexpr, extra:Set[IRI]
Sexpr := Choice|Group|PathConstraint

The construction of a Shape is a Partition with an expression of the construction of the tripleExpr and expression.

EachOf{expressions:[tripleExpr] min:INTEGER? max:(INTEGER | "*")? semActs:[SemAct]? annotations:[Annotation]? }
Group := exprs:Set[Sexpr]

Each tripleExpr in tripleExprs is consructed as a Shape in shapes.

ShEx:

<User> { foaf:givenName . ; foaf:familyName }

SHACL:

<User> sh:partition [ sh:group (
    [ sh:property foaf:givenName; sh:minCount 1; sh:maxCount 1 ]
    [ sh:property foaf:familyName; sh:minCount 1; sh:maxCount 1 ]
) ]
SomeOf{expressions:[tripleExpr] min:INTEGER? max:(INTEGER | "*")? semActs:[SemAct]? annotations:[Annotation]? }
Choice := exprs:Set[Sexpr]

Each tripleExpr in tripleExprs is consructed as a Shape in shapes.

ShEx:

<User> { foaf:name . | vcard:name }

SHACL:

<User> sh:partition [ sh:choice (
    [ sh:property foaf:name; sh:minCount 1; sh:maxCount 1 ]
    [ sh:property vcard:name; sh:minCount 1; sh:maxCount 1 ]
) ]
TripleConstraint{inverse:BOOL? negated:BOOL? predicate:IRI valueExpr:shapeExpr? min:INTEGER? max:(INTEGER | "*")? semActs:[SemAct]? annotations:[Annotation]? }
PathConstraint := path:SPARQLPropertyPath, parms:Set[Parameter]
Inclusion{include:shapeLabel }

The construction of a Inclusion is the construction of the shapeExpr for shapeLabel in the ShEx Schema's shapes map.

Semantic Actions

SemAct{name:IRI code:STRING? }

A schemas with a ShapeExternal has no translation to SHACL.

Annotations

Annotation{predicate:IRI object:objectValue }

ShEx Annotations construct triples with the subject of the current expression, predicate predicate and object: object