I recently approached SHACL and I really like it. I have a problem with SHACL rules and I wonder if any of you could help me.
I created this small ontology, a portion of a much bigger ontology for the GDPR that I am working on.
# baseURI: http://w3.org/ns/temp
# prefix: temp
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix temp: <http://w3.org/ns/temp#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://w3.org/ns/temp>
rdf:type owl:Ontology ;
owl:versionInfo "Created with TopBraid Composer" ;
.
temp:Action
rdf:type owl:Class ;
rdfs:subClassOf owl:Thing ;
.
temp:Consent
rdf:type owl:Class ;
rdfs:subClassOf owl:Thing ;
.
temp:DataSubject
rdf:type owl:Class ;
rdfs:subClassOf owl:Thing ;
.
temp:GiveConsent
rdf:type owl:Class ;
rdfs:subClassOf temp:Action ;
.
temp:John
rdf:type temp:DataSubject ;
.
temp:LegalBasis
rdf:type owl:Class ;
rdfs:subClassOf owl:Thing ;
.
temp:PersonalDataProcessing
rdf:type owl:Class ;
rdfs:subClassOf owl:Thing ;
.
temp:c
rdf:type temp:Consent ;
temp:objectOfConsent temp:pdp ;
.
temp:gc
rdf:type temp:GiveConsent ;
temp:hasAgent temp:John ;
temp:hasPatient temp:c ;
.
temp:hasAgent
rdf:type owl:FunctionalProperty ;
rdfs:domain temp:GiveConsent ;
rdfs:range temp:DataSubject ;
.
temp:hasLegalBasis
rdf:type owl:FunctionalProperty ;
rdfs:domain temp:PersonalDataProcessing ;
rdfs:range temp:LegalBasis ;
.
temp:hasPatient
rdf:type owl:FunctionalProperty ;
rdfs:domain temp:GiveConsent ;
rdfs:range temp:Consent ;
.
temp:isLawful
rdf:type owl:DatatypeProperty ;
rdfs:domain temp:PersonalDataProcessing ;
rdfs:range xsd:boolean ;
.
temp:objectOfConsent
rdf:type owl:FunctionalProperty ;
rdfs:domain temp:Consent ;
rdfs:range temp:PersonalDataProcessing ;
.
temp:pdp
rdf:type temp:PersonalDataProcessing ;
.
There are five main classes: PersonalDataProcessing, DataSubject, LegalBasis, Consent, and GiveConsent. And, there are four (functional) object properties:
- hasLegalBasis (domain: PersonalDataProcessing, range: LegalBasis).
- hasAgent (domain: GiveConsent, range: DataSubject)
- hasPatient (domain: GiveConsent, range: Consent)
- objectOfConsent (domain: Consent, range: PersonalDataProcessing)
And there is one datatype (boolean) property called "isLawful" and defined on PersonalDataProcessing: every PersonalDataProcessing can be lawful (isLawful=true) or not (isLawful=false).
I created an individual "gc" within the class GiveConsent. "gc" has an agent "John" (who is a DataSubject) and a patient "c" (which is a Consent). The Consent "c" is connected via the property objectOfConsent to another individual "pdp", which is a PersonalDataProcessing.
Then I have two SHACL rules. One of them has "sh:order 1", so it should be executed after the other one (which has default sh:order equal to 0);
# baseURI: http://w3.org/ns/rules
# imports: http://w3.org/ns/temp
# prefix: rules
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rules: <http://w3.org/ns/rules#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix temp: <http://w3.org/ns/temp#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<http://w3.org/ns/rules>
rdf:type owl:Ontology ;
owl:imports <http://w3.org/ns/temp> ;
owl:versionInfo "Created with TopBraid Composer" ;
.
rules:givenConsentIsLegalBasis
rdf:type sh:NodeShape ;
sh:rule [
rdf:type sh:TripleRule ;
sh:object [
sh:path temp:hasPatient ;
] ;
sh:predicate temp:hasLegalBasis ;
sh:subject [
sh:path (
temp:hasPatient
temp:objectOfConsent
) ;
] ;
] ;
sh:targetClass temp:GiveConsent ;
.
rules:legalBasisEntailLawful
rdf:type sh:NodeShape ;
sh:rule [
rdf:type sh:TripleRule ;
sh:order 1 ;
sh:condition [
sh:property [
sh:path temp:hasLegalBasis ;
sh:minCount 1 ;
] ;
] ;
sh:object "true"^^xsd:boolean ;
sh:predicate temp:isLawful ;
sh:subject sh:this ;
] ;
sh:targetClass temp:PersonalDataProcessing ;
.
The first rule above states that if someone has given consent to a PersonalDataProcessing, that consent is a legal basis for the PersonalDataProcessing. The second rule (with "sh:order 1 ;") states that every PersonalDataProcessing that has a legal basis is lawful.
Finally I wrote a Java file to execute the rules:
//Load the ontology
Model ontology = JenaUtil.createMemoryModel();
FileInputStream fisOntology = new FileInputStream("./ontology.ttl");
ontology.read(fisOntology, "urn:dummy", FileUtils.langTurtle);
//Load the rules
Model rules = JenaUtil.createMemoryModel();
FileInputStream fisRules = new FileInputStream("./rules.ttl");
rules.read(fisRules, "urn:dummy", FileUtils.langTurtle);
//Executing the rules
Model inferredModel = RuleUtil.executeRules(ontology, rules, null, null);
//Print
System.out.println(ModelPrinter.get().print(inferredModel));
I am writing you because the first rule correctly creates the triple "pdp hasLegalBasis c" via the Java code above:
<http://w3.org/ns/temp#pdp>
<http://w3.org/ns/temp#hasLegalBasis>
<http://w3.org/ns/temp#c> ;
However, the second rule do NOT trigger after this triple is inferred: isLawful is NOT set to true.
On the other hand, if I manually add the triple "pdp hasLegalBasis c" in the ontology, both rules triggers:
<http://w3.org/ns/temp#pdp>
<http://w3.org/ns/temp#hasLegalBasis>
<http://w3.org/ns/temp#c> ;
<http://w3.org/ns/temp#isLawful>
true .
What am I doing wrong? Can any of you help me?
Thank you very much