View on GitHub

Groovyrdf

Library for building and processing RDF data with Groovy

Download this project as a .zip file Download this project as a tar.gz file

User guide - groovyrdf

Versions 0.2.x

groovyrdf is a groovy library that helps you building and consuming RDF data in a "groovy" way. For building RDF see section "Building RDF". If you want to process RDF data or even load linked data resoures see section "Loading & consuming RDF".

Building RDF

General syntax

rdfBuilderInstance {
  resourceUri {
    a typeUri
    predicateUri value
    predicateUri list
    predicateUri value, [lang: language]
    predicateUri {
      resourceUri {
        // more statements if needed
      }
    }
  }
}

/*
rdfBuilderInstance: Instance of RdfBuilder
resourceUri: String that contains a URI of a resource
a: Keyword for a type property
typeUri: String that contains a URI of a type
predicateUri: String that contains a URI of a predicate
value: a String or a primitive
list: a list of values
lang: Keyword for setting a language tag
language: String containing a language tag
*/

Code Examples

Instantiate RdfBuilder

Currently a RdfBuilder based on the Jena-Framework is supported:

def rdfBuilder = new JenaRdfBuilder()

You may use a BuilderFactory to instantiate a RdfBuilder:

def rdfBuilder = new JenaRdfBuilderFactory().newInstance()

RdfBuilder is not thread-safe and cannot be reused for multiple builds.

Build & write RdfData

def rdfBuilder = new JenaRdfBuilder()

RdfData rdfData = rdfBuilder {
  // statements
}

You can export it to TURTLE like this:

rdfData.write(System.out, RdfDataFormat.TURTLE)

Simple statement

RdfData rdfData = rdfBuilder {
  "http://example.com/resource/alice" {
    "http://example.com/vocab/name" "Alice"
  }
}

is equivalent to the following RDF in TURTLE syntax:

<http://example.com/resource/alice>
  <http://example.com/vocab/name> "Alice".

RDF types

Use the "a" keyword as a shortcut for the rdf:type predicate:

RdfData rdfData = rdfBuilder {
  "http://example.com/resource/alice" {
     a "http://example.com/vocab/Person"
    "http://example.com/vocab/name" "Alice"
  }
}

is equivalent to the following RDF in TURTLE syntax:

<http://example.com/resource/alice>
  a <http://example.com/vocab/Person>;
  <http://example.com/vocab/name> "Alice".

Multiple literals

Just pass a groovy list to assign multiple values:

def names = ["Alice", "Julia"]

RdfData rdfData = rdfBuilder {
  "http://example.com/resource/alice" {
     a "http://example.com/vocab/Person"
    "http://example.com/vocab/name" names
  }
}

is equivalent to the following RDF in TURTLE syntax:

<http://example.com/resource/alice>
  a <http://example.com/vocab/Person>;
  <http://example.com/vocab/name> "Alice", "Julia".

Language tags

You can easily assign a language to a literal like this:

RdfData rdfData = rdfBuilder {
  "http://example.com/resource/alice" {
     a "http://example.com/vocab/Person"
    "http://example.com/vocab/name" "Alice", [lang: "en"]
  }
}

is equivalent to the following RDF in TURTLE syntax:

<http://example.com/resource/alice>
  a <http://example.com/vocab/Person>;
  <http://example.com/vocab/name> "Alice"@en.

Nested resources

Of course you can nest resources:

RdfData rdfData = rdfBuilder {
  "http://example.com/resource/alice" {
     a "http://example.com/vocab/Person"
    "http://example.com/vocab/name" "Alice"
    "http://example.com/vocab/knows" {
      "http://example.com/resource/bob" {
         a "http://example.com/vocab/Person"
        "http://example.com/vocab/name" "Bob"
      }
    }
  }
}

is equivalent to the following RDF in TURTLE syntax:

<http://example.com/resource/alice>
  a <http://example.com/vocab/Person>;
  <http://example.com/vocab/name> "Alice";
  <http://example.com/vocab/knows> <http://example.com/resource/bob>.

<http://example.com/resource/bob>
  a <http://example.com/vocab/Person>;
  <http://example.com/vocab/name> "Bob".

Adding WebIDs

You can easily add a WebID to a resource:

RdfData rdfData = rdfBuilder {
  "http://example.com/resource/alice" {
    publicKey (
      '#alicePublicKey',
      label: 'Public Key of Alice',
      modulus: '2cbf8fff963dea33ee7d4f007ae',
      exponent: 65537
    )
  }
}

is equivalent to the following RDF in TURTLE syntax:

<http://example.com/resource/alice>
  <http://www.w3.org/ns/auth/cert#key>
    <#alicePublicKey>.

<#alicePublicKey>
  a <http://www.w3.org/ns/auth/cert#RSAPublicKey>;
  <http://www.w3.org/2000/01/rdf-schema#label> "Public Key of Alice";
  <http://www.w3.org/ns/auth/cert#exponent> 65537;
  <http://www.w3.org/ns/auth/cert#modulus>
    "2cbf8fff963dea33ee7d4f007ae"^^<http://www.w3.org/2001/XMLSchema#hexBinary> .

Using namespaces

The code will be much clearer if you use namespaces:

def vocab = new RdfNamespace("http://example.com/vocab/")

Any call to a property of vocab will result in a String of the form "http://example.com/vocab/property"

vocab.anything == "http://example.com/vocab/anything"

The "Nested resources" example with the help of this namespace:

RdfData rdfData = rdfBuilder {
  "http://example.com/resource/alice" {
     a vocab.Person
    "$vocab.name" "Alice"
    "$vocab.knows" {
      "http://example.com/resource/bob" {
         a vocab.Person
        "$vocab.name" "Bob"
      }
    }
  }
}
Why this strange "$vocab.name"-Syntax?

Because RdfBuilder actually has to call a method named "http://example.com/vocab/name" to build the statement. If we just wrote vocab.name Groovy would try to call a method on the resulting string instead of calling a method that is named like the value in the string. You will get used to it ;-)

Be dynamic

Of course when using a scripting language, you want to build your RDF dynamically based on some data structures. Here is an example with a Person class:

class Person {
  String uri
  String name
  List<Person> friends
}

This will generate RDF data with the name of a person and all their friends:

Person person = ... // whatever you program does to set up a person

def vocab = new RdfNamespace("http://example.com/vocab/")

RdfData rdfData = rdfBuilder {
  "$person.uri" {
     a vocab.Person
    "$vocab.name" person.name
    "$vocab.knows" {
      person.friends.each { friend ->
        "$friend.uri" {
           a vocab.Person
          "$vocab.name" friend.name
        }
      }
    }
  }
}

Take a look at the unit tests

For more examples a look at the groovyrdf unit tests might be helpful:

https://github.com/angelo-v/groovyrdf/tree/master/src/test/groovy/de/datenwissen/util/groovyrdf

Loading & consuming RDF

General syntax

RdfResource resoure = rdfLoaderInstance.loadResource(resourceUri)
resource.uri // get the resources URI
resource.type // get the RDF type URI of the resource
resource(predicateUri) // get the value/object of a predicate
resource."$predicateUri" // another way to get the value/object of a predicate
resource(predicateUri, language) // get the value in a specific language

/*
rdfLoaderInstance: Instance of RdfLoader
resourceUri: String that contains a URI of a resource
predicateUri: String that contains a URI of a predicate
language: String containing a language tag
*/

Code Examples

Given the following data is provided under http://example.com/resource/alice

<http://example.com/resource/alice>
  a <http://example.com/vocab/Person> ;
  <http://example.com/vocab/name> 'Alice' ;
  <http://example.com/vocab/knows> <http://example.com/resource/bob>.

<http://example.com/resource/alice.rdf>
  <http://example.com/vocab/dateCreated> '2012-12-12' .

Instantiate RdfLoader

Currently a RdfLoader based on the Jena-Framework is supported:

def rdfLoader = new JenaRdfLoader()

A loader may be reused for multiple requests.

Load RDF document

The RDF data can be retrieved like this:

  RdfData rdfData = rdfLoaderInstance.load('http://example.com/resource/alice')

The loader uses content-negotiation, so that you do not have to care about the RDF data format used by the server you are querying.

Accessing RDF resources

RDF resources can be accessed by there uri in two different ways:

RdfData rdfData = rdfLoaderInstance.load('http://example.com/resource/alice')
RdfResource alice = rdfData.'http://example.com/resource/alice' // first way
RdfResource aliceDoc = rdfData('http://example.com/resource/alice.rdf') // second way

Load RDF resource directly

If you are interested in only one specific resource, you may retrieve it directly via loadResource:

RdfResource alice = rdfLoaderInstance.loadResource('http://example.com/resource/alice')

Listing subjects

You can get a list of all subject resources using the listSubject()-Method:

RdfData rdfData = rdfLoaderInstance.load('http://example.com/resource/alice')
List<RdfResource> resources = rdfData.listSubjects()
['http://example.com/resource/alice', 'http://example.com/resource/alice.rdf'] == resources*.uri

You may only list subjects of a specific RDF type:

List<RdfResource> resources = rdfData.listSubjects('http://example.com/vocab/Person')
['http://example.com/resource/alice'] == resources*.uri

Accessing properties

Accessing properties works the same ways as accessing the resources themselves:

RdfResource alice = rdfData.'http://example.com/resource/alice'
RdfResource aliceDoc = rdfData('http://example.com/resource/alice.rdf')
alice.'http://example.com/vocab/name' == 'Alice'
aliceDoc('http://example.com/vocab/dateCreated') == '2012-12-12'

You can add a preferred language to get the property in that language, if available:

alice ('http://example.com/vocab/name', 'en') == 'Alice'

Listing properties

You can list the available properties of a resource:

RdfResource alice = rdfData.'http://example.com/resource/alice'
Set<String> properties = alice.listProperties ()
['http://example.com/vocab/name', 'http://example.com/vocab/knows'] as Set == properties

Be aware that the RDF type is excluded from that list, although it may be present!

Single value vs. list of values

For any RDF predicate may exist multiple values. groovyrdf returns a single value, if there is only one, and a Set of vales, if there are multiple values for the given predicate.

Given RDF:

<http://example.com/resource/alice>
  <http://example.com/vocab/name> "Alice" ;
  <http://example.com/vocab/nick> "Ally", "Lissy";

Accessing the vocab:name predicate will return only one value, while accessing vocab:nick returns a Set:

RdfResource alice = rdfData.'http://example.com/resource/alice'
alice.'http://example.com/vocab/name' == 'Alice'
alice.'http://example.com/vocab/nick' == ['Ally', 'Lissy'] as Set

Accessing linked resources

If the value of a property is a resoure, you will get a RdfResource instance:

RdfResource bob = alice.'http://example.com/vocab/knows'

You will get a Set of RdfResource instances, if there are multiple values!

Note that you cannot access properties of the linked resource, that are not provided in the current RDF data:

bob.'http://example.com/vocab/name' == null

But you may explicitly load the linked resource and process the loaded data afterwards:

bob = rdfLoader.loadResource (bob.uri)
bob.'http://example.com/vocab/name' == 'Bob'

Final words

And now, be creative using groovyrdf to build and process RDF data "the groovy way". Questions, ideas and any feedback may be sent to angelo.veltens@online.de

To contribute to groovyrdf just fork and sent a pull request at github: https://github.com/angelo-v/groovyrdf