Thursday, November 02, 2006

Jena tip: renaming RDF resources

We rather frequently get asked, on the Jena support list, something along the lines of "how do I rename an RDF resource?" or "how do I change the local-name of an OWL class?" or something similar. We get asked this often enough that we made a FAQ entry about it. That FAQ entry is fairly terse, because many users are fine to read the Javadoc, figure out how to apply the renameResource in their application, and off they go. For inexperienced Jena users, especially those without much Java experience either, a more detailed explanation is probably in order however.

For a variety of good design reasons, the Java class representing RDF resources in Jena, com.hp.hpl.jena.rdf.model.Resource is immutable - once created, it can never be changed. This means that there is not, and never will be, a method on Resource called something like rename(). This also means that all the classes that extend Resource, such as OntClass also can't be renamed in place. Suppose you are developing a semantic web editor. It's a perfectly natural requirement to change the name of a class as your understanding of the ontology grows. So, what to do?

It's important to note that the Resource object in a Jena model doesn't contain any state information. All the RDF object state is held in the RDF Model) (and, internally within the Model in a Graph object, but that's another topic). Resource, therefore, isn't really an information container but an accessor for information that is contained in the model. Moreover, Model itself doesn't contain Resource's per se: Model only contains RDF subject-predicate-object triples. A resource is in a model only to the extent that it appears in one of the triples in that model. This, then, gives us a way to achieve the effect of renaming a resource: to rename a resource from A0 to A1, simply replace every triple that contains A0 with one that contains A1. A quick example should make this clearer. Suppose we have the following information in the model (I'm using N3/Turtle syntax for compactness; it would be exactly the same with RDF/XML):

@prefix owl: <http://www.w3.org/2002/07/owl#>.
@prefix eg: <http://example.com/eg#>.

eg:Device 
      rdf:type owl:Class
    .
eg:MobilePhone
      rdf:type owl:Class
    ; rdfs:subClassOf eg:Device
    .
eg:JavaPhone
      rdf:type owl:Class
    ; rdfs:subClassOf eg:MobilePhone
    .

This model fragment contains five triples. To rename eg:MobilePhone to eg:CellPhone, we need to replace three of those triples, to produce the following model:

eg:Device 
      rdf:type owl:Class
    .
eg:CellPhone
      rdf:type owl:Class
    ; rdfs:subClassOf eg:Device
    .
eg:JavaPhone
      rdf:type owl:Class
    ; rdfs:subClassOf eg:CellPhone
    .

This can be done manually by the calling Jena program, and that's fine. However, we do provide a helper method to assist with this, in ResourceUtils. The following code fragment shows one way of achieving the above example. Assume that m is a Java variable containing an already-loaded Jena model which, in turn, contains the resource we want to rename:

Model m = .... ; // source model, already initialised

String NS = "http://example.com/eg#";
Resource cls = m.getResource( NS + "MobilePhone" );

// this is the step where eg:MobilePhone becomes eg:CellPhone
ResourceUtils.renameResource( cls, NS + "CellPhone" );

// it's important that we forget about, or re-assign,
// cls, since as yet it's not pointing to the 
// revised definition
cls = m.getResource( NS + "CellPhone" );

// now we can, for example, look at the updated definition
for (StmtIterator i = cls.listProperties(); i.hasNext();) {
    System.out.println( " m contains triple " + i.nextStatement() );
}

And that's all there is to it.

del.icio.us: jena, semanticweb, java,

No comments: