I've got an ontology with properties whose domains are unions of classes. Given such a property I would like to be able to find those classes that are in the domain, but haven't been able to figure out how to do that.
Here's some sample data:
@prefix : http://example.com/forso/ .
@prefix forso: http://example.com/forso/ .
@prefix owl: http://www.w3.org/2002/07/owl# .
@prefix rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns# .
@prefix xml: http://www.w3.org/XML/1998/namespace .
@prefix xsd: http://www.w3.org/2001/XMLSchema# .
@prefix rdfs: http://www.w3.org/2000/01/rdf-schema# .
@base http://example.com/forso/ .
http://example.com/forso/ rdf:type owl:Ontology .
forso:TypeA rdf:type owl:Class .
forso:TypeB rdf:type owl:Class .
forso:PropertyDomain
rdf:type owl:Class ;
owl:equivalentClass [
rdf:type owl:Class ;
owl:unionOf ( forso:TypeA forso:TypeB )
] .
forso:TheProperty
rdf:type owl:ObjectProperty ;
rdf:type owl:FunctionalProperty , owl:AsymmetricProperty ;
rdfs:domain forso:PropertyDomain .
I can get the domain of forso:TheProperty
with
SELECT ?domain WHERE {
forso:TheProperty rdfs:domain ?domain .
}
from which I get forso:PropertyDomain
. What I want is to then take forso:PropertyDomain
and get forso:TypeA
and forso:TypeB
.
(In my actual use case, I'd like to use anonymous classes without an explicit forso:PropertyDomain
, but if I can't that's ok).
As I understand it, forso:TypeA
and forso:TypeB
should be subclasses of forso:PropertyDomain
, so I was expecting
SELECT * WHERE {
?cls rdfs:subClassOf forso:PropertyDomain .
}
to return forso:TypeA
and forso:TypeB
, but instead it returns nothing. Replacing rdfs:subClassOf
with rdfs:subclassOf*
returns only forso:PropertyDomain
.
EDIT: And of course immediately after posting I figure it out:
SELECT ?cls WHERE {
forso:TheProperty rdfs:domain ?domain .
?domain owl:equivalentClass [
rdf:type owl:Class ;
owl:unionOf [
rdf:rest*/rdf:first ?cls
]
] .
}
But that doesn't seem to work with anonymous classes.
The approach in your edit, which I'd compress a bit as:
SELECT ?cls WHERE {
:property rdfs:domain/owl:equivalentClass/owl:unionOf/rdf:rest\*/rdf:first ?cls
}
seems right for your sample data. When you say
But that doesn't seem to work with anonymous classes.
I'm guessing you mean when you have data like:
:property rdfs:domain [ a owl:Class ; owl:unionOf ( :a : b ) ]
then you'd need to drop the owl:equivalentClass
part of that query. With property paths, you should be able to do something like:
:property rdfs:domain/owl:equivalentClass*/owl:unionOf/rdf:rest*/rdf:first ?cls
I.e., by using owl:equivalentClass*
instead of just owl:equivalentClass
, you can follow zero-or-more owl:equivalentClass
triples, thereby handling the case that the domain is an anonymous node with an owl:unionOf
property.