Protege-OWL API中文版(自己翻译的)

时间:2022-12-25 20:41:06

Protege-OWL API 网址链接如下(http://protegewiki.stanford.edu/wiki/ProtegeOWL_API_Basics)

一. 使用OWL模型

在model包下,有一些java接口,这些接口集合组成了API。通过这些接口可以访问OWL模型以及模型中元素:类,属性,实例等。程序开发者不可以直接访问这些接口的具体实现,只能操作这些接口。只用接口时你没有必要担心Protégé是如何存储本体这些内部细节,接口中的所有方法都是抽象的,你不用考虑它的具体实现。
最重要的模型接口是OWLModel,它提供了可以访问本体中资源的顶层容器。你可以使用它去创建,查询,删除各种类型的资源,也可以使用OWLModel返回的对象来进行某种操作。例如,下面的代码片段创建了本体模型和类(在OWL语言中表示为:owl:Class),同时得到了URI(统一资源标识符):
OWLModel owlModel = ProtegeOWL.createJenaOWLModel();
OWLNamedClass worldClass = owlModel.createOWLNamedClass("World");
System.out.println("Class URI: " + worldClass.getURI());

ProtegeOWL提供了两个可以创建owlModel的简单的静态的方法,还可以直接导入已经存在的OWL文件。例如,你可以载入一个已存在的本体按照如下方法:

String uri = "http://www.co-ode.org/ontologies/pizza/2007/02/12/pizza.owl";
OWLModel owlModel = ProtegeOWL.createJenaOWLModelFromURI(uri);

二. 名字,命名空间前缀和URI

OWL和RDF通过它们的URI(统一资源标识符)在全球范围内被标识,比如:http://www.owl-ontologies.com/travel.owl#Destination.由于这些URI很长而且不方便处理,所以在Protege-OWL API中通过名字来访问和辨别本体资源。例如,我们可以用owl:Class 来代替http://www.w3.org/2002/07/owl#Class,因为“owl”是命名空间
http://www.w3.org/2002/07/owl#的前缀。同样的,如果你导入了travel本体,那么你可以定义一个前缀“travel”去访问所有的导入类和属性,例如,travel:Destination。如果我们的本体是默认的命名空间,那么它的前缀是空的,资源名字只有Destination。程序开发者可以通过使用NamespaceManager接口来控制命名空间前缀。为了访问当前OWLModel的NamespaceManager,你可以使用OWLModel.getNamespaceManager()方法,假设我们已经载入了一个travel本体作为一个默认的命名空间,我们通过如下方式访问包含在OWLModel内的资源:

OWLNamedClass destinationClass =                      
owlModel.getOWLNamedClass("Destination");
OWLObjectProperty hasContactProperty = owlModel.getOWLObjectProperty("hasContact");
OWLDatatypeProperty hasZipCodeProperty = owlModel.getOWLDatatypeProperty("hasZipCode");
OWLIndividual sydney = owlModel.getOWLIndividual("Sydney");

也可以查询和操作相应的资源。例如,提取一个已命名的object,可以使用
RDFResource.getURI()方法。

三. 理解model接口

Model包里的接口是按照继承层次排列的。所有资源中,最基本的接口是RDFResource,其他的对于类,属性,实例的子接口(RDFSclass,RDFProperty,RDFIndividual)都是由它衍生的。
RDFResource定义了所有资源的基本操作,尤其是get和set属性值。
RDFProperty也是基本接口,对于rdf:Properties,以及子类型owl:DatatypeProperty and owl:ObjectProperty。
对于类来说,层级制度很复杂,因为在OWL中有很多匿名类,这个问题稍后处理。
下面这个例子创建一个简单的类,以及它的实例和一对属性:

OWLModel owlModel = ProtegeOWL.createJenaOWLModel();

OWLNamedClass personClass = owlModel.createOWLNamedClass("Person");

OWLDatatypeProperty ageProperty = owlModel.createOWLDatatypeProperty("age");
ageProperty.setRange(owlModel.getXSDint());
ageProperty.setDomain(personClass);

OWLObjectProperty childrenProperty = owlModel.createOWLObjectProperty("children");
childrenProperty.setRange(personClass);
childrenProperty.setDomain(personClass);

RDFIndividual darwin = personClass.createRDFIndividual("Darwin");
darwin.setPropertyValue(ageProperty, new Integer(0));

RDFIndividual holgi = personClass.createRDFIndividual("Holger");
holgi.setPropertyValue(childrenProperty, darwin);
holgi.setPropertyValue(ageProperty, new Integer(33));

四. 创建命名类和实例

Protégé-OWL API对于命名类和匿名类有很明确的区分。命名类被用来创建实例,而匿名类用于详细说明命名类的逻辑特点(限制条件)。匿名类稍后讨论,现在我们来看命名类。为了显示出OWL的规范性,这里有两种命名类的类型:RDFSNamedClass(rdfs:Class)和OWLNamedClass(owl:Class).除非你在RDF上非常明确的,否则你做好还是创建OWL类。当你创建好类以后,你可以按照子类的关系排列它们:

OWLNamedClass personClass = owlModel.createOWLNamedClass("Person");

// Create subclass (complicated version)
OWLNamedClass brotherClass = owlModel.createOWLNamedClass("Brother");
brotherClass.addSuperclass(personClass);
brotherClass.removeSuperclass(owlModel.getOWLThingClass());

在这个例子程序中,首先创建一个personClass和brotherClass类,都是顶层类。通过OWLModel.createOWLNamedClass(String name) 方法创建的类都默认是owl:Thing的子类。然后又将personClass设置为brotherClass的父类,所以此时brotherClass有两个父类,所以在后面remove了一个类。一个更方便的创建person子类的方法如下:

OWLNamedClass sisterClass = owlModel.createOWLNamedSubclass("Sister", personClass);

最后得到的继承层次如下:

Person
brother
sister

一个简单的递归调用可能在之后会被用于打印带有缩进的继承层次关系。

 printClassTree(personClass, "");
}

private static void printClassTree(RDFSClass cls, String indentation) {
System.out.println(indentation + cls.getName());
for (Iterator it = cls.getSubclasses(false).iterator(); it.hasNext();) {
RDFSClass subclass = (RDFSClass) it.next();
printClassTree(subclass, indentation + " ");
}
}

在递归程序中, RDFSClass.getSubclasses()得到一个Boolean类型的参数,如果这个参数是true,那么不仅会返回该类的直接子类,还会返回这个子类的子类,等等。命名类可用于产生实例,这个类的实例可以通过RDFSClass.getInstances()方法被查询到:

 OWLIndividual individual = brotherClass.createOWLIndividual("Hans");
Collection brothers = brotherClass.getInstances(false);
assert (brothers.contains(hans));
assert (brothers.size() == 1);

直接和间接实例有很大差别。个体Hans是一个brother的直接实例,却是Person的间接实例。因为brother是person的子类,每一个brother都是一个person。程序员可以通过控制参数来决定是否只得到直接实例或者也需要间接实例,其中true表示返回的实例包括该类子类的实例:

assert (personClass.getInstanceCount(false) == 0);
assert (personClass.getInstanceCount(true) == 0);
assert (personClass.getInstances(true).contains(hans));

可以使用 RDFResource.getRDFType()方法来根据某个实例得到它所属的类。例如,Hans有直接父类brother和间接父类Person:

assert (hans.getRDFType().equals(brotherClass));
assert (hans.hasRDFType(brotherClass));
assert !(hans.hasRDFType(personClass, false));
assert (hans.hasRDFType(personClass, true));

如果一个资源的生存期结束了,就可以通过 RDFResource.delete() 方法删除。该API使用和其他API相同的约定,当“delete”时就意味着完全的毁灭,而“remove”表示删除一个对象的引用。这意味着,当你“delete”一个资源后,它的所有属性值只是被“remove”,没有被“delete”。

hans.delete();

五. 使用数据类型属性和数据类型值

为了创建owl:DatatypeProperty,你可以使用OWLModel.createOWLDatatypeProperty(String name)。默认的,数据类型属性的参数值可以采用任何类型,字符串,整型等。Owl定义了几种xml模式来限制属性的范围。最常用的xml模式有,xsd:string, xsd:int, xsd:float, 和 xsd:boolean.如果你想要将属性范围限制为String,可以这样做:

OWLDatatypeProperty property = owlModel.createOWLDatatypeProperty("name");
name.setRange(owlModel.getXSDstring());

调用getXSDstring()时返回引用给getXSDstring() xsd:String.其他默认的数据类型可以通过类似的OWLModel.getXSD..方法来访问。更多复杂的数据类型可以通过他们URI来访问:

RDFSDatatype dateType = owlModel.getRDFSDatatypeByName("xsd:date");

对于默认的数据类型,属性值可以通过相应的java的数据类型来方便的处理。例如,如果你为一个string类型的属性分配属性值你可以对string对象进行setPropertyValue调用。相应的映射也可以用于其他数据类型:

    individual.setPropertyValue(stringProperty, "MyString");
individual.setPropertyValue(intProperty, new Integer(42));
individual.setPropertyValue(floatProperty, new Float(4.2));
individual.setPropertyValue(booleanProperty, Boolean.TRUE);

反过来,得到数据属性也有很简单的方法:

String stringValue = (String) individual.getPropertyValue(stringProperty);
Integer intValue = (Integer) individual.getPropertyValue(intProperty);
Float float = (Float) individual.getPropertyValue(floatProperty);
Boolean boolean = (Boolean) individual.getPropertyValue(booleanProperty);

所有其他数据类型的值都被包装到一个RDFSLiteral类的对象中。一个literal中一个值连接一个数据类型。值可以被存储为string类型,需要用户代码解封装。下面这个例子分配给xml模式数据类型xsd:data一个值:

RDFSDatatype xsdDate = owlModel.getRDFSDatatypeByName("xsd:date");
OWLDatatypeProperty dateProperty = owlModel.createOWLDatatypeProperty("dateProperty", xsdDate);
RDFSLiteral dateLiteral = owlModel.createRDFSLiteral("1971-07-06", xsdDate);
individual.setPropertyValue(dateProperty, dateLiteral);
RDFSLiteral myDate = (RDFSLiteral) individual.getPropertyValue(dateProperty);
System.out.println("Date: " + myDate);

上面代码将打印出“Date-1971-07-06”.
RDFSLiteral类也用于绑定一个string类型到一个language标签:

    RDFSLiteral langLiteral = owlModel.createRDFSLiteral("Wert", "de");
individual.setPropertyValue(stringProperty, langLiteral);
RDFSLiteral result = (RDFSLiteral) individual.getPropertyValue(stringProperty);
assert (result.getLanguage().equals("de"));
assert (result.getString().equals("Wert"));

总结,被处理的数据类型值既可以是基本类型对象(string,integer,float,Boolean),也可以是RDFSLiterals.如果我们有一个默认的数据类型的literal,那么它将自动的简化。在一些情况下,使用RDFSLiterals更加方便,尤其当用户的代码要执行任意的数据类型。对于这种情况,Protégé-owl API提供了一些方便的方法来返回RDFSLiterals:OWLModel.asRDFSLiteral()

六. 使用对象类型在资源之间建立关系

Owl:ObjectProperty用于在个体之间建立关系。下面这个程序片段创建一个对象属性“children”,它把“persons”作为值域:

OWLNamedClass personClass = owlModel.createOWLNamedClass("Person");
OWLObjectProperty childrenProperty = owlModel.createOWLObjectProperty("children");
childrenProperty.setRange(personClass);

接下来,API还可以为个体分配属性值:

    RDFIndividual darwin = personClass.createRDFIndividual("Darwin");
RDFIndividual holgi = personClass.createRDFIndividual("Holger");
holgi.setPropertyValue(childrenProperty, darwin);

API还提供方法来添加和删除值:

    holgi.addPropertyValue(childrenProperty, other);
holgi.removePropertyValue(childrenProperty, other);

假设现在有一个animal类,你想要指定children属性的值域是animal同时是person。在owl中,你需要创建一个owl:unionOf类来声明值域,因为声明这两个类作为rdfs:ranges将意味着一个对象必须同时是person和animal,才是有效的属性。因此,要正确的声明,就像下面这样:

<owl:Class rdf:ID="Person"/>
<owl:Class rdf:ID="Animal"/>
<owl:ObjectProperty rdf:ID="children">
<rdfs:range>
<owl:Class>
<owl:unionOf rdf:parseType="Collection">
<owl:Class rdf:about="#Person"/>
<owl:Class rdf:about="#Animal"/>
</owl:unionOf>
</owl:Class>
</rdfs:range>
</owl:ObjectProperty>

尽管人工的创建unions属性很复杂,但是Protege-owl API提供了可以简单动态的创建值域的方法:

OWLNamedClass personClass = owlModel.createOWLNamedClass("Person");
OWLNamedClass animalClass = owlModel.createOWLNamedClass("Animal");
OWLObjectProperty childrenProperty = owlModel.createOWLObjectProperty("children");
childrenProperty.addUnionRangeClass(personClass);
childrenProperty.addUnionRangeClass(animalClass);

对象属性也可以声明有其他的特点,比如,可传递性。在下面的代码片段中,属性的祖先被声明是具有传递性的,因为如果A是B的祖先,而且B是C的祖先,那么A也是C的祖先:

    OWLObjectProperty ancestorProperty = owlModel.createOWLObjectProperty("ancestor");
ancestorProperty.setRange(personClass);
ancestorProperty.setTransitive(true);

相同的方法适用于对称属性或功能属性。

七. 引用外部的/无类型的资源

在很多例子中,owl中的资源可以引用其他的非owl资源。比如,你想要定义一条从owl资源到图片的资源。owl/RDF可以包含到任意URI的连接,比如下面的hasImage属性:

<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns="http://www.owl-ontologies.com/unnamed.owl#"
xml:base="http://www.owl-ontologies.com/unnamed.owl">

<owl:Ontology rdf:about=""/>
<owl:Class rdf:ID="Person"/>
<rdf:Property rdf:ID="hasImage"/>
<Person rdf:ID="Darwin">
<hasImage rdf:resource="http://www.knublauch.com/darwin/Darwin-Feeding-Smiling.jpg"/>
</Person>
</rdf:RDF>

Protege-owl API用 RDFUntypedResource类来实现这种连接。无类型的资源是没有rdf:type描述的实例。因为命名空间前缀无能应用于无类型的资源,所以RDFUntypedResource类的实例是用它们完整的URI作为名字。下面的程序创建了一个本体例子来展示上述内容:

JenaOWLModel owlModel = ProtegeOWL.createJenaOWLModel();

OWLNamedClass personClass = owlModel.createOWLNamedClass("Person");
OWLIndividual individual = personClass.createOWLIndividual("Darwin");
RDFProperty hasImageProperty = owlModel.createRDFProperty("hasImage");

String uri = "http://www.knublauch.com/darwin/Darwin-Feeding-Smiling.jpg";
RDFUntypedResource image = owlModel.createRDFUntypedResource(uri);
individual.addPropertyValue(hasImageProperty, image);

Jena.dumpRDF(owlModel.getOntModel());

八.属性域

属性域指定了资源的类型,通过它可以得到属性值。在一些小例子中,属性是没有域的,也就是,在owl文件中,它是没有任何rdfs:domain描述的。在逻辑上等同于,这个domain只是由owl:Thing类组成的,因为每一个类都是来源于owl:Thing类的。在protégé中,一个新的属性的domain默认为空,意味着是无类型的,
在API的RDFProperty类中提供了几种方法来设置和查询domain。下面的代码片段创建一个新的属性并且设置person类为它的属性:

OWLNamedClass personClass = owlModel.createOWLNamedClass("Person");
OWLObjectProperty childrenProperty = owlModel.createOWLObjectProperty("children");
childrenProperty.setDomain(personClass);

原则上,属性可以有多个定义域。类似于range描述,有多个domain意味着属性可以应用于domain类的交集。这样做是不能反应模型建造者的意图,而且更常见的例子是声明domain是很多个类的联合,通过匿名owl:unionOf来实现。在Protégé-owl API中,这些联合类可以自动的被创建,参照如下的调用:

OWLNamedClass animalClass = owlModel.createOWLNamedClass("Animal");
childrenProperty.addUnionDomainClass(animalClass);

产生 的结果就像下面这段代码一样:

<owl:Class rdf:ID="Person"/>
<owl:Class rdf:ID="Animal"/>
<owl:ObjectProperty rdf:ID="children">
<rdfs:domain>
<owl:Class>
<owl:unionOf rdf:parseType="Collection">
<owl:Class rdf:about="#Person"/>
<owl:Class rdf:about="#Animal"/>
</owl:unionOf>
</owl:Class>
</rdfs:domain>
</owl:ObjectProperty>

如果你想实现子属性层次结构的话,处理domain会有点复杂。如果子属性没有自己的domain,那么它将继承父属性的domain。例如,如果你有个son属性,它是children的子属性,你没有指定son的domain的话,那么它的domain会包括person和animal:

 OWLObjectProperty sonsProperty = owlModel.createOWLObjectProperty("sons");
sonsProperty.addSuperproperty(childrenProperty);
assert (sonsProperty.getDomain(false) == null);
assert (sonsProperty.getDomain(true) instanceof OWLUnionClass);

在程序中,RDFProperty.getDomain方法可以设置布尔变量来区分属性的直接域和它可能继承的域。在上面的例子中,domain由OWLUnionClass组成,之后一个方法RDFProperty.getUnionDomain可以由联合domains得到一个简单的类集合:

Collection unionDomain = sonsProperty.getUnionDomain(true);
assert (unionDomain.contains(personClass));
assert (unionDomain.contains(animalClass));

以上全部是我自己根据官网API文档翻译的,存在很多不足之处,仅供参考。。期待和正在研究本体相关知识的人共同进步。。。。谢谢。。