©2001 [Dan Connolly], Frank van Harmelen, [ Ian Horrocks], Deborah L. McGuinness, Lynn Andrea Stein, and Lucent Technologies, Inc.. All Rights Reserved. Distribution policies are governed by the W3C intellectual property terms.
DAML+OIL is a semantic markup language for Web resources. It builds on earlier W3C standards such as RDF and RDF Schema, and extends these languages with richer modelling primitives. The use of DAML+OIL is illustrated here via an annotated example.
This document is a submission to the World Wide Web Consortium from Lucent Technologies (see Submission Request, W3C Staff Comment).
Please send comments to Peter F. Patel-Schneider pfps@research.bell-labs.com, or, preferably, to the publicly archived distribution list, www-rdf-logic@w3.org [archive].
This document is a NOTE made available by the W3C for discussion only. Publication of this Note by W3C indicates no endorsement by W3C or the W3C Team, or any W3C Members. W3C has had no editorial control over the preparation of this Note. This document is a work in progress and may be updated, replaced, or rendered obsolete by other documents at any time.
A list of current W3C technical documents can be found at the Technical Reports page.
This is an annotated walk through an example DAML+OIL (March 2001) ontology, contained in daml+oil-ex.daml and daml+oil-ex-dt.xsd, and replicated in Appendix D and Appendix E. The example ontology demonstrates many of the features in DAML+OIL, but is not intended as a complete description of the language. For this, please refer to the reference document on DAML+OIL.
Superscripted text refers to notes at the end of this document.
DAML+OIL builds on existing Web technologies like Extensible Markup Language[XML] and Uniform Resource Identifiers[URI]. The references and suggested reading section cites introductory materials as well as official specifications for these technologies.
DAML+OIL is written in RDF[RDF], i.e., DAML+OIL markup is a specific kind of RDF markup. RDF, in turn, is written in XML, using XML Namespaces[XMLNS], and URIs. If you are unfamiliar with RDF, the minimalist survival guide to XML and the minimalist survival guide to RDF below may help get you started.
Thus, our example begins with an RDF start tag including several namespace declarations:
<rdf:RDF xmlns:rdf ="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:xsd ="http://www.w3.org/2000/10/XMLSchema#" xmlns:daml="http://www.w3.org/2001/10/daml+oil#" xmlns:dex ="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex#" xmlns:exd ="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#" xmlns ="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex#" >
So in this document, the rdf:
prefix should be understood as
referring to things drawn from the namespace called
http://www.w3.org/1999/02/22-rdf-syntax-ns#
. This is a
conventional RDF declaration appearing verbatim at the beginning of almost
every rdf document.xmlns:rdf
The second and third declarations make similar statements about the RDF Schema and XML Schema datatype namespaces.
The fourth declaration says that in this document, elements prefixed with
daml:
should be understood as referring to things drawn from
the namespace called
http://www.w3.org/2001/10/daml+oil#
.
This again is a conventional DAML+OIL declaration.
The fifth declaration says that in this document, elements prefixed with
dex:
should be understood as referring to things drawn from
the namespace called
http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex#
,
i.e., the location of this document itself.
The sixth declaration says that in this document, elements prefixed with
exd:
should be understood as referring to things drawn from
the namespace called
http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#
,
which is a sibling document to this document itself, containing
XML Schema datatype definitions used in this document.
This is conventional in many DAML+OIL documents, as they will have a
separate document containing XML Schema datatype definitions.
The final declaration states that unprefixed elements
refer to
http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex#
,
i.e., the location of this document itself.
If you look at the bottom of this document, you'll see the matching closing tag, </rdf:RDF>.
The first thing we do inside this RDF document is to assert that this is an ontology.
<daml:Ontology rdf:about="">
This assertion is formulaic; the about attribute will typically be empty, indicating that the subject of this assertion is this document.Same-document reference
Then we give a couple of properties of this ontology for documentation purposes:
<daml:versionInfo>$Id: daml+oil-ex.daml,v 1.8 2001/03/27 21:24:04 horrocks Exp $</daml:versionInfo> <rdfs:comment> An example ontology, with data types taken from XML Schema </rdfs:comment>
followed by
<daml:imports rdf:resource="http://www.w3.org/2001/10/daml+oil"/>
Inside the Ontology element, we list any imported ontologies (using imports properties). This particular ontology depends only on the standard DAML+OIL ontology (used in the namespace definitions above).
Note that this (imports) tag is an empty element; the same tag starts and ends the element, denoted by the trailing "/" just before the closing ">".
</daml:Ontology>
Now, we begin our ontology definitions. In order to describe objects, it is useful to define some basic types. This is done by giving a name for a class, which is the subset of the universe which contains all objects of that type. If we are working in a domain of animals, we will want to define a kind of thing called animal. To do this, we use a Class tag. Class
<daml:Class rdf:ID="Animal">
This asserts that there is a class known as Animal. It doesn't say anything else about animal other than specifying an identifier. It is also not (necessarily) the sole source of information about Animals; we will see below how we can add to a definition made elsewhere.
However, by saying that its ID is Animal, we make it possible for others to
refer to the definition of Animal we're giving here. (This is done using the
uri of the containing page followed by #Animal
.)
<rdfs:label>Animal</rdfs:label> <rdfs:comment> This class of animals is illustrative of a number of ontological idioms. </rdfs:comment>
These two lines introduce a label -- a brief identifier of the enclosing element, suitable for graphical representations of RDF, etc. -- and a comment -- a natural language (English, in this case) description of the element within which it is included. Neither a label nor a comment contributes to the logical interpretation of the language.
</daml:Class>
DAML+OIL divides the world up into objects, which are elements of DAML classes, and datatype values, i.e., values that come from XML Schema datatypes, like the integer 4. Here we are creating an object class. Later we will see examples of datatypes. Datatype values are used to help define classes, but they are not DAML objects and cannot be included in a DAML object class.
There are two types of animals, Male and Female.
<daml:Class rdf:ID="Male"> <rdfs:subClassOf rdf:resource="#Animal"/> </daml:Class>
The subClassOf element asserts that its subject -- Male -- is a subclass of its object -- the resource identified by #Animal.
<daml:Class rdf:ID="Female"> <rdfs:subClassOf rdf:resource="#Animal"/> <daml:disjointWith rdf:resource="#Male"/> </daml:Class>
Some animals are Female, too, but nothing can be both Male and Female (in this ontology) because these two classes are disjoint (using the disjointWith tag)
It perfectly admissible for a class to have multiple superclasses: A Man is a Male Person
<daml:Class rdf:ID="Man"> <rdfs:subClassOf rdf:resource="#Person"/> <rdfs:subClassOf rdf:resource="#Male"/> </daml:Class>
...and a Woman is a Female Person.
<daml:Class rdf:ID="Woman"> <rdfs:subClassOf rdf:resource="#Person"/> <rdfs:subClassOf rdf:resource="#Female"/> </daml:Class>
Note that person has not yet been introduced (it is defined later in the document). This is perfectly fine in DAML+OIL. Information about any class can be given at any time.
As always in DAML+OIL, conjoining statements without an explicit connective means that the statements must be read conjunctively, in this case: Woman is a subclass of Person and is a subclass of Female.
Next, we define a property. A property -- or binary relation -- connects
two items.
As with classes, DAML+OIL properties are generally divided into two
sorts -- those that relate objects to other objects and
those that relate objects to datatype values. The former belong
to daml:ObjectProperty
and the latter belong to
daml:DatatypeProperty
.
It is possible to use properties that are not sorted this way, but very
little can be done with such properties.
In this case, we're defining the hasParent relation which will be used to connect two animals.
<daml:ObjectProperty rdf:ID="hasParent">
The property definition begins by stating that there is a property called hasParent. Note, however, that this is not a closing tag; there's more to this definition. (There is a matching </daml:ObjectPropety> tag below.)
<rdfs:domain rdf:resource="#Animal"/>
Like all embedded elements, this is understood to describe its enclosing element. So, this element describes the Property whose ID is hasParent. It says that the domain of the hasParent relation is Animal. That is, we're defining hasParent as a property that applies to animals.
<rdfs:range rdf:resource="#Animal"/>
Similar to the domain, we also declare the range of the hasParent relation to be Animal. That is, we're defining hasParent as a property whose value can only be animals.
It is allowed in DAML+OIL to state multiple ranges. Again, such multiple statements must be read conjunctively: the values of the property must satisfy all the range statements (and similarly for multiple domain statements). Note that in this aspect, DAML+OIL departs from the RDF Schema semantics for domain and range. See the reference document for more details. We do this by asserting that there's a thing which is a domain -- the things to which this property applies, ie. the things that can have parents -- and saying that this domain is the resource known as #Animal. What is the resource attribute? It is a reference to something. Note that the ID attributes that we created for each entry until now serve as reference-able descriptions; resource refers to such descriptions. In this case, it refers to names in this document, since its reference begins with a #.
Domains and ranges are global information about properties. As such, they should be used with care. Putting a too-restrictive domain or range on a property can cause all sorts of trouble. (Note the comment below which points out that there is an alternative for domain and range restrictions.)
</daml:ObjectProperty>
That's all we have to say about this Property (whose ID = hasParent).
Next, we state that hasFather is a property that is a kind of hasParent property, i.e., x's father is also x's parent. In addition, range is used to ensure that x's father must be a Male.
<daml:ObjectProperty rdf:ID="hasFather"> <rdfs:subPropertyOf rdf:resource="#hasParent"/> <rdfs:range rdf:resource="#Male"/> </daml:ObjectProperty>
Properties that relate object properties to datatype values are members
of DatatypeProperty
. For example, we might want to provide a
shoesize property, which is provides at most a single shoe size, which is a
decimal number. We reference the XML Schema datatype
decimal by referring to its standard location.
<daml:DatatypeProperty rdf:ID="shoesize"> <rdfs:comment> shoesize is a DatatypeProperty whose range is xsd:decimal. shoesize is also a UniqueProperty (can only have one shoesize) </rdfs:comment> <rdf:type rdf:resource="http://www.w3.org/2001/10/daml+oil#UniqueProperty"/> <rdfs:range rdf:resource="http://www.w3.org/2000/10/XMLSchema#decimal"/> </daml:DatatypeProperty>
Similarly we create an age property, which maps into XML Schema non-negative integers.
<daml:DatatypeProperty rdf:ID="age"> <rdfs:comment> age is a DatatypeProperty whose range is xsd:decimal. age is also a UniqueProperty (can only have one age) </rdfs:comment> <rdf:type rdf:resource="http://www.w3.org/2001/10/daml+oil#UniqueProperty"/> <rdfs:range rdf:resource="http://www.w3.org/2000/10/XMLSchema#nonNegativeInteger"/> </daml:DatatypeProperty>
Now we'll define a Class with some internal structure.
<daml:Class rdf:ID="Person">
This element describes a kind of thing called a Person, and is referenceable as such.
<rdfs:subClassOf rdf:resource="#Animal"/>
A Person is a kind of Animal (referring to the definition of Animal above).
The next few lines describe a class-specific range restriction. In particular, the parent of a Person is also a Person.
<rdfs:subClassOf> <daml:Restriction> <daml:onProperty rdf:resource="#hasParent"/> <daml:toClass rdf:resource="#Person"/> </daml:Restriction> </rdfs:subClassOf>
What happens here is that the Restriction defines an anonymous class, namely the class of all things that satisfy the restriction. In this case: the class of all things whose parent is a Person. We then demand that the class Person is a subClassOf this (anonymous) class. In other words: we demand that every Person must satisfy this Restriction, which in this case amounts to demanding that Persons have only Persons as their parents.
The syntax used here is a cliche, i.e., it is always used as shown, except for (i) the name of the resource in the OnProperty element, which will give the name of the Property to be restricted, and (ii) the resource associated with the toClass element, which will give the name of the Class to which the Property is restricted.
Note: When restricting the range of a property, as we are doing here, there is an important difference between using a toClass restriction and using rdfs:range (as we did for the hasFather property). An rdfs:range element has a global scope: any use of the hasFather property for any class must always yield a male. A toClass restriction (as used in the Person class) on the other hand has a local scope: the parent of a person must be person, but the parent of any other class (e.g. the parent of an elephant) need not be a person.
Note: In general, stating toClass restrictions locally to a class will result in ontologies that are more extendable (and therefore more reusable) then those using rdfs:range and rdfs:domain. The latter two make global assertions that must be obeyed by anyone who will ever want to use the property concerned, applied to any class whatsoever. Because of this, using local Restriction elements is considered much better DAML+OIL style than using global rdfs:domain and rdfs:range.
The class Person comes with two other examples of restrictions :
<rdfs:subClassOf> <daml:Restriction daml:cardinality="1"> <daml:onProperty rdf:resource="#hasFather"/> </daml:Restriction> </rdfs:subClassOf> <rdfs:subClassOf> <daml:Restriction> <daml:onProperty rdf:resource="#shoesize"/> <daml:minCardinality>1</daml:minCardinality> </daml:Restriction> </rdfs:subClassOf>
This requires that any person must have exactly 1 father and at least one shoe size. Again, this is done by first using a Restriction to define an anonymous class (in this case the class of all things that have exactly one father), and then demanding that Person is a subClassOf this anonymous class (i.e., demanding that every Person satisfies this Restriction).
The two restrictions above have slightly different layouts, but they both result in similar RDF. Either layout can be used at will.Alternative syntax.
Again, the above restrictions have only local scope: the above only enforces that a Person has exactly 1 father. This still leaves open the (unlikely) possibility that other classes have more or fewer than one father.
Besides toClass and cardinality, other restrictions are possible. These are all discussed in the reference document on DAML+OIL.
</daml:Class>
That's the end of the Person class.
A key feature of any web-based ontology language is that statements about entities such as classes and properties can be distributed among different locations. For example, if we wanted to add to the Animal class (defined above) that all animals have exactly 2 parents, we need not modify the above statement, but we can simply add the following, referring to the statement with its ID:
<daml:Class rdf:about="#Animal"> <rdfs:comment> Animals have exactly two parents, ie: If x is an animal, then it has exactly 2 parents (but it is NOT the case that anything that has 2 parents is an animal). </rdfs:comment> <rdfs:subClassOf> <daml:Restriction daml:cardinality="2"> <daml:onProperty rdf:resource="#hasParent"/> </daml:Restriction> </rdfs:subClassOf> </daml:Class>
Such an assertion "about" the class Animals has exactly the same logical status as the assertions made within the <daml:Class rdf:ID="Animal"> element about vs. ID.
Note that if this statement had lived in another file, we should have
referred to the class Animal with a fully qualified URL:
rdf:about="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex.daml#Animal"
The cardinality property specifies a precise cardinality. But sometimes we want to bound the cardinality without precisely specifiying it. A person may have zero or one spouse, but no more:
<daml:Class rdf:about="#Person"> <rdfs:subClassOf> <daml:Restriction daml:maxCardinality="1"> <daml:onProperty rdf:resource="#hasSpouse"/> </daml:Restriction> </rdfs:subClassOf> </daml:Class>
Of course, a minimal value for the cardinality of a property can be expressed in a similar way.
If no minimum cardinality is specified, a minimum cardinality of 0 is
assumed. Thus, <Restriction daml:minCardinality="0">
would not need to
be asserted.
A more sophisticated version of a cardinality constraint on a property not only specifies a maximum, minimum or precise number of values for that property, but also enforces the type that these property values must have:
<daml:Class rdf:about="#Person"> <rdfs:subClassOf> <daml:Restriction daml:maxCardinalityQ="1"> <daml:onProperty rdf:resource="#hasOccupation"/> <daml:hasClassQ rdf:resource="#FullTimeOccupation"/> </daml:Restriction> </rdfs:subClassOf> </daml:Class>
This states that a Person may have at most one occupation that is a FullTimeOccupation. (This still allows for the possibility that they may have multiple jobs of other types than FullTimeOccupation).
Of course, such qualified cardinality constraints can be stated as well for minimal cardinalities and exact cardinalities.
The next several annotations illustrate various notations for properties:
HasMother is defined similarly to hasFather, but using a variant notation. A UniqueProperty is one with cardinality 1, so we can omit the cardinality sub-element from HasMother's definition.
<daml:UniqueProperty rdf:ID="hasMother"> <rdfs:subPropertyOf rdf:resource="#hasParent"/> <rdfs:range rdf:resource="#Female"/> </daml:UniqueProperty>
Since a UniqueProperty has cardinality 1, each subject uniquely identifies the object (value) of the property (ie. the identity of a person determines their mother). Conversely, an UnambiguousProperty is a property whose object uniquely identifies its subject. (The inverse of any UniqueProperty is always an UnambiguousProperty).
Notice that UniqueProperty and UnambiguousProperty specify global cardinality restrictions. That is, no matter what class the property is applied to, the cardinality constraints must hold, unlike the cardinality restrictions illustrated above, which are part of a class element, and are only enforced on the property when applied to that class.
If x's parent is y, then y is x's child. This is defined using the inverseOf tag.
<daml:ObjectProperty rdf:ID="hasChild"> <daml:inverseOf rdf:resource="#hasParent"/> </daml:ObjectProperty>
The hasAncestor and descendent properties are transitive versions of the hasParent and hasChild properties.
<daml:TransitiveProperty rdf:ID="hasAncestor"> <rdfs:label>hasAncestor</rdfs:label> </daml:TransitiveProperty> <daml:TransitiveProperty rdf:ID="descendant"/>
Note that this only states that hasAncestor is transitive, but not yet that hasAncestor is the transitive version of hasParent (and ditto for hasDescendant and hasChild). DAML+OIL would need additional language constructs to enforce these connections.
Sometimes, we like to refer to mothers using the synonym mom. The tag samePropertyAs allows us to establish this synonymy:
<daml:ObjectProperty rdf:ID="hasMom"> <daml:samePropertyAs rdf:resource="#hasMother"/> </daml:ObjectProperty>
Classes, too, can be written in various ways:
<daml:Class rdf:ID="Car"> <rdfs:comment>no car is a person</rdfs:comment>
We want to state that cars can never be persons, in other words: cars are a subclass of non-persons. The thing that Car is a subClassOf (ie non-persons) could in principle be specified using a resource= attribute. In this case, however, there is no pre-existing succinct name for the thing we want (the class of non-persons). We build this by introducing a new -- anonymous -- Class definition described using the complementOf tag:
<rdfs:subClassOf> <daml:Class> <daml:complementOf rdf:resource="#Person"/> </daml:Class> </rdfs:subClassOf>
In other words: Car is a Class that is a specialization of another (anonymous) Class, namely the Class consisting of all things except Persons.
</daml:Class>
... and this finishes the definition of the class Car.
In effect, the above makes the class Car disjoint from the class Person (since Car is declared to be a subClass of the complementOf Person). Because such disjointness statements among classes occur very frequently, DAML+OIL has a specific vocabulary for this special case. The same fact could have been stated using the disjointWith tag that we already saw above in the definition of Female.
Besides stating that classes are disjoint, we can also identify a Class with the disjoint union of a set of other classes. In this case, we identify the Class Person with the disjoint union of the Classes Man and Woman.
<daml:Class rdf:about="#Person"> <rdfs:comment>every person is a man or a woman</rdfs:comment> <daml:disjointUnionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#Man"/> <daml:Class rdf:about="#Woman"/> </daml:disjointUnionOf> </daml:Class>
This is also another example of further specifying a previously defined element by using the about attribute. Note that the disjointUnionOf element contains multiple subelements. The parseType="daml:collection" indicates that these subelements are to be treated as a unit (namely as a single collection) RDF extension.
We have already seen that we can construct a new class by taking the complementOf another class. In the same way, we can construct classes out of the intersection of other classes:
<daml:Class rdf:ID="TallMan"> <daml:intersectionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#TallThing"/> <daml:Class rdf:about="#Man"/> </daml:intersectionOf> </daml:Class>
This states that the class TallMan is exactly equal to the intersection of Man and TallThing. (See below for the definition of the class TallThing). Note that we can take the intersectionOf an arbitrary number of classes (parseType="daml:collection").
Similarly, we can construct a class as the unionOf a set of classes.
As already indicated, the intersectionOf construction makes the named class exactly equal to the result of the intersection. This construction is frequently used as an idiom if we want to state not only necessary but also sufficient conditions for a class. For example, a MarriedPerson is a Person with a spouse, but also vice versa: any Person with a spouse is a MarriedPerson. Such necessary and sufficient conditions can be enforced using intersectionOf:
<daml:Class rdf:ID="MarriedPerson"> <daml:intersectionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#Person"/> <daml:Restriction daml:cardinality="1"> <daml:onProperty rdf:resource="#hasSpouse"/> </daml:Restriction> </daml:intersectionOf> </daml:Class>
Note the use of the cardinality Restriction to specify an anonymous class. This anonymous class (the class of all things that have exactly one spouse) is intersected with the Person class to yield exactly all Persons that have one spouse.
Just as for properties, a mechanism exists for declaring synonyms for classes:
<daml:Class rdf:ID="HumanBeing"> <daml:sameClassAs rdf:resource="#Person"/> </daml:Class>
It is also possible to use user-defined datatypes in DAML+OIL. Suppose
we wanted to distinguish between different classes of people by their ages.
We would create several XML Schema datatype definitions in a separate
file, such as
http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt.xsd
,
which contains
<!-- $Revision: 1.2 $ of $Date: 2001/03/18 22:44:50 $. --> <xsd:schema xmlns:xsd ="http://www.w3.org/2000/10/XMLSchema#"> <xsd:simpleType name="over12"> <!-- over12 is an XMLS datatype based on decimal --> <!-- with the added restriction that values must be >= 13 --> <xsd:restriction base="xsd:decimal"> <xsd:minInclusive value="13"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="over17"> <!-- over17 is an XMLS datatype based on positiveIntege --> <!-- with the added restriction that values must be >= 18 --> <xsd:restriction base="xsd:positiveInteger"> <xsd:minInclusive value="18"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="over59"> <!-- over59 is an XMLS datatype based on positiveIntege --> <!-- with the added restriction that values must be >= 59 --> <xsd:restriction base="xsd:positiveInteger"> <xsd:minInclusive value="60"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="clothingsize"> <!-- clothingsize is an XMLS union datatype --> <!-- values of clothingsize may be either integers or strings --> <xsd:union> <xsd:simpleType> <xsd:restriction base='integer'/> </xsd:simpleType> <xsd:simpleType> <xsd:restriction base='string'/> </xsd:simpleType> </xsd:union> </xsd:simpleType> <xsd:simpleType name="XSDEnumerationHeight"> <!-- This is an XMLS datatype valid values for which are the strings --> <!-- "short", "medium" and "tall". --> <xsd:restriction base="string"> <xsd:enumeration value="short"/> <xsd:enumeration value="medium"/> <xsd:enumeration value="tall"/> </xsd:restriction> </xsd:simpleType> </xsd:schema>
Then we could reference elements of this file in DAML+OIL restrictions, as in
<daml:Class rdf:ID="Adult"> <daml:intersectionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#Person"/> <daml:Restriction> <daml:onProperty rdf:resource="#age"/> <daml:hasClass rdf:resource="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#over17"/> </daml:Restriction> </daml:intersectionOf> </daml:Class> <daml:Class rdf:ID="Senior"> <daml:intersectionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#Person"/> <daml:Restriction> <daml:onProperty rdf:resource="#age"/> <daml:hasClass rdf:resource="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#over59"/> </daml:Restriction> </daml:intersectionOf> </daml:Class>
We can also define individual objects in a class, e.g., Adam, a person of age 13 and shoesize 9.5:
<Person rdf:ID="Adam"> <rdfs:label>Adam</rdfs:label> <rdfs:comment>Adam is a person.</rdfs:comment> <age><xsd:integer rdf:value="13"/></age> <shoesize><xsd:decimal rdf:value="9.5"/></shoesize> </Person>
Note that we provided an XML Schema datatype along with a lexical representation of the value. This datatype is used to parse the lexical representation into an actual value. It is possible, but not recommended, to provide the lexical representation without the datatype.
A Person has a property called hasHeight, which is a Height. (hasHeight is a Property, or relation; Height is a Class, or kind of thing.)
<daml:ObjectProperty rdf:ID="hasHeight"> <rdfs:range rdf:resource="#Height"/> </daml:ObjectProperty>
Height is a Class described by an explicitly enumerated set. We can describe this set using the oneOf element. Like disjointUnionOf, oneOf uses the RDF-extending parsetype="daml:collection". RDF extension
<daml:Class rdf:ID="Height"> <daml:oneOf rdf:parseType="daml:collection"> <Height rdf:ID="short"/> <Height rdf:ID="medium"/> <Height rdf:ID="tall"/> </daml:oneOf> </daml:Class>
Finally, TallThing is exactly the class of things whose hasHeight has the value tall:
<daml:Class rdf:ID="TallThing"> <daml:sameClassAs> <daml:Restriction> <daml:onProperty rdf:resource="#hasHeight"/> <daml:hasValue rdf:resource="#tall"/> </daml:Restriction> </daml:sameClassAs> </daml:Class>
From the inside out, this says first that TallThings must have the value tall as value for their hasHeight property, i.e., having the value tall as your height is a necessary condition for being a TallThing. Secondly, we say that TallThing is exactly the same class as the the class of all such objects (i.e., all objects having tall as their value for hasHeight), in other words: besides being necessary, this condition is also sufficient for being a TallThing.
Consider what would have happened if we had used subClassOf instead of sameClassAs. This would have resulted in a necessary but not sufficient condition for the definition of the class TallThing. Thus, a necessary-only and a necessary-and-sufficient class definition now only differ simply in their outermost element: either a subClassOf or a sameClassAs as element, respectively.
To illustrate the various methods of providing datatype values in DAML+OIL,
we create two datatype properties, one (shirtsize) whose range is a union
datatype that we constructed in our datatype file
http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt.xsd
and one (associatedData) without a range.
We also create the class of people with shoesize over 12 and say that
people can have at most one piece of associated data.
<daml:DatatypeProperty rdf:ID="shirtsize"> <rdfs:comment> shirtsize is a DatatypeProperty whose range is clothingsize. </rdfs:comment> <rdf:type rdf:resource="http://www.w3.org/2001/10/daml+oil#UniqueProperty"/> <rdfs:range rdf:resource="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#clothingsize"/> </daml:DatatypeProperty> <daml:DatatypeProperty rdf:ID="associatedData"> <rdfs:comment> associatedData is a DatatypeProperty without a range restriction. </rdfs:comment> </daml:DatatypeProperty> <rdfs:Class rdf:ID="BigFoot"> <rdfs:comment> BigFoots (BigFeet?) are exactly those persons whose shosize is over12. </rdfs:comment> <daml:intersectionOf rdf:parseType="daml:collection"> <rdfs:Class rdf:about="#Person"/> <daml:Restriction> <daml:onProperty rdf:resource="#shoesize"/> <daml:hasClass rdf:resource="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#over12"/> </daml:Restriction> </daml:intersectionOf> </rdfs:Class> <daml:Class rdf:about="#Person"> <rdfs:comment> Persons have at most 1 item of associatedData </rdfs:comment> <rdfs:subClassOf> <daml:Restriction> <daml:onProperty rdf:resource="#associatedData"/> <daml:maxCardinality>1</daml:maxCardinality> </daml:Restriction> </rdfs:subClassOf> </daml:Class>
Now we can (try to) create several individuals.
<Person rdf:ID="Ian"> <shoesize>14</shoesize> <age>37</age> <shirtsize><xsd:string rdf:value="12"/></shirtsize> </Person> <Person rdf:ID="Peter"> <shoesize>9.5</shoesize> <age>46</age> <shirtsize>15</shirtsize> </Person> <Person rdf:ID="Santa"> <associatedData><xsd:float rdf:value="3.14159"/></associatedData> <associatedData><xsd:string rdf:value="3.14159"/></associatedData> </Person>
Ian is an instance of Person. Ian has shoesize 14 and age 37. From the range restrictions we know that these are of type xsd:decimal and xsd:nonNegativeInteger respectively. Ian also has shirtsize 12, the type of which is the union type clothingsize; the discriminating type "string" has been specified, so the value is to be taken as the string "12" rather than the integer 12. We may be able to infer that Ian is an instance of BigFoot (because 14 is a valid value for xsd:over12).
Peter is an instance of Person. Peter has shoesize 9.5 and age 46. From the range restrictions we know that these are of type xsd:decimal and xsd:nonNegativeInteger respectively. Peter also has shirtsize 15, the type of which is the union type clothingsize; no discriminating type has been specified, so the value may be either a string or an integer.
Santa is an instance of Person. Santa has two pieces of associatedData, one of which is the real number 3.14159 and the other of which is the string "3.14159". We may be able to infer a logical inconsistency (because Persons can have at most 1 item of associatedData, and a value cannot be both a string and a real number).
Finally, we end our specfication with the rdf:RDF element.
</rdf:RDF>
This appendix is intended for those unfamiliar with RDF. It contains only enough information to enable you to read the annotated DAML+OIL markup example, and is not intended as a complete introduction to RDF, XML, or any other of the technologies on which DAML+OIL is based. See the suggested readings below for more information.
RDF is built on XML, which makes use of tags to structure information. Here are some example tags:
<aTag>...</aTag> <anEmptyTag/> <anotherTag with="an attribute">...</anotherTag> <aTag>with <anemptyTag/> inside it</aTag> <tags>and<moreTags>and<yetmoreTags>and...</yetmoreTags></moreTags></tags>
The first thing after the open angle bracket is the tag name. The whole tag is often referred to by this name. So
<Class ID="Animal">
is a Class tag.
A tag ends with a closing angle bracket.
Some tags are start tags, and have matching end tags. The end tag has the same tag name as the opening tag, but begins with </ rather than simply <. For example,
<Class ID="Animal">
would be closed by the matching end tag
</Class>
From an opening tag to its matching closing tag is an element. Other tags can be embedded inside the element, but all such embedded elements must be closed inside the enclosing element. So <rdf:RDF> would begin an element that runs until an </rdf:RDF>. In this case, anything between the <rdf:RDF> and the matching </rdf:RDF> would be enclosed in the scope of this element.
An alternate way to specify an element that has nothing between its opening and its closing tag is to use a single tag with a slash immediately before the closing angle-bracket. Thus, the self-closing tag
<Class ID="Animal"/>
is the same as
<Class ID="Animal"></Class>
with nothing inside it.
An opening tag (or a self-closing tag) may contain things other than the tag name. These things after the tag name are attributes. Each attribute has a name, an equal sign, and an attribute value (generally enclosed in double quotes). So, for example, in the Class tag above,
ID="Animal"
is the attribute,
ID
is the attribute name, and
"Animal"
is the attribute value. Attributes are read as properties of the element in which they appear.
An RDF document is a collection of assertions in subject verb object (SVO) form. Within the obligatory RDF declaration (typically a tag that begins something like <rdf:RDF ...), each topmost element is the subject of a sentence. The next level of enclosed elements represent verb/object pairs for this sentence:
<Class ID="Male"> <subClassOf resource="#Animal"/> </Class>
Male is a subclass of Animal.
<Class ID="Female"> <subClassOf resource="#Animal"/> <disjointWith resource="#Male"/> </Class>
Female is a subclass of Animal AND Female is disjoint from Male. The single subject -- Female -- is used to begin each of the verb-object assertions
<subClassOf resource="#Animal"/>
and
<disjointWith resource="#Male"/>
A few attributes here require explanation.
ID creates a referenceable name, corresponding to the attribute value. So, for example, ID="Male" means that you can refer to Male and mean the thing described by the Class element above. Similarly, Female is a referenceable name.
The resource attribute, then, is simply a reference to such a name. In
<disjointWith resource="#Male"/>
the resource attribute is used to indicate that the object of the assertion "Female is disjoint from" is the thing identified with the name Male. Note the prepended # to refer to the name. This indicates a reference to a name within the same containing document, i.e., a local name. It is also possible (e.g., by prepending a url before the #) to refer to a name defined elsewhere.
In the above example, each verb tag is self-closing. It is also possible to embed elements inside these verb elements, making objects which are themselves the subjects of subordinate clauses. This causes an alternation of subject verb subject verb ... sometimes called RDF striped syntax.
about=
" or "ID=
" results in exactly the
same set of RDF triples, and perforce the DAML+OIL meaning of these
different notations is the same. <!-- $Revision: 1.10 $ of $Date: 2001/12/18 21:48:05 $ --> <rdf:RDF xmlns:rdf ="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:daml="http://www.w3.org/2001/10/daml+oil#" xmlns:xsd ="http://www.w3.org/2000/10/XMLSchema#" xmlns:dex ="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex#" xmlns:exd ="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#" xmlns ="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex#" > <daml:Ontology rdf:about=""> <daml:versionInfo>$Id: Overview.html,v 1.10 2001/12/18 21:48:05 connolly Exp $</daml:versionInfo> <rdfs:comment> An example ontology, with data types taken from XML Schema </rdfs:comment> <daml:imports rdf:resource="http://www.w3.org/2001/10/daml+oil"/> </daml:Ontology> <daml:Class rdf:ID="Animal"> <rdfs:label>Animal</rdfs:label> <rdfs:comment> This class of animals is illustrative of a number of ontological idioms. </rdfs:comment> </daml:Class> <daml:Class rdf:ID="Male"> <rdfs:subClassOf rdf:resource="#Animal"/> </daml:Class> <daml:Class rdf:ID="Female"> <rdfs:subClassOf rdf:resource="#Animal"/> <daml:disjointWith rdf:resource="#Male"/> </daml:Class> <daml:Class rdf:ID="Man"> <rdfs:subClassOf rdf:resource="#Person"/> <rdfs:subClassOf rdf:resource="#Male"/> </daml:Class> <daml:Class rdf:ID="Woman"> <rdfs:subClassOf rdf:resource="#Person"/> <rdfs:subClassOf rdf:resource="#Female"/> </daml:Class> <daml:ObjectProperty rdf:ID="hasParent"> <rdfs:domain rdf:resource="#Animal"/> <rdfs:range rdf:resource="#Animal"/> </daml:ObjectProperty> <daml:ObjectProperty rdf:ID="hasFather"> <rdfs:subPropertyOf rdf:resource="#hasParent"/> <rdfs:range rdf:resource="#Male"/> </daml:ObjectProperty> <daml:DatatypeProperty rdf:ID="shoesize"> <rdfs:comment> shoesize is a DatatypeProperty whose range is xsd:decimal. shoesize is also a UniqueProperty (can only have one shoesize) </rdfs:comment> <rdf:type rdf:resource="http://www.w3.org/2001/10/daml+oil#UniqueProperty"/> <rdfs:range rdf:resource="http://www.w3.org/2000/10/XMLSchema#decimal"/> </daml:DatatypeProperty> <daml:DatatypeProperty rdf:ID="age"> <rdfs:comment> age is a DatatypeProperty whose range is xsd:decimal. age is also a UniqueProperty (can only have one age) </rdfs:comment> <rdf:type rdf:resource="http://www.w3.org/2001/10/daml+oil#UniqueProperty"/> <rdfs:range rdf:resource="http://www.w3.org/2000/10/XMLSchema#nonNegativeInteger"/> </daml:DatatypeProperty> <daml:Class rdf:ID="Person"> <rdfs:subClassOf rdf:resource="#Animal"/> <rdfs:subClassOf> <daml:Restriction> <daml:onProperty rdf:resource="#hasParent"/> <daml:toClass rdf:resource="#Person"/> </daml:Restriction> </rdfs:subClassOf> <rdfs:subClassOf> <daml:Restriction daml:cardinality="1"> <daml:onProperty rdf:resource="#hasFather"/> </daml:Restriction> </rdfs:subClassOf> <rdfs:subClassOf> <daml:Restriction> <daml:onProperty rdf:resource="#shoesize"/> <daml:minCardinality>1</daml:minCardinality> </daml:Restriction> </rdfs:subClassOf> </daml:Class> <daml:Class rdf:about="#Animal"> <rdfs:comment> Animals have exactly two parents, ie: If x is an animal, then it has exactly 2 parents (but it is NOT the case that anything that has 2 parents is an animal). </rdfs:comment> <rdfs:subClassOf> <daml:Restriction daml:cardinality="2"> <daml:onProperty rdf:resource="#hasParent"/> </daml:Restriction> </rdfs:subClassOf> </daml:Class> <daml:Class rdf:about="#Person"> <rdfs:subClassOf> <daml:Restriction daml:maxCardinality="1"> <daml:onProperty rdf:resource="#hasSpouse"/> </daml:Restriction> </rdfs:subClassOf> </daml:Class> <daml:Class rdf:about="#Person"> <rdfs:subClassOf> <daml:Restriction daml:maxCardinalityQ="1"> <daml:onProperty rdf:resource="#hasOccupation"/> <daml:hasClassQ rdf:resource="#FullTimeOccupation"/> </daml:Restriction> </rdfs:subClassOf> </daml:Class> <daml:UniqueProperty rdf:ID="hasMother"> <rdfs:subPropertyOf rdf:resource="#hasParent"/> <rdfs:range rdf:resource="#Female"/> </daml:UniqueProperty> <daml:ObjectProperty rdf:ID="hasChild"> <daml:inverseOf rdf:resource="#hasParent"/> </daml:ObjectProperty> <daml:TransitiveProperty rdf:ID="hasAncestor"> <rdfs:label>hasAncestor</rdfs:label> </daml:TransitiveProperty> <daml:TransitiveProperty rdf:ID="descendant"/> <daml:ObjectProperty rdf:ID="hasMom"> <daml:samePropertyAs rdf:resource="#hasMother"/> </daml:ObjectProperty> <daml:Class rdf:ID="Car"> <rdfs:comment>no car is a person</rdfs:comment> <rdfs:subClassOf> <daml:Class> <daml:complementOf rdf:resource="#Person"/> </daml:Class> </rdfs:subClassOf> </daml:Class> <!-- @@CAVEAT: daml:collection is an extension of RDF 1.0 syntax; don't expect existing tools to support it. See http://www.w3.org/TR/daml+oil-reference#collection for details. --> <daml:Class rdf:about="#Person"> <rdfs:comment>every person is a man or a woman</rdfs:comment> <daml:disjointUnionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#Man"/> <daml:Class rdf:about="#Woman"/> </daml:disjointUnionOf> </daml:Class> <daml:Class rdf:ID="TallMan"> <daml:intersectionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#TallThing"/> <daml:Class rdf:about="#Man"/> </daml:intersectionOf> </daml:Class> <daml:Class rdf:ID="MarriedPerson"> <daml:intersectionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#Person"/> <daml:Restriction daml:cardinality="1"> <daml:onProperty rdf:resource="#hasSpouse"/> </daml:Restriction> </daml:intersectionOf> </daml:Class> <daml:Class rdf:ID="HumanBeing"> <daml:sameClassAs rdf:resource="#Person"/> </daml:Class> <daml:Class rdf:ID="Adult"> <daml:intersectionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#Person"/> <daml:Restriction> <daml:onProperty rdf:resource="#age"/> <daml:hasClass rdf:resource="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#over17"/> </daml:Restriction> </daml:intersectionOf> </daml:Class> <daml:Class rdf:ID="Senior"> <daml:intersectionOf rdf:parseType="daml:collection"> <daml:Class rdf:about="#Person"/> <daml:Restriction> <daml:onProperty rdf:resource="#age"/> <daml:hasClass rdf:resource="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#over59"/> </daml:Restriction> </daml:intersectionOf> </daml:Class> <Person rdf:ID="Adam"> <rdfs:label>Adam</rdfs:label> <rdfs:comment>Adam is a person.</rdfs:comment> <age><xsd:integer rdf:value="13"/></age> <shoesize><xsd:decimal rdf:value="9.5"/></shoesize> </Person> <daml:ObjectProperty rdf:ID="hasHeight"> <rdfs:range rdf:resource="#Height"/> </daml:ObjectProperty> <daml:Class rdf:ID="Height"> <daml:oneOf rdf:parseType="daml:collection"> <Height rdf:ID="short"/> <Height rdf:ID="medium"/> <Height rdf:ID="tall"/> </daml:oneOf> </daml:Class> <!-- TallThing is EXACTLY the class of things whose hasHeight is tall --> <daml:Class rdf:ID="TallThing"> <daml:sameClassAs> <daml:Restriction> <daml:onProperty rdf:resource="#hasHeight"/> <daml:hasValue rdf:resource="#tall"/> </daml:Restriction> </daml:sameClassAs> </daml:Class> <daml:DatatypeProperty rdf:ID="shirtsize"> <rdfs:comment> shirtsize is a DatatypeProperty whose range is clothingsize. </rdfs:comment> <rdf:type rdf:resource="http://www.w3.org/2001/10/daml+oil#UniqueProperty"/> <rdfs:range rdf:resource="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#clothingsize"/> </daml:DatatypeProperty> <rdfs:Class rdf:ID="BigFoot"> <rdfs:comment> BigFoots (BigFeet?) are exactly those persons whose shosize is over12. </rdfs:comment> <daml:intersectionOf rdf:parseType="daml:collection"> <rdfs:Class rdf:about="#Person"/> <daml:Restriction> <daml:onProperty rdf:resource="#shoesize"/> <daml:hasClass rdf:resource="http://www.w3.org/TR/2001/NOTE-daml+oil-walkthru-20011218/daml+oil-ex-dt#over12"/> </daml:Restriction> </daml:intersectionOf> </rdfs:Class> <Person rdf:ID="Ian"> <rdfs:comment> Ian is an instance of Person. Ian has shoesize 14 and age 37. From the range restrictions we know that these are of type xsd:decimal and xsd:nonNegativeInteger respectively. Ian also has shirtsize 12, the type of which is the union type clothingsize; the discriminating type "string" has been specified, so the value is to be taken as the string "12" rather than the integer 12. We may be able to infer that Ian is an instance of BigFoot (because 14 is a valid value for xsd:over12). </rdfs:comment> <shoesize>14</shoesize> <age>37</age> <shirtsize><xsd:string rdf:value="12"/></shirtsize> </Person> <Person rdf:ID="Peter"> <rdfs:comment> Peter is an instance of Person. Peter has shoesize 9.5 and age 46. From the range restrictions we know that these are of type xsd:decimal and xsd:nonNegativeInteger respectively. Peter also has shirtsize 15, the type of which is the union type clothingsize; no discriminating type has been specified, so the value may be either a string or an integer. </rdfs:comment> <shoesize>9.5</shoesize> <age>46</age> <shirtsize>15</shirtsize> </Person> <daml:DatatypeProperty rdf:ID="associatedData"> <rdfs:comment> associatedData is a DatatypeProperty without a range restriction. </rdfs:comment> </daml:DatatypeProperty> <daml:Class rdf:about="#Person"> <rdfs:comment> Persons have at most 1 item of associatedData </rdfs:comment> <rdfs:subClassOf> <daml:Restriction> <daml:onProperty rdf:resource="#associatedData"/> <daml:maxCardinality>1</daml:maxCardinality> </daml:Restriction> </rdfs:subClassOf> </daml:Class> <Person rdf:ID="Santa"> <rdfs:comment> Santa is an instance of Person. Santa has two pieces of associatedData, one of which is the real number 3.14159 and the other of which is the string "3.14159". We may be able to infer a logical inconsistency (because Persons can have at most 1 item of associatedData, and a value cannot be both a string and a real number). </rdfs:comment> <associatedData><xsd:float rdf:value="3.14159"/></associatedData> <associatedData><xsd:string rdf:value="3.14159"/></associatedData> </Person> </rdf:RDF>
<!-- $Revision: 1.10 $ of $Date: 2001/12/18 21:48:05 $. --> <xsd:schema xmlns:xsd ="http://www.w3.org/2000/10/XMLSchema"> <xsd:simpleType name="over12"> <!-- over12 is an XMLS datatype based on decimal --> <!-- with the added restriction that values must be >= 13 --> <xsd:restriction base="xsd:decimal"> <xsd:minInclusive value="13"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="over17"> <!-- over17 is an XMLS datatype based on positiveIntege --> <!-- with the added restriction that values must be >= 18 --> <xsd:restriction base="xsd:positiveInteger"> <xsd:minInclusive value="18"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="over59"> <!-- over59 is an XMLS datatype based on positiveIntege --> <!-- with the added restriction that values must be >= 59 --> <xsd:restriction base="xsd:positiveInteger"> <xsd:minInclusive value="60"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="clothingsize"> <!-- clothingsize is an XMLS union datatype --> <!-- values of clothingsize may be either integers or strings --> <xsd:union> <xsd:simpleType> <xsd:restriction base='integer'/> </xsd:simpleType> <xsd:simpleType> <xsd:restriction base='string'/> </xsd:simpleType> </xsd:union> </xsd:simpleType> <xsd:simpleType name="XSDEnumerationHeight"> <!-- This is an XMLS datatype valid values for which are the strings --> <!-- "short", "medium" and "tall". --> <xsd:restriction base="string"> <xsd:enumeration value="short"/> <xsd:enumeration value="medium"/> <xsd:enumeration value="tall"/> </xsd:restriction> </xsd:simpleType> </xsd:schema>
This walkthrough draws on the work of many of the researchers in the DAML project, and from discussion with and review by Jim Hendler, Tim Berners-Lee, Ralph R. Swick, Pat Hayes, Drew McDermott, Stefan Decker, Richard Fikes, and Jeff Heflin.
This work was supported in part by the US Defense Advanced Research Projects Agency under the auspices of the DARPA Agent Markup Language (DAML) Project , Prof. James Hendler, program manager.
background: RDF: Resource Description Framework at W3C