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.