Validating RDF data with SHACL

latest update: 2018-12-21

Introduction

This topic is a first attempt to apply the new W3C Recommendation "Shapes Constraint Language (SHACL)", dated 20 July 2017,  to ISO 15926-7/8 data.

Reference is made to that Recommendation https://www.w3.org/TR/shacl/ and a (free) on-line book with ample examples http://book.validatingrdf.com .

Also of interest: SHACL Test Suite and Implementation Report - W3C Document 09 January 2018

This technology is brandnew and still in development, but, as may be concluded, very well suited for the validation of ISO 15926-8 exchange files.

Validating a declared object

Assume the signature of the TIP for the declaration of a PhysicalObject with the shown example data values:

TIP_1761 - DeclarationOfActualPhysicalObject

Element No

Role Variable

Description of Variable

Example values

1

TIP_P1761_var_Label

Human readable identifier of the PhysicalObject that is being declared and that, normally, shall stay with it forever (here Serial Number)

TK349834-a

2

TIP_P1761_var_Label#EntityType

ISO 15926 entity type of which the declared PhysicalObject is an instance

InanimatePhysicalObject

3

TIP_P1761_var_Label#EssentialType

The essential class of the PhysicalObject, of which the membership is always applicable; if no longer, the PhysicalObject ends its life

PUMP SYSTEM

4

TIP_P1761_var_Label#WorldType

Does the PhysicalObject exists in the real world or in some imaginary, non-actual, world like Design World ? Here fixed at ActualIndividual

ActualIndividual

5

TIP_P1761_var_LifecycleActivity

The ID of the ClassOfActivity in the RDL or an extension thereof that classifies any Activity that caused this information to exist

MANUFACTURING

6

TIP_P1761_var_EffectiveDate

The dateTime that the declaration did become effective

2018-01-09T14:05:23Z

 

These data in the TIP signature are filled in into the generic code below:

 

        <id(TIP_P1761_var_Label)>

            rdf:type <id(TIP_P1761_var_Label#EntityType)>, <id(TIP_P1761_var_Label#EssentialType)>, <id(TIP_P1761_var_Label#WorldType)>, dm:WholeLifeIndividual ;

            rdfs:label "TIP_P1761_var_Label"@en ;

            meta:hasLifecycleActivity <id(TIP_P1761_var_LifecycleActivity)> ;

            meta:valEffectiveDate "TIP_P1761_var_EffectiveDate"^^xsd:dateTime .

 

which results, when using the given example data values, in (the identifiers are fetched by inputting the labels):

 

        :112473e9-7642-45d2-ade2-c68a5ed47cf3

            rdf:type lci:InanimatePhysicalObject, rdl:RDS414081061, dm:ActualIndividual, dm:WholeLifeIndividual ; # PUMP SYSTEM

            rdfs:label "TK349834-a"@en ;

            meta:hasLifecycleActivity rdl:RDS9661877 ; # MANUFACTURING

            meta:valEffectiveDate "2018-01-09T14:05:23Z"^^xsd:dateTime .

 

NOTES - The meta:valDeprecationDate will, if at all, be applicable (much) later and will be added then in the form of an extra triple.

This is the RDF code that shall be validated with SHACL, thereby referring to the code below that generically applies to the above TIP:

Related SHACL code

@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .

@prefix sh:    <http://www.w3.org/ns/shacl#> .

@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .

@prefix dm:    <http://data.15926.org/dm/> .

@prefix lci:   <http://data.15926.org/lci/> .

@prefix meta:  <http://data.15926.org/meta/> .

@prefix rdl:   <http://data.15926.org/rdl/> .

@prefix shacl: <http://data.15926.org/shacl/> .

 

:PhysicalObjectShacl a sh:NodeShape ; # Note that the word Shape has been replaced with Shacl, because Shape is too confusing in the context of ISO 15926.

    sh:nodeKind sh:IRI ;

    sh:targetClass dm:PhysicalObject ;

# There shall be at least four occurrences of rdf:type

    sh:property [

        sh:path rdf:type ;

        sh:minCount 4 ;

    ];

# The PhysicalObject shall at least be typed with one subclass of dm:PhysicalObject

    sh:property [

        sh:path (rdf:type rdfs:subClassOf) ;

        sh:hasValue dm:PhysicalObject ;

        sh:minCount 1 ;

    ];

# The PhysicalObject shall be typed with exactly one of the classes in the list

    sh:property [

        sh:path rdf:type ;

        sh:qualifiedValueShape [

            sh:in   ( lci:InanimatePhysicalObject lci:Person lci:Organism lci:Organization lci:Feature lci:InformationObject lci:Energy dm:Stream dm:SpatialLocation ) ;

        ] ;

        sh:qualifiedMinCount 1 ;

        sh:qualifiedMaxCount 1 ;

    ] ;

# The PhysicalObject shall be typed with dm:ActualIndividual

    sh:property [

        sh:path rdf:type ;

        sh:hasValue dm:ActualIndividual

        sh:qualifiedMinCount 1 ;

        sh:qualifiedMaxCount 1 ;

    ] ;

# The PhysicalObject shall be typed with dm:WholeLifeIndividual

    sh:property [

        sh:path rdf:type ;

        sh:hasValue dm:WholeLifeIndividual ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ] ;

# The PhysicalObject shall have one rdfs:label

    sh:property [

        sh:path rdfs:label ;

        sh:datatype xsd:string ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ] ;

# The PhysicalObject may have one or more skos:altLabel

    sh:property [

        sh:path skos:altLabel ;

        sh:datatype xsd:string ;

        sh:minCount 0 ;

    ] ;

# The PhysicalObject shall have exactly one meta:hasLifecycleActivity

    sh:property [

        sh:path meta:hasLifecycleActivity ;

        sh:qualifiedValueShape [

            sh:in ( rdl:RDS9661877 rdl:RDS9664082 rdl:RDS2229993 rdl:RDS9685637 rdl:RDS9658862 rdl:RDS9686717  rdl:RDS9660257 rdl:RDS9661742 rdl:RDS14526342 ) ;

        ] ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ] ;

# The PhysicalObject shall have exactly one meta:valEffectiveDate

    sh:property [

        sh:path meta:valEffectiveDate ;

        sh:datatype xsd:dateTime ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ] ;

# The PhysicalObject may have one meta:valDeprecationDate

    sh:property [

        sh:path meta:valDeprecationDate ;

        sh:datatype xsd:dateTime ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] .

Validating a template instance

Assume the signature of the template IndividualHasPropertyWithValue:

TIP_P3001 - IndividualHasPropertyWithValue

Element No

Role Variable

Description of Variable

Example values

1

TIP_P3001_var_Label

Human readable identifier of the PhysicalObject that is being declared and that, normally, shall stay with it forever (here a Stream)

P-101-S-IN

2

TIP_P3001_var_Label#PropertyType The "direct Property" (dm:SinglePropertyDimension ) that is possessed by the PhysicalObject

GAUGE PRESSURE

3

TIP_P3001_var_Label#PropertyValue The numerical value (xsd:decimal) that of the possessed Property when mapped to the given Scale

"15.8"

4

TIP_P3001_var_Label#Scale The scale (dm:Scale) that is used for the possessed Property

BAR GAUGE

5

TIP_P1761_var_LifecycleActivity

The ID of the ClassOfActivity in the RDL or an extension thereof that classifies any Activity that caused this information to exist

OPERATIONS

6

TIP_P1761_var_EffectiveDate

The dateTime that the information, represented by this template, did become effective

2018-11-15T13:45:23Z

 

The example data values in the template signature result in a template instance:

 

:73131D3A1E3042FD8A4E9AEC8E70C99F

    rdf:type tpl:IndividualHasPropertyWithValue ;

    rdfs:label "[Stream] [P-101-S-IN] has a [GAUGE PRESSURE] of [15.8] [BAR GAUGE]" ;

    tpl:hasPropertyPossessor :8875A120FE284D45A954ABBEB472BB00 ; # Stream P-101-S-IN (earlier declared)

    tpl:hasPropertyType rdl:RDS7345161 ; # GAUGE PRESSURE

    tpl:valPropertyValue "15.8"^^xsd:decimal ;

    tpl:hasScale rdl:RDS1348874 ; # BAR GAUGE

    meta:hasLifecycleActivity rdl:RDS9660257 ; # OPERATING (= OPERATIONS)

    meta:valEffectiveDate "2018-11-15T13:45:23Z"^^xsd:dateTime .

Related SHACL code

@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .

@prefix sh:    <http://www.w3.org/ns/shacl#> .

@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .

@prefix dm:    <http://data.15926.org/dm/> .

@prefix lci:   <http://data.15926.org/lci/> .

@prefix meta:  <http://data.15926.org/meta/> .

@prefix rdl:   <http://data.15926.org/rdl/> .

@prefix shacl: <http://data.15926.org/shacl/> .

 

:IndividualHasPropertyWithValueShacl a sh:NodeShape ;

    sh:targetClass tm:Template ;

    sh:nodeKind sh:IRI ;

    sh:closed true ; # Only the sh:path's shown below are acceptable

    sh:class tpl:IndividualHasPropertyWithValue ;

# The Template shall have exactly one sh:property called tpl:hasPropertyPossessor of which the object shall be typed dm:PossibleIndividual or a subtype thereof

    sh:property [

        sh:path (tpl:hasPropertyPossessor rdf:type);

        sh:hasValue dm:PossibleIndividual ;

        sh:minCount 1 ;

    ] ;

    sh:property [

        sh:path tpl:hasPropertyPossessor ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ];

# The Template shall have exactly one sh:property called tpl:hasPropertyType of which the object shall be a subclass of dm:Property

    sh:property [

        sh:path (tpl:hasPropertyType rdfs:subClassOf) ;

        sh:hasValue dm:Property ;

        sh:minCount 1 ;

    ];

    sh:property [

        sh:path tpl:hasPropertyType ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ];

# The Template shall have exactly one sh:property called tpl:valPropertyValue with an xsd:decimal data value

    sh:property [

        sh:path     tpl:valPropertyValue ;

        sh:datatype xsd:decimal ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ] .

# The Template shall have exactly one sh:property called tpl:hasScale of which the object shall be typed dm:Scale

    sh:property [

        sh:path (tpl:hasScale rdf:type) ;

        sh:hasValue dm:Scale ;

        sh:minCount 1 ;

    ] ;

    sh:property [

        sh:path tpl:hasScale ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ];

# The Template shall have exactly one meta:valEffectiveDate

    sh:property [

        sh:path     meta:valEffectiveDate ;

        sh:datatype xsd:dateTime ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ] ;

# The Template may have one meta:valDeprecationDate

    sh:property [

        sh:path     meta:valDeprecationDate ;

        sh:datatype xsd:dateTime ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] .

Validating an Information Model

Assume an information model of a centrifugal pump:

For each node a sh:NodeShape is defined, and above relations are defined as sh:Property of the Node that is the subject of that Property. 

For example between PUMP and PUMP DESIGN CLASS:

  • define the PUMP with three sh:Property's : 1x classifier, 1x contains, and 1x locatedAt;
  • define PUMP DESIGN CLASS with 7x hasPart, 3x subjectedTo, and 1x performs.

Related SHACL code

@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .

@prefix sh:    <http://www.w3.org/ns/shacl#> .

@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .

@prefix dm:    <http://data.15926.org/dm/> .

@prefix lci:   <http://data.15926.org/lci/> .

@prefix meta:  <http://data.15926.org/meta/> .

@prefix rdl:   <http://data.15926.org/rdl/> .

@prefix shacl: <http://data.15926.org/shacl/> .

<> owl:imports <http://data.15926.org/shacl/declared_objects> . # imports all SHACL code for declared objects (like :PhysicalObjectShape above) so that we re-use that code. # NOTE - This obviously still has to be built

:CentrifugalPumpShacl a sh:NodeShape ;

    sh:node :PumpShacl ; # re-using the generic shacl:PumpShacl that in turn is re-using the shacl:PhysicalObjectShacl NodeShape.

    sh:targetClass lci:InanimatePhysicalObject ;

# The (individual) CentrifugalPump is classified (typed) with :CentrifugalPumpClass

    sh:property [

        sh:path imod:classifier ;

        sh:targetNode :CentrifugalPumpClass ;

        sh:minCount 1 ;

    ] ;

# The (individual) CentrifugalPump may contain one :Stream

    sh:property [

        sh:path imod:contains ;

        sh:targetNode :Stream ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] ;

# The (individual) CentrifugalPump may be located at one :PumpLocation

    sh:property [

        sh:path imod:locatedAt ;

        sh:targetNode :PumpLocation ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] .

 

:CentrifugalPumpClassShacl a sh:NodeShape ;

    sh:node :DynamicPumpClassShacl ;

    sh:targetClass rdl:RDS416834 ;

# Members of CentrifugalPumpClass have exactly one :PumpCasing as a part

    sh:property [

        sh:path imod:hasPart ;

        sh:targetNode :PumpCasing ;

        sh:minCount 1 ;

        sh:maxCount 1 ;

    ] ;

# Members of CentrifugalPumpClass have at least one :Impeller as a part

    sh:property [

        sh:path imod:hasPart ;

        sh:targetNode :Impeller ;

        sh:minCount 1 ;

# Members of CentrifugalPumpClass have at least one :Bearing as a part

    ] ;

    sh:property [

        sh:path imod:hasPart ;

        sh:targetNode :Bearing ;

        sh:minCount 1 ;

    ] ;

# Members of CentrifugalPumpClass may have one :BearingLubricationSystem as a part

    sh:property [

        sh:path imod:hasPart ;

        sh:targetNode :BearingLubricationSystem ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] ;

# Members of CentrifugalPumpClass have at least one :PumpDriver as a part

    sh:property [

        sh:path imod:hasPart ;

        sh:targetNode :PumpDriver ;

        sh:minCount 1 ;

    ] ;

# Members of CentrifugalPumpClass have at least one :PumpCoupling as a part

    sh:property [

        sh:path imod:hasPart ;

        sh:targetNode :PumpCoupling ;

        sh:minCount 1 ;

    ] ;

# Members of CentrifugalPumpClass may have one :PumpPipingPlan as a part

    sh:property [

        sh:path imod:hasPart ;

        sh:targetNode :PumpPipingPlan ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] ;

# Members of CentrifugalPumpClass may be subjected to one :ShopInspectionHydrostatic (at a time)

    sh:property [

        sh:path imod:subjectedTo ;

        sh:targetNode :ShopInspectionHydrostatic ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] ;

# Members of CentrifugalPumpClass may be subjected to one :ShopInspectionHydrostatic (at a time)

    sh:property [

        sh:path imod:subjectedTo ;

        sh:targetNode :ShopInspectionPerformanceVibration ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] ;

# Members of CentrifugalPumpClass may be subjected to one :ShopInspectionTwoHourRun (at a time)

    sh:property [

        sh:path imod:subjectedTo ;

        sh:targetNode :ShopInspectionTwoHourRun ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] ;

# Members of CentrifugalPumpClass may perform one :PumpingActivity (at a time)

    sh:property [

        sh:path imod:performs ;

        sh:targetNode :PumpingActivity ;

        sh:minCount 0 ;

        sh:maxCount 1 ;

    ] .


Tools

Below is a screen dump of a tool called Playground, that can be found at http://shacl.org/playground/


Work To Do

  • Validate the above.
  • Study SHACL-SPARQL, extending SHACL-Core with SPARQL; presumably we will need that because of the federated architecture of ISO 15926.

 

 

SHACL Constructs used in this Topic

(copied for quick reference from the W3C Recommendation)

This is only a subset of SHACL. Implementing ISO 15926 requires only the basic functions of whatever language is used. That is caused by the fact that ISO 15926 has an upper ontology (Part 2) that covers non-modal logic and is meant to register facts-only because it is to put life-cycle information on record in an integrated manner. It also assumes that the data coming from the source applications, and mapped to ISO 15926-8 format, are what they are and don't need to be semantically validated. That responsibility lies with those applications (and its users of course).


Tables in the book

SHACL validation result properties

Property

Description

sh:focusNode

The focus node that was being validated when the error happened

sh:resultPath

The path from the focus node. This property is optional usually corresponds to the sh:path declaration of property shapes

sh:value

The value that violated the constraint, when available

sh:sourceShape

The shape that the focus node was validated against when the constraint was violated.

sh:sourceConstraintComponent

The IRI that identifies the component that caused the violation.

sh:detail

May point to further details about the cause of the error. This property can be used for reporting errors in nested nested shapes.

sh:resultMessage

Textual details about the error. This message can be affected by the sh:message property (see section 5.6.4)

sh:resultSeverity

A value which is equal to the sh:severity value of the shape that caused the violation error. If the shape doesn’t have sh:severity declaration then the default value will be sh:Violation.

 

Table 5.2: SHACL and SPARQL paths
SHACL path SPARQL path
schema:name schema:name
[sh:inversePath schema:knows] ^schema:knows
(schema:knows schema:name) schema:knows/schema:name
[sh:alternativePath (schema:knows schema:follows)] schema:knows| schema:follows
[sh:zeroOrOnePath schema:knows] schema:knows?
[sh:oneOrMorePath schema:knows] schema:knows+
([sh:zeroOrMorePath schema:knowsschema:name) schema:knows*/schema:name

 

Target declarations

Value

Description

sh:targetNode

Directly point to a node

sh:targetClass

All nodes that are instances of some class

sh:targetSubjectsOf

All nodes that are subjects of some predicate

sh:targetObjectsOf

All nodes that are objects of some predicate

 

Constraints on values

Operation

Description

sh:datatype

Specifies the values must be literals with some datatype

sh:class

Specifies that values must be SHACL instances of some class

sh:nodeKind

Possible values: sh:BlankNode, sh:IRI, sh:Literal, sh:BlankNodeOrIRI, sh:BlankNodeOrLiteral, sh:IRIOrLiteral

sh:in

Enumerates the value nodes that a property is allowed to have

sh:hasValue

A node must have a given value

 

Node kinds

Nodekind

Description

sh:IRI

Nodes must be IRIs

sh:BlankNode

Nodes must be Blank nodes

sh:Literal

Nodes must be Literals

sh:BlankNodeOrLiteral

Nodes must be Blank nodes or literals

sh:BlankNodeOrIRI

Nodes must be Blank nodes or IRIs

sh:IRIOrLiteral

Nodes must be IRIs or literals

 

Logical operators

Operation

Description

sh:and

sh:and (S1 ... SN) specifies that each value node must conform to all the shapes S1SN.

sh:or

sh:or (S1 ... SN) specifies that each value node conforms to at least one of the shapes S1SN.

sh:not

sh:not S specifies that each value node must not conform to S.

sh:xone

sh:xone (S1 ... SN) specifies that exactly one node conforms to one of the shapes S1SN.

 

Closed shapes

Parameter

Description

sh:closed

Valid resources must only have values for properties that appear as values of sh:path in property shapes.

sh:ignoredProperties

List of predicates that are also permitted in addition to those that are explicitly enumerated

 

Property pair constraints

Operation

Description

sh:equals

The sets of values from both properties at a given focus node must be equal

sh:disjoint

The sets of values from both properties at a given focus node must be different

sh:lessThan

Current values must be smaller than another property values

sh:lessThanOrEquals

Current values must be smaller or equal than another property values