The Web Semantic

Avatar

data for humans and computers and the tools that make it available

Jena Ruby bindings: accessing Jena’s feature rich RDF api from Ruby

While working on jenabean I began to wonder if dynamic languages had features that would make editing ontology instance data easier.  The traditional method for bindind a schemas to objects normally involves creating some kind of binding descriptor file in XML.  The tedium of that process is well known and so painfull that it may not even continue to be a viable pattern.  What I discovered is that it’s rather easy to manipulate RDF files from Ruby (JRuby to be exact) using Jena.  The technique I decided upon was to dynamically create classes that map to RDF types in the ontology.  This is a type of “metaprogramming” that is familiar to rails developers, and to be fair, I spent a few hours reading ActiveRecord code to glean some ideas on how this type of binding works.  So let’s get started.  Here’s what you’ll need to follow along in a hands on manner:

JRuby comes as a zip or tar, just expand it in your favorite open source project directory.  You’ll need to have jena.rb and song.owl in your current directory as well.  Instead of the customary “hello world” I’d rather we use interactive ruby, it’ll make it easier to see what’s happening and play around a bit with jena.  JRuby comes with an executable called “jirb”.  Run it like this…

jirb interactive ruby shell

Next we need to tell JRuby where to find our Jena libs.  Somebody please correct me if I’m wrong, but this is the easiest way I’ve found, cut-n-past this into your interactive shell:

require '../jenabean/jenalib/jena.jar'
require '../jenabean/jenalib/log4j-1.2.12.jar'
require '../jenabean/jenalib/commons-logging-1.1.jar'
require '../jenabean/jenalib/concurrent.jar'
require '../jenabean/jenalib/icu4j_3_4.jar'
require '../jenabean/jenalib/stax-api-1.0.jar'
require '../jenabean/jenalib/wstx-asl-3.0.0.jar'
require '../jenabean/jenalib/xercesImpl.jar'
require '../jenabean/jenalib/xml-apis.jar'
require '../jenabean/jenalib/iri.jar'
require '../jenabean/dist/jenabean.jar'
require 'jena'

You’ll need to modify the paths to suit the location of your jena installation. The require ‘jena’ line loads jena.rb, assuming it’s in your current working directory.  Now we’re going to use the Jena helper to create a model, and then print it out just to demonstrate that all’s well.  Notice we’re able to access the familiar java singleton class “System”…


rb(main):013:0> m = Jena.create_model
irb(main):014:0> m.write(System.out)
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#”
    xmlns:owl=”http://www.w3.org/2002/07/owl#”
    xmlns:daml=”http://www.daml.org/2001/03/daml+oil#”
    xmlns:rdfs=”http://www.w3.org/2000/01/rdf-schema#” >
</rdf:RDF>
=> #<Java::ComHpHplJenaRdfModelImpl::ModelCom:0×1af1915 @java_object=<ModelCom
 {} | >>

Now it’s time to read in the ontology, this time it’s 100% straight Jena access via our model instance…


irb(main):014:0> m.read('file:song.owl')

Sorry about the the verbose output…that’s not us, that’s jirb and jena. Jena’s OntModel has a terribly verbose toString() implementation, and since we’re interacting directly with Jena there’s not much we can do other than turning off echo, and I want that for some stuff we’re about to do. We’re about to…drum role…bind Ruby objects to our ontology so get out those XML editors. No, just kidding. Instead, cut-n-past the following lines into your ruby shell:


Jena.make(m,'http://example.org/music#Genre')
Jena.make(m,'http://example.org/music#Song')
Jena.make(m,'http://example.org/music#Composer')
Jena.make(m,'http://example.org/music#Instrument')
Jena.make(m,'http://example.org/music#Musician')
Jena.make(m,'http://example.org/music#Recording')

There, we’re done. Now we should have some ontology specific classes ready for us to work with. Jena.make finds the OntClasses at the specified URI’s and dynamically creates ruby classes for us. Yes, you have to be carefull with the URI’s, they have to be right on. (perhaps I need to create a utility to pull the urls out and store as constants). Now we can interact with the ontology in a structured way.


irb> jazz = Genre.new('http://example.org/genre/jazz')
a type of http://example.org/music#Genre
my uri is http://example.org/genre/jazz
bindings:
  hasName -> http://example.org/music#hasName
.
=>
irb(main):024:0>

Genre is a fullfledged ruby class. Genre.new creates a new isntance for us, given a URI, just like we normally do with Jena. Notice our new instance has a property called “hasName”…we can set it like this..


irb>jazz.hasName = "Jazz Music"

We can save the new individual by calling jazz.save, or save it to a new clean model, which will help us see exactly what happened:

irb(main):031:0> jazz.save_to(m2)
=> {"hasName"=>"Jazz music"}
irb(main):032:0> m2.write(System.out)
<rdf:RDF
    xmlns:j.0="http://example.org/music#”
    xmlns:rdf=”http://www.w3.org/1999/02/22-rdf-syntax-ns#”
    xmlns:owl=”http://www.w3.org/2002/07/owl#”
    xmlns:daml=”http://www.daml.org/2001/03/daml+oil#”
    xmlns:rdfs=”http://www.w3.org/2000/01/rdf-schema#” >
  <rdf:Description rdf:about=”http://jazz“>
    <j.0:hasName rdf:datatype=”http://www.w3.org/2001/XMLSchema#string”>Jazz mus
ic</j.0:hasName>
    <rdf:type rdf:resource=”http://example.org/music#Genre”/>
  </rdf:Description>
  <rdf:Description rdf:about=”http://example.org/music#Genre“>
    <rdf:type rdf:resource=”http://www.w3.org/2002/07/owl#Class”/>
  </rdf:Description>
</rdf:RDF>
=>

7 Comments, Comment or Ping

  1. Roger Marin

    Taylor, i am very impressed with what you’ve got so far, in fact, i plan to use this approach for my thesis project. Something that i was thinking, it would be cool if a groovy version of this could be made, i plan on working on it as soon as i get some free time, another cool idea was to somehow integrate it with grails that would make a really “groovy” platform for developing semantic web apps :)

    BTW: jenabean rocks! congrats on coming up with such a usable and easy to use API. i absolutely love it, i’m just starting with it but it definitely makes working with RDF a lot more fun.

    Cheers!.

  2. Mike

    Taylor,
    I am using your helper class and it’s really great to be able to integrate jena into ruby like this. Right now I am just having a problem. When I try to save a model, I keep getting the error :

    undefined method `individual’ for #

    It says that, the following line in your code is the problem:

    185: value.each do |v| i.addProperty(ont_property, v.individual(model)) end

    If I remove the call to “individual(model)”, it’s working fine. Can you help me? Thanks in advance.. Mike

  3. admin

    Hi Mike, I’ll give it a look. Perhaps you can post a little example that causes the issue, that’ll help me out.

  4. Mike

    Hey,
    I finally switched to directly using the Jena Java classes with JRuby. But the problem always appeared, when I used ontologies including the property “equivalentProperty” like this:

    If I had an instance of the property like this,

    Horizontal: 49° (total 149°)Vertical: 37° (total 87°)

    your class tried to use the individual-method on the string, which caused the error.
    Hope that might help you,
    Mike

  5. Mike

    Ok, seems like tags are not displayed here…
    So again, the property-definition looks like this:

    []
    []
    []
    []
    []
    []

    The property-instance like this:

    []
    Horizontal: 49° (total 149°)Vertical: 37° (total 87°)
    []

  6. Mike

    Incredible. Last try. I’m sorry. Please delete what you don’t wanna see her…

    owlDatatypeProperty rdfID is viewingAngle
    rdftype rdfresource is &owl;FunctionalProperty
    rdfsdomain rdfresource is #Item
    rdfsrange rdfresource is &xsd;string”
    owlequivalentProperty rdfresource is &ath;viewingAngle
    owlDatatypeProperty

    and

    viewingAngle
    Horizontal: 49° (total 149°)Vertical: 37° (total 87°)
    viewingAngle

    If this one is not working again, just send me a mail. If it’s hardly readyble, i’m sorry..

  7. Hi Mike, it looks like that property is not getting tagged as a datatype property, based on what Jena reports on p.getDatatypeProperty()…therefore the JRuby code tries to find or create an individual for the object of the assertion…still working on it.

    Taylor

Reply to “Jena Ruby bindings: accessing Jena’s feature rich RDF api from Ruby”

Before you go

places we like