Difference between revisions of "ProtegeOWL API Advanced Topics"

From Protege Wiki
Jump to: navigation, search
(checkpoint save)
(Querying the OWLModel: Changed part of example for File URIs to be more robust.)
 
(2 intermediate revisions by one other user not shown)
Line 16: Line 16:
  
 
//alternatively, you can specify a local path on your computer
 
//alternatively, you can specify a local path on your computer
//for the travel.owl ontology. Example:
+
//for the travel.owl ontology. If you do this, it is more robust
//String uri = "file:///c:/Work/Projects/travel.owl"
+
//to go through the File object to get the URI instead of writing it by hand
 +
// Example:
 +
//String uri = new File("c:/Work/Projects/travel.owl").toURI();
  
 
OWLModel owlModel = ProtegeOWL.createJenaOWLModelFromURI(uri);
 
OWLModel owlModel = ProtegeOWL.createJenaOWLModelFromURI(uri);
Line 71: Line 73:
  
 
For more advanced queries in languages like RDQL, you need to use external libraries as there is currently no native support in Protege-OWL for them. For example, you could access a Jena '''OntModel''' on the fly and then perform queries on this OntModel. Instructions for accessing the Jena model are provided later.
 
For more advanced queries in languages like RDQL, you need to use external libraries as there is currently no native support in Protege-OWL for them. For example, you could access a Jena '''OntModel''' on the fly and then perform queries on this OntModel. Instructions for accessing the Jena model are provided later.
 
  
 
=== RDF(S) and OWL ===
 
=== RDF(S) and OWL ===
Line 164: Line 165:
 
=== Loading and Saving Files ===
 
=== Loading and Saving Files ===
  
The Protégé-OWL API can be used in two storage modes:
+
The Protege-OWL API can be used in two storage modes:
  
 
* OWL Files mode (class [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/jena/JenaOWLModel.html JenaOWLModel])
 
* OWL Files mode (class [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/jena/JenaOWLModel.html JenaOWLModel])
Line 171: Line 172:
 
Both modes operate on the same '''OWLModel''' core interface. Method calls to do things like create classes are totally independent from the storage mode. Programmers do not have to care whether the class is physically created in a database or only kept in memory. There are some subtle differences between the two modes as both have some extra functions.
 
Both modes operate on the same '''OWLModel''' core interface. Method calls to do things like create classes are totally independent from the storage mode. Programmers do not have to care whether the class is physically created in a database or only kept in memory. There are some subtle differences between the two modes as both have some extra functions.
  
OWL Files mode is based on the '''JenaOWLModel''' class. You can use the static methods from the '''ProtegeOWL''' class to load an existing OWL file from a stream or a URL. The calls will return a '''JenaOWLModel''', and you can then use the save methods in the '''JenaOWLModel''' to write the file back to disk:
+
OWL Files mode is based on the '''JenaOWLModel''' class. You can use the static methods from the '''ProtegeOWL''' class to load an existing OWL file from a stream or a URL. The calls will return a JenaOWLModel, and you can then use the save methods in the JenaOWLModel to write the file back to disk:
 +
 
  
 
<pre>
 
<pre>
  String uri = "http://protege.cim3.net/file/pub/ontologies/travel/travel.owl";
+
String uri = "http://protege.cim3.net/file/pub/ontologies/travel/travel.owl";
    //alternatively, you can specify a local path on your computer
+
 
    //for the travel.owl ontology. Example:
+
//alternatively, you can specify a local path on your computer
    //String uri = "file:///c:/Work/Projects/travel.owl"
+
//for the travel.owl ontology. Example:
    JenaOWLModel owlModel = ProtegeOWL.createJenaOWLModelFromURI(uri);
+
//String uri = "file:///c:/Work/Projects/travel.owl"
 +
 
 +
JenaOWLModel owlModel = ProtegeOWL.createJenaOWLModelFromURI(uri);
  
    OWLNamedClass destinationClass = owlModel.getOWLNamedClass("Destination");
+
OWLNamedClass destinationClass = owlModel.getOWLNamedClass("Destination");
    // ...
+
// ...
  
    String fileName = "travel-saved.owl";
+
String fileName = "travel-saved.owl";
    Collection errors = new ArrayList();
+
Collection errors = new ArrayList();
    owlModel.save(new File(fileName).toURI(), FileUtils.langXMLAbbrev, errors);
+
owlModel.save(new File(fileName).toURI(), FileUtils.langXMLAbbrev, errors);
    System.out.println("File saved with " + errors.size() + " errors.");
+
System.out.println("File saved with " + errors.size() + " errors.");
 
</pre>
 
</pre>
 +
  
 
=== Working with Multi-File Projects and TripleStores ===
 
=== Working with Multi-File Projects and TripleStores ===
  
OWL ontologies can import other ontologies and thus establish relationships between resources from multiple files. For example, it is a common design pattern to keep instance data separate from classes and properties. In this case, the instances ontology would import the ontology that defines the classes. The Protégé user interface allows users to switch the "active" sub-ontology, so that users can select which file changes will be propogated to.
+
OWL ontologies can import other ontologies and thus establish relationships between resources from multiple files. For example, it is a common design pattern to keep instance data separate from classes and properties. In this case, the instances ontology would import the ontology that defines the classes. The Protege user interface allows users to switch the "active" sub-ontology, so that users can select which file changes will be propagated to.
  
Protégé stores OWL ontologies in triple tables, one table for each file. These tables are now named after the Java interface [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/model/triplestore/TripleStore.html TripleStore]. Each '''OWLModel''' manages a list of '''TripleStores''' by means of its [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/model/triplestore/TripleStoreModel.html TripleStoreModel]. An empty project has two '''TripleStores''': The system '''TripleStore''' containing the system classes such as '''owl:Class''', and the main '''TripleStore'''. If your project imports other ontologies, you can change the active '''TripleStore''' using the corresponding '''TripleStoreModel''' methods.
+
Protege stores OWL ontologies in triple tables, one table for each file. These tables are named after the Java interface [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/model/triplestore/TripleStore.html TripleStore]. Each OWLModel manages a list of '''TripleStores''' by means of its [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/model/triplestore/TripleStoreModel.html TripleStoreModel]. An empty project has two TripleStores: The system '''TripleStore''' containing the system classes such as owl:Class, and the main TripleStore. If your project imports other ontologies, you can change the active TripleStore using the corresponding '''TripleStoreModel''' methods.
  
 
When you save your project, the saver will overwrite all files that have an alternative file:-entry in the ont-policy file, and which are declared to be editable.
 
When you save your project, the saver will overwrite all files that have an alternative file:-entry in the ont-policy file, and which are declared to be editable.
 +
  
 
=== Working with Jena models ===
 
=== Working with Jena models ===
  
Protégé-OWL uses the popular [http://jena.sourceforge.net/ Jena] API for various tasks, in particular for parsing of OWL/RDF files. Furthermore, the Protégé-OWL API can be used to generate a '''Jena OntModel''' at any time. Both '''JenaOWLModel''' and '''OWLDatabaseModel''' implement the [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/jena/OntModelProvider.html OntModelProvider]  interface, which has a [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/jena/OntModelProvider.html#getOntModel() getOntModel()]  method to create an '''OntModel''' from the current ontology.
+
Protege-OWL uses the popular [http://jena.sourceforge.net/ Jena] API for various tasks, in particular for parsing of OWL/RDF files. Furthermore, the Protege-OWL API can be used to generate a Jena '''OntModel''' at any time. Both '''JenaOWLModel''' and '''OWLDatabaseModel''' implement the [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/jena/OntModelProvider.html OntModelProvider]  interface, which has a [http://protege.stanford.edu/protege/3.4/docs/api/owl/edu/stanford/smi/protegex/owl/jena/OntModelProvider.html#getOntModel() getOntModel()]  method to create an OntModel from the current ontology.
 +
 
  
 
<pre>
 
<pre>
  JenaOWLModel owlModel = ProtegeOWL.createJenaOWLModel();
+
JenaOWLModel owlModel = ProtegeOWL.createJenaOWLModel();
  
    OWLNamedClass cls = owlModel.createOWLNamedClass("Class");
+
OWLNamedClass cls = owlModel.createOWLNamedClass("Class");
    OWLDatatypeProperty property = owlModel.createOWLDatatypeProperty("property");
+
OWLDatatypeProperty property = owlModel.createOWLDatatypeProperty("property");
    OWLIndividual individual = cls.createOWLIndividual("Individual");
+
OWLIndividual individual = cls.createOWLIndividual("Individual");
  
    OntModel ontModel = owlModel.getOntModel();
+
OntModel ontModel = owlModel.getOntModel();
    OntClass ontClass = ontModel.getOntClass(cls.getURI());
+
OntClass ontClass = ontModel.getOntClass(cls.getURI());
    DatatypeProperty ontProperty = ontModel.getDatatypeProperty(property.getURI());
+
DatatypeProperty ontProperty = ontModel.getDatatypeProperty(property.getURI());
    Individual ontIndividual = ontModel.getIndividual(individual.getURI());
+
Individual ontIndividual = ontModel.getIndividual(individual.getURI());
 
</pre>
 
</pre>
  
As an application programmer, you are free to do arbitrary operations on the resulting '''OntModel'''. In particular you can use any Jena-based services such as querying or saving files. Note however, that you currently need to call '''getOntModel()''' after each change if you want to have an '''OntModel''' that is synchronized with the current '''OWLModel'''. This may be a time consuming procedure for large ontologies.
+
 
 +
As an application programmer, you are free to do arbitrary operations on the resulting OntModel. In particular you can use any Jena-based services such as querying or saving files. Note however, that you currently need to call getOntModel() after each change if you want to have an OntModel that is synchronized with the current OWLModel. This may be a time consuming procedure for large ontologies.

Latest revision as of 11:40, February 15, 2011

Main article: ProtegeOWL_API_Programmers_Guide



Advanced Topics

Querying the OWLModel

While most of the examples so far were used to create resources in an OWLModel, we will now look at how to query and traverse the contents of an ontology. The following code iterates through all user-defined named classes in the "travel.owl" ontology and prints their instances:


String uri = "http://protege.cim3.net/file/pub/ontologies/travel/travel.owl";

//alternatively, you can specify a local path on your computer
//for the travel.owl ontology. If you do this, it is more robust
//to go through the File object to get the URI instead of writing it by hand
// Example:
//String uri = new File("c:/Work/Projects/travel.owl").toURI();

OWLModel owlModel = ProtegeOWL.createJenaOWLModelFromURI(uri);

Collection classes = owlModel.getUserDefinedOWLNamedClasses();
for (Iterator it = classes.iterator(); it.hasNext();) {
    OWLNamedClass cls = (OWLNamedClass) it.next();
    Collection instances = cls.getInstances(false);
    System.out.println("Class " + cls.getBrowserText() + " (" + instances.size() + ")");
    for (Iterator jt = instances.iterator(); jt.hasNext();) {
        OWLIndividual individual = (OWLIndividual) jt.next();
        System.out.println(" - " + individual.getBrowserText());
    }
}


This program produces the following output (using the "travel.owl" ontology):


Class Town (1)
 - Coonabarabran
Class UrbanArea (0)
Class Destination (0)
Class RuralArea (2)
 - CapeYork
 - Woomera
Class QuietDestination (0)
Class FamilyDestination (0)
...


Note that the OWLModel contains many more classes than those returned by the getUserDefined... methods. These methods filter out the system resources such as the owl:Class metaclass, owl:Thing and rdfs:subClassOf. If you want to access other resources by their names, you can easily use methods such as OWLModel.getOWLNamedClass() or OWLModel.getOWLObjectProperty().

In summary, the OWLModel class provides access to all the resources in the model. After you have gained access to the resource objects via the OWLModel, you can then call other getter methods.

To a certain extent, other types of queries are also supported. For example, you can use OWLModel.getRDFResourcesWithPropertyValue() to get all resources that have a certain property value. These properties can also be system properties, and the next example code snippet performs a query of all resources that have owl:Thing as their superclass:


RDFProperty subClassOfProperty = owlModel.getRDFProperty(RDFSNames.Slot.SUB_CLASS_OF);
OWLNamedClass owlThingClass = owlModel.getOWLThingClass();
Collection results = owlModel.getRDFResourcesWithPropertyValue(subClassOfProperty, owlThingClass);
System.out.println("Subclasses of owl:Thing:");
for (Iterator it = results.iterator(); it.hasNext();) {
    RDFResource resource = (RDFResource) it.next();
    System.out.println(" - " + resource.getBrowserText());
}


For more advanced queries in languages like RDQL, you need to use external libraries as there is currently no native support in Protege-OWL for them. For example, you could access a Jena OntModel on the fly and then perform queries on this OntModel. Instructions for accessing the Jena model are provided later.

RDF(S) and OWL

The Protege-OWL API is not limited to OWL. Since OWL is an extension of RDF Schema, the API also has native support for handling all relevant RDF elements. In particular, it is possible to create and query pure RDF files, using classes such as RDFSNamedClass, RDFProperty, and RDFIndividual instead of their OWL-specific extensions. It is also easy to create hybrid solutions that make use of selected OWL features to overcome limitations of pure RDF. For example, you can assign union classes as ranges or domains to an RDFProperty.

The following code snippet shows a typical sequence for creating an RDF ontology:


JenaOWLModel owlModel = ProtegeOWL.createJenaOWLModel();

RDFSNamedClass personClass = owlModel.createRDFSNamedClass("Person");
RDFProperty ageProperty = owlModel.createRDFProperty("age");
ageProperty.setRange(owlModel.getXSDint());
ageProperty.setDomain(personClass);

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

Jena.dumpRDF(owlModel.getOntModel());


The resulting output is the following OWL/RDF file:


<?xml version="1.0"?>
<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=""/>
  <rdfs:Class rdf:ID="Person"/>
  <rdf:Property rdf:ID="age">
    <rdfs:domain rdf:resource="#Person"/>
    <rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#int"/>
  </rdf:Property>
  <Person rdf:ID="Holger">
    <age rdf:datatype="http://www.w3.org/2001/XMLSchema#int">33</age>
  </Person>
</rdf:RDF>


If the owl:Ontology tag is not desired in the output, it can be easily stripped from the Jena model before the file is saved.


Reacting to Changes using Listeners

The Protege-OWL API supports the typical Model-view-controller architecture. This means that the model stores the representation of the ontology data, and changes in that model trigger events which external components such as UI widgets can react to. The OWL API follows the typical observer design pattern known from Swing and other UI libraries to implement such event mechanisms. Here is a trivial example, which reacts on instance creation for a given class:


OWLNamedClass cls = owlModel.createOWLNamedClass("Class");
cls.addClassListener(new ClassAdapter() {
    public void instanceAdded(RDFSClass cls, RDFResource instance) {
        System.out.println("Instance was added to class: " + instance.getName());
    }
});

for(int i = 0; i < 5; i++) {
    String newName = "Individual" + (int)(Math.random() * 10000);
    cls.createOWLIndividual(newName);
}


The basic idea is that a dedicated object called a listener registers with the model and from then on will receive notifications about changes in that object. In the example above, the listener is an instance of the ClassListener interface, which is registered at the given named class. Other listener types are PropertyListener (for property-related events), PropertyValueListener (for arbitrary property value changes at any resource), and ResourceListener for type changes of a resource. There is also a very powerful listener type ModelListener, which can be used to detect changes the affect the OWLModel in general, e.g., if a new class is created. This is demonstrated in the following code snippet:


owlModel.addModelListener(new ModelAdapter() {
    public void propertyCreated(RDFProperty property) {
        System.out.println("Property created: " + property.getName());
    }
});

owlModel.createRDFProperty("RDF-Property");
owlModel.createOWLObjectProperty("Object-Property");
owlModel.createOWLDatatypeProperty("Datatype-Property");


The code shown above will print out three lines after each create statement. The main trick here is that event handling can be completely decoupled. This is typically used in interactive user interfaces, where an action is required after a user has done a certain action, but it is not known in advance when the user will perform the action.


Loading and Saving Files

The Protege-OWL API can be used in two storage modes:

Both modes operate on the same OWLModel core interface. Method calls to do things like create classes are totally independent from the storage mode. Programmers do not have to care whether the class is physically created in a database or only kept in memory. There are some subtle differences between the two modes as both have some extra functions.

OWL Files mode is based on the JenaOWLModel class. You can use the static methods from the ProtegeOWL class to load an existing OWL file from a stream or a URL. The calls will return a JenaOWLModel, and you can then use the save methods in the JenaOWLModel to write the file back to disk:


String uri = "http://protege.cim3.net/file/pub/ontologies/travel/travel.owl";

//alternatively, you can specify a local path on your computer
//for the travel.owl ontology. Example:
//String uri = "file:///c:/Work/Projects/travel.owl"

JenaOWLModel owlModel = ProtegeOWL.createJenaOWLModelFromURI(uri);

OWLNamedClass destinationClass = owlModel.getOWLNamedClass("Destination");
// ...

String fileName = "travel-saved.owl";
Collection errors = new ArrayList();
owlModel.save(new File(fileName).toURI(), FileUtils.langXMLAbbrev, errors);
System.out.println("File saved with " + errors.size() + " errors.");


Working with Multi-File Projects and TripleStores

OWL ontologies can import other ontologies and thus establish relationships between resources from multiple files. For example, it is a common design pattern to keep instance data separate from classes and properties. In this case, the instances ontology would import the ontology that defines the classes. The Protege user interface allows users to switch the "active" sub-ontology, so that users can select which file changes will be propagated to.

Protege stores OWL ontologies in triple tables, one table for each file. These tables are named after the Java interface TripleStore. Each OWLModel manages a list of TripleStores by means of its TripleStoreModel. An empty project has two TripleStores: The system TripleStore containing the system classes such as owl:Class, and the main TripleStore. If your project imports other ontologies, you can change the active TripleStore using the corresponding TripleStoreModel methods.

When you save your project, the saver will overwrite all files that have an alternative file:-entry in the ont-policy file, and which are declared to be editable.


Working with Jena models

Protege-OWL uses the popular Jena API for various tasks, in particular for parsing of OWL/RDF files. Furthermore, the Protege-OWL API can be used to generate a Jena OntModel at any time. Both JenaOWLModel and OWLDatabaseModel implement the OntModelProvider interface, which has a getOntModel() method to create an OntModel from the current ontology.


JenaOWLModel owlModel = ProtegeOWL.createJenaOWLModel();

OWLNamedClass cls = owlModel.createOWLNamedClass("Class");
OWLDatatypeProperty property = owlModel.createOWLDatatypeProperty("property");
OWLIndividual individual = cls.createOWLIndividual("Individual");

OntModel ontModel = owlModel.getOntModel();
OntClass ontClass = ontModel.getOntClass(cls.getURI());
DatatypeProperty ontProperty = ontModel.getDatatypeProperty(property.getURI());
Individual ontIndividual = ontModel.getIndividual(individual.getURI());


As an application programmer, you are free to do arbitrary operations on the resulting OntModel. In particular you can use any Jena-based services such as querying or saving files. Note however, that you currently need to call getOntModel() after each change if you want to have an OntModel that is synchronized with the current OWLModel. This may be a time consuming procedure for large ontologies.