The core of the ELTK is an interface to the combined data models of the Web Ontology Language (OWL), Resource Description Framework Schema (RDFS) and the Resource Description Framework(RDF). (In the documentation we refer to this combined data model as “OWL+RDFS+RDF”.) That is, using the ELTK, OWL+RDFS+RDF entities are imported into the Python programming environment such that classes, properties and individuals of OWL+RDFS+RDF are created and manipulated alongside Python classes, methods and instances. The goal, then, is to produce Python code that reflects the OWL+RDFS+RDF data model. In this way, the developer can simply use the model at hand (loaded via an ontology and various RDF data graphs), not worrying about ways to re-model OWL+RDFS+RDF in Python. This approach seems quite natural for a Semantic Web effort and may be characterized as a type of ontology-driven software design (cf. [KoideTakeda2006]).
In order to import the model into Python’s OOP environment, we use metaprogramming, or the ability to write code to manipulate code. As inspired by [BabikHluchy2006], the OWL class hierarchy can be directly imported into the Python class hierarchy.
In general OWL+RDFS+RDF is conceptually similar to the object-oriented programming (OOP) paradigm as used in Python. Both OWL+RDFS+RDF and OOP allow for classes and subclasses, inheritance and limited multiple inheritance. RDFS:subClassOf is translated directly to Python class inheritance. Object composition and class instantiation are also similar. RDF:type is translated to Python class instantiation. But the semantics of OWL+RDFS+RDF is inconsistent with that of Python’s in a number of key aspects. For example in most OOP languages, a class instance can only belong to a single class. That is, in Python, the expression type(MyInstance) can only yield a single class. This ensures the behavior of instances based on the associated methods and variables of the instantiated class. In OWL+RDFS+RDF, however, a single individual (corresponding to an instance in OOP) can instantiate multiple classes in the same knowledge base. Thus, to provide a linguistics example, a particular language can be an individual of both EndangeredLanguage and of Koiné at the same time. In the ELTK we manage to integrate this facet of OWL semantics in a fairly seamless way.
The first thing to do is to import the Meta module:
>>> from eltk.kb.Meta import *
In the simplest case, an OWL class can be created using the new constructor which takes some URI:
>>> Word=OWLClass.new(u'http://mydomain.org/Word')
The new constructor is needed in order to create an instance of metaclass, i.e., Word. Its URI can be called using getURI()
>>> Word.getURI()
>>> http://mydomain.org/Word
The following also works
>>>Word.uri
>>> http://mydomain.org/Word
To demonstrate inheritance, let’s create another class:
>>> Root=OWLClass.new(u'http://mydomain.org/Root')
And then create yet a third class that inherits from both Word and Root:
>>> RootWord=OWLClass.new(u'RootWord',(Word,Root))
>>> issubclass(RootWord,Root)
True
>>> issubclass(RootWord,Word)
True
Instances of classes (cf. OWL individuals) can be created as follows:
>>> Word = OWLClass.new('http://foo.org/Word')
>>> w1 = Word(u'http://foo.org/word123')
>>> w2 = Word(u'http://foo.org/word456')
>>> type(w1)
<class 'eltk.kb.Meta.Word'>
The getType method is defined to return a list of all types
>>> getType(w1)
[<class 'eltk.kb.Meta.Word'>]
Like Python’s built-in type function, getType returns the type for a metaclass instance. However, unlike built-in type, this function returns a list of types and is, thus, used to simulate the multiple typing found with OWL.
>>> class1 = OWLClass.new(u'http://foo.org/class1')
>>> class2 = OWLClass.new(u'http://foo.org/class2')
>>> i = class1(u'http://foo.org/i',[class2])
>>> getType(i)
[<class '__main__.class2'>, <class '__main__.class1'>]
There are two kinds of OWL properties: OWLObjectProperty and OWLDatatypeProperty. An OWLObjectProperty can be created as follows
>>> hasConstituent = OWLObjectProperty.new(u'http://foo.org/hasConstituent')
We now create a Morpheme individual in order to demonstrate has the property can be used
>>> Morpheme = OWLClass.new(u'http//foo.org/Morpheme')
>>> m1 = Morpheme(u'http:foo.org/m1')
The property can be used as follows, glossed as “the Word w1 has the Morpheme m1 as its constituent”
>>> hasConstituent(w1,m1)
(<eltk.kb.Meta.Word object at 0x3a68dd0>, <class 'eltk.kb.Meta.hasConstituent'>, <eltk.kb.Meta.Morpheme object at 0x3a68f90>)
Notice that a 3-tuple (a triple) was returned. That is, when a property is called, a statement in the form of a triple is created.