Consider the following RDF:
semapi:BaseClass a rdfs:Class;
rdfs:subClassOf rdfs:Class .
semapi:hasChainTo a rdf:Property;
rdfs:domain semapi:BaseClass;
rdfs:range semapi:BaseClass .
semapi:DerivedClass a rdfs:Class; rdfs:subClassOf semapi:BaseClass .
instances:Instance1 a semapi:DerivedClass;
semapi:hasChainTo (
[
a semapi:DerivedClass;
semapi:hasChainTo (
[C1]
[C2]
)
]
)
If semapi:hasChainTo rdfs:range semapi:BaseClass
then it implies the list is rdf:type semapi:BaseClass
.
What I really mean to say is each item in the list is rdf:type
(ei. [C1] rdf:type semapi:BaseClass
, [C2] rdf:type semapi:BaseClass
, ...)
How can I do this? Do I need Owl (preferably not)?
Depending on how you want to do this, you have a few options. I think you're trying to stick to non-OWL reasoning, so we'll make sure to include such a solution, but I do want to touch on an OWL solution too, since for some similar situations, it works very well.
Using OWL and a custom ObjectList
If you do have the option of using an OWL reasoner, then this is a nice case in which you can create your own list vocabulary and use some property chains. The idea is that you introduce a class
List
with an individualnil
, and propertiesfirst
andrest
. You're really just copying the vocabulary in your own namespace. Then lets say you define two propertieslikes
: relates an individual X to another individual Y; "X likes Y".likesList
: relates an individual X to a List (not an RDF list, though) of individuals that X likes.Then you can introduce two property chain axioms
likesList subPropertyChain likesList o rest
: if X likesList (_ ...), then X likesList (...).This way, from
X likes (A B C)
we getX likes (A B C)
,X likes (B C)
,X likes (C)
, andX likes nil
.likes subPropertyChain likesList o first
: if X likesList (A ...), then X likes A.Then, from all those inferred statements above, we get
X likes A
,X likes B
, andX likes C
.In Turtle, this looks like:
This gets a bit inconvenient if you have to write the RDF manually, since you have to do
and can't use the nice
(...)
syntax that Turtle includes. This also really doesn't help for the case that you've got, since OWL classes aren't individuals, so they can't be the object of object properties, andrdf:type
isn't an object property. I just wanted to include this because it's a nice way for an object property to distribute over a (non-RDF) list of individuals, and because the approach makes the following solutions clearer.Using SPARQL queries
Given data like:
A SPARQL query like
produces
In imitation of the the OWL based approach above, I used two properties
pList
andp
, but they could be the same, in which casep
would be "distributed" over the list.With a datastore somewhere, you should be able to do a SPARQL update using
insert/where
:to add the data to the store.
Using a Prolog like syntax
If you want to actually get this reasoning to be performed with a reasoner, you'll be in the domain of reasoner specific stuff. However, lots of reasoners support a Prolog-like query language, and you can write these rules there, too. I don't know AllegoGraph's RDFS++ syntax, but the general structure would include some definitions like: