Reputation: 101
I want to make a reified 'statement about a statement', say I have userX memberOf groupY
and want to make a statement about that (say, that they joined on May 11).
So, I have something like:
statementX a rdf:statement
statementX subject userX
statementX predicate memberOf
statementX object groupY
statementX since "2022-05-11T11:32:52"^^xsd:dateTime
My question is, is it worthwhile subclassing rdf:statement
? Say UserGroupStatement rdf:subClassOf rdf:statement
, then statementX a UserGroupStatement
.
Does that make sense, is it something people do? Or do people just use rdf:statement
, or create their own joining classes? What would be the pros and cons?
In my thinking, it would at least allow me to model that a certain type of statement has certain properties, e.g. that a UserGroupStatement
has a 'since' property (domain UserGroupStatement
, range xsd:datetime
). But then I can see that it doesn't help me specify anything else, because the subject/predicate/object of the UserGroupStatement
could still be any Resource
. Or for modelling purposes should I just make a new statement-like linking object, and forget about rdf:statement altogether?
Upvotes: 2
Views: 109
Reputation: 12207
If it suits your use case, you can subclass rdf:Statement
but be careful about the capital S, as URIs are case sensitive.
You could then use OWL to restrict the properties on that subclass further but that would help you only with inference. I assume you want to validate your data, for that use case SHACL or ShEx are better suited.
@prefix : <http://example.org/>.
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix sh: <http://www.w3.org/ns/shacl#>.
# Ontology
:UserStatement rdfs:subClassOf rdf:Statement.
## Knowledge Base
:GroupY a :Group.
:UserX a :User; :memberOf :GroupY.
:AdminX a :Admin; :memberOf :GroupY.
:CorrectStatement a :UserStatement;
rdf:subject :UserX;
rdf:predicate :memberOf;
rdf:object :GroupY;
:since "2022-05-11T11:32:52"^^xsd:dateTime.
:IncorrectStatement1 a :UserStatement;
rdf:subject :AdminX;
rdf:predicate :memberOf;
rdf:object :GroupY;
:since "2022-05-11T11:32:52"^^xsd:dateTime.
:IncorrectStatement2 a :UserStatement;
rdf:subject :UserX;
rdf:predicate :schmemberOf;
rdf:object :GroupY;
:since "2022-05-11T11:32:52"^^xsd:dateTime.
:InorrectStatement3 a :UserStatement;
rdf:subject :UserX;
rdf:predicate :memberOf;
rdf:object :GroupY.
# SHACL Shape
:UserStatementShape a sh:NodeShape;
sh:targetClass :UserStatement;
sh:property
[sh:path rdf:type; sh:hasValue :UserStatement; sh:minCount 1; sh:maxCount 1],
[sh:path rdf:subject; sh:class :User; sh:minCount 1; sh:maxCount 1],
[sh:path rdf:predicate; sh:hasValue :memberOf; sh:minCount 1; sh:maxCount 1],
[sh:path rdf:object; sh:class :Group; sh:minCount 1; sh:maxCount 1],
[sh:path :since; sh:nodeKind sh:Literal; sh:datatype xsd:dateTime; sh:minCount 1; sh:maxCount 1];
sh:closed true.
Save the example as test.ttl
, install pySHACL and run pyshacl test.ttl
and you will get the following:
$ pyshacl test.ttl
Validation Report
Conforms: False
Results (3):
Constraint Violation in MinCountConstraintComponent (http://www.w3.org/ns/shacl#MinCountConstraintComponent):
Severity: sh:Violation
Source Shape: [ sh:datatype xsd:dateTime ; sh:maxCount Literal("1", datatype=xsd:integer) ; sh:minCount Literal("1", datatype=xsd:integer) ; sh:nodeKind sh:Literal ; sh:path :since ]
Focus Node: :InorrectStatement3
Result Path: :since
Message: Less than 1 values on :InorrectStatement3->:since
Constraint Violation in HasValueConstraintComponent (http://www.w3.org/ns/shacl#HasValueConstraintComponent):
Severity: sh:Violation
Source Shape: [ sh:hasValue :memberOf ; sh:maxCount Literal("1", datatype=xsd:integer) ; sh:minCount Literal("1", datatype=xsd:integer) ; sh:path rdf:predicate ]
Focus Node: :IncorrectStatement2
Result Path: rdf:predicate
Message: Node :IncorrectStatement2->rdf:predicate does not contain a value in the set: [':memberOf']
Constraint Violation in ClassConstraintComponent (http://www.w3.org/ns/shacl#ClassConstraintComponent):
Severity: sh:Violation
Source Shape: [ sh:class :User ; sh:maxCount Literal("1", datatype=xsd:integer) ; sh:minCount Literal("1", datatype=xsd:integer) ; sh:path rdf:subject ]
Focus Node: :IncorrectStatement1
Value Node: :AdminX
Result Path: rdf:subject
Message: Value does not have class :User
Upvotes: 1