LeanRDF

SHACL

leanrdf-shacl implements SHACL Core: a shapes reader, the semantics as Lean propositions, a validator, and proofs that the validator computes the semantics in both directions. Book chapter 14 explains the proofs. The snippets are compiled from shacl/ShaclTests/Examples.lean.

Validate from Lean

private def shapes : List Shape := (readShapes (ttl "
  :PersonShape a sh:NodeShape ; sh:targetClass :Person ;
    sh:property [ sh:path :name ; sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ] ;
    sh:property [ sh:path :knows ; sh:class :Person ] .")).toOption.getD []

private def good : Graph := ttl ":ada a :Person ; :name \"Ada\" ; :knows :alan .
  :alan a :Person ; :name \"Alan\" ."

private def bad : Graph := ttl ":ada a :Person ; :name \"Ada\", \"A. Lovelace\" ; :knows :rex .
  :rex a :Dog ."

#guard (validate good shapes).conforms
#guard (validate bad shapes).results.map (·.component.val) ==
  ["http://www.w3.org/ns/shacl#MaxCountConstraintComponent",
   "http://www.w3.org/ns/shacl#ClassConstraintComponent"]

theorem good_conforms : DataConforms good shapes :=
  (validate_conforms good shapes).1 (by native_decide)

theorem bad_does_not_conform : ¬ DataConforms bad shapes := fun h =>
  absurd ((validate_conforms bad shapes).2 h) (by native_decide)

example : ∀ r ∈ (validate bad shapes).results, Violation bad r := fun _ h => validate_sound _ _ h

The API

DefinitionMeaning
readShapes sg : Except String (List Shape)the shapes of a shapes graph that have targets, with the shapes they refer to
validate G S : Reportconforms : Bool and results : List Result
Resultfocus, path, value, source (the shape), component, severity, messages
Report.toTurtle, readReportwrite a report in Turtle (§3.6); read one back, as the W3C tests do
Conforms G s xfocus node x conforms to shape s (the semantics)
DataConforms G Severy focus node of every shape conforms
Violation G rthe result names a shape and a component that fail at its focus node
ValueNode G p x y, valueNodesthe value nodes of a path, as a relation and computed
TheoremStatement
valueNodes_iffy ∈ valueNodes G p x ↔ ValueNode G p x y
results_nila focus node has no results exactly when it conforms
validate_conforms(validate G S).conforms = true ↔ DataConforms G S
validate_soundevery result of the report is a Violation

When the shapes and the data come from different files, rename the shapes graph's blank nodes apart first (renameShapes, as the command line does), so that the two graphs' blank nodes do not collide.

Supported

All 98 W3C SHACL Core tests pass, and the skip list is empty.

Not supported

Comparing with oxilite

oxilite validates with rudof. scripts/shacl-oxilite-fixtures.sh records oxilite's reports on the samples in shacl/ShaclTests/data/oxilite/, and ShaclTests/Oxilite.lean checks that both engines report the same results: focus node, path and component, result by result.