Friday, April 08, 2005

Jena tip: navigating a union or intersection class expression

One of the things I spend a lot of my time doing is answering Jena questions. Historically, the search capability at YahooGroups has been atrocious. For some time, I've been thinking that blogging some Jena tips for Google to find would be a good idea. I'm told that YahooGroups' search capability has been improved recently, nonetheless I'm going to try blogging some of the more common issues and FAQ's as they come up. Maybe it will save someone some time, and me some email effort.

One frequently asked question is how to get classes out of a union or intersection class expression. Suppose you have some OWL like this:

  <owl:Class rdf:ID='StateMachine'> 
  <owl:equivalentClass> 
    <owl:Class> 
      <owl:intersectionOf rdf:parseType='Collection'> 
        <owl:Restriction> 
          <owl:onProperty> 
            <owl:ObjectProperty rdf:about='#state'/> 
          </owl:onProperty> 
          <owl:someValuesFrom> 
            <owl:Class rdf:about='#State'/> 
          </owl:someValuesFrom> 
        </owl:Restriction> 
        <owl:Class rdf:about='#Automaton'/> 
      </owl:intersectionOf> 
    </owl:Class> 
  </owl:equivalentClass> 

A state machine is the intersection of class Automaton with things that have a state property. It's just a synthetic example, don't sweat the details! First, here's some code to list the elements of the intersection:

  OntClass nfp = m.getOntClass( NS + "StateMachine" );
  IntersectionClass ec = nfp.getEquivalentClass()
                            .asIntersectionClass();

  for (Iterator i = ec.listOperands(); i.hasNext(); ) {
      OntClass op = (OntClass) i.next();

      if (op.isRestriction()) {
          System.out.println( "Restriction on property " + 
                              op.asRestriction().getOnProperty() );
      }
      else {
          System.out.println( "Named class " + op );
      }
  }

Two key points here: first, Jena uses .as() to convert between views, or facets of RDF resources in the model. Since RDF resources can change type according to what's asserted in the model, ordinary Java casting doesn't work because it's too static. The .as() mechanism is really a form of dynamic polymorphism. The generic form of .as() takes the facet's Java class as a parameter, but the Ontology API classes provide various convenience methods with the pattern .asXYX. Hence .asIntersectionClass().

The second key point, and the one that many people don't seem to notice in the documentation, is that UnionClass and IntersectionClass are both instances of BooleanClassDescription, which presents a variety of means for accessing the members of the intersection or union. listOperands() returns an iterator whose values are the class in the intersection or union.

del.icio.us: jena semanticweb

No comments: