First, note that using rdf:List
s in your OWL code means that you're going to be in OWL Full, whereas many of the reasoners are designed to work with OWL DL. You might be OK with this, and if you are, then great. If you need to remain in OWL DL, then you'll have to use your own vocabulary for lists, e.g., a class warp:List
and properties warp:first
and warp:rest
, and use those instead of their RDF counterparts.
At any rate, once you've decided on your List
class and your first
and rest
properties, you can define a list type ListOfElements
that can only contain members of some class Element
with the following restriction:
ElementList ⊑ List and (first only Element) and (rest only ElementList)
This means that an ElementList
is: (i) a List
; (ii) has an value for the first
property that is an Element
; and (iii) has an ElementList
as its rest
, which means that the rest of the things in the List
must also be Element
s. Whatever the nil
object is should already be declared as a List
, but you may also want to include:
nil a ElementList
but this isn't necessarily as important. For your case, you'd want to define a class TitleList
in a similar fashion, and then declare the range of your property as TitleList
.
Here's an example ontology that includes just defines these type of List
class and an ElementList
class (in human readable Turtle):
@prefix : <http://stackoverflow.com/a/19480798/1281433/code#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
:rest a owl:ObjectProperty ;
rdfs:domain :List ;
rdfs:range :List .
:List a owl:Class .
:nil a owl:NamedIndividual , :ElementList , :List .
:ElementList a owl:Class ;
rdfs:subClassOf [ a owl:Class ;
owl:intersectionOf ( :List [ a owl:Restriction ;
owl:allValuesFrom :Element ;
owl:onProperty :first
] [ a owl:Restriction ;
owl:allValuesFrom :ElementList ;
owl:onProperty :rest
] )
] .
:Element a owl:Class .
:first a owl:ObjectProperty ;
rdfs:domain :List .
<http://stackoverflow.com/a/19480798/1281433/code>
a owl:Ontology .
[ a owl:Axiom ;
rdfs:comment "It's probably a good idea to specify that nil is an ElementList. This could also be inferred, though, if there is a nil-terminated List that is known to be an ElementList." ;
owl:annotatedProperty rdf:type ;
owl:annotatedSource :nil ;
owl:annotatedTarget :ElementList
] .
For full generality, I've defined new a new List
class, first
and rest
properties, and an individual nil
, but if OWL Full is OK with you, then you can just use rdf:List
, etc. For completeness, here's the same ontology in RDF/XML:
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns="http://stackoverflow.com/a/19480798/1281433/code#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<owl:Ontology rdf:about="http://stackoverflow.com/a/19480798/1281433/code"/>
<owl:Class rdf:about="http://stackoverflow.com/a/19480798/1281433/code#List"/>
<owl:Class rdf:about="http://stackoverflow.com/a/19480798/1281433/code#ElementList">
<rdfs:subClassOf>
<owl:Class>
<owl:intersectionOf rdf:parseType="Collection">
<owl:Class rdf:about="http://stackoverflow.com/a/19480798/1281433/code#List"/>
<owl:Restriction>
<owl:onProperty>
<owl:ObjectProperty rdf:about="http://stackoverflow.com/a/19480798/1281433/code#first"/>
</owl:onProperty>
<owl:allValuesFrom>
<owl:Class rdf:about="http://stackoverflow.com/a/19480798/1281433/code#Element"/>
</owl:allValuesFrom>
</owl:Restriction>
<owl:Restriction>
<owl:onProperty>
<owl:ObjectProperty rdf:about="http://stackoverflow.com/a/19480798/1281433/code#rest"/>
</owl:onProperty>
<owl:allValuesFrom rdf:resource="http://stackoverflow.com/a/19480798/1281433/code#ElementList"/>
</owl:Restriction>
</owl:intersectionOf>
</owl:Class>
</rdfs:subClassOf>
</owl:Class>
<owl:ObjectProperty rdf:about="http://stackoverflow.com/a/19480798/1281433/code#rest">
<rdfs:range rdf:resource="http://stackoverflow.com/a/19480798/1281433/code#List"/>
<rdfs:domain rdf:resource="http://stackoverflow.com/a/19480798/1281433/code#List"/>
</owl:ObjectProperty>
<owl:ObjectProperty rdf:about="http://stackoverflow.com/a/19480798/1281433/code#first">
<rdfs:domain rdf:resource="http://stackoverflow.com/a/19480798/1281433/code#List"/>
</owl:ObjectProperty>
<owl:Axiom>
<rdfs:comment>It's probably a good idea to specify that nil is an ElementList. This could also be inferred, though, if there is a nil-terminated List that is known to be an ElementList.</rdfs:comment>
<owl:annotatedTarget rdf:resource="http://stackoverflow.com/a/19480798/1281433/code#ElementList"/>
<owl:annotatedSource>
<owl:NamedIndividual rdf:about="http://stackoverflow.com/a/19480798/1281433/code#nil">
<rdf:type rdf:resource="http://stackoverflow.com/a/19480798/1281433/code#ElementList"/>
<rdf:type rdf:resource="http://stackoverflow.com/a/19480798/1281433/code#List"/>
</owl:NamedIndividual>
</owl:annotatedSource>
<owl:annotatedProperty rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#type"/>
</owl:Axiom>
</rdf:RDF>