06 November 2009

Handling RDF Statements with Apache Velocity

This post is about using Apache Velocity ( a Java-based template engine ) and the Jena RDF library. My aim was to use Velocity to handle the content of one or more RDF store without compiling, just by using a custom velocity template. This idea was much inspired by Egon Willighagen's posts where the RDF was handled with a scripting engine embedded in bioclipse. It also seems that I'm not the first who had this idea of using Velocity+RDF: see [here].
OK, my experimental source code for the program JenaVelocity is available here:

Describing the RDFstores


On the command line, one (or more) RDF dataset is described as a JSON document. In the following example this is a remote file, but it could also be the description of a persistent database, a N3 file, etc... This RDF file will also be used later for resolving some names from the bio2rdf repository, this is why I also added a table for the prefix mappings. This RDF model will be inserted in the VelocityContext under the name "$store1"
[
{
"name": "store1",
"url":"http://www.lri.fr/~pietriga/foaf.rdf",
"prefix-mapping":{
"uniprot":"http://bio2rdf.org/uniprot:"
}
}
]

Example 1

In the following example: all the RDFstores are inserted in the VelocityContext as $rdfstores. For each rdfstore a HTML list is created. The list contains the names of all the infividuals of the FOAF file described previously.
<html><body>
#set($RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#")
#set($FOAF="http://xmlns.com/foaf/0.1/")
<h1>Staff</h1>
<ul>
#foreach($store in $rdfstores)
#set($pred = ${store.model.createProperty("${FOAF}","name")})
#foreach($stmt in
${store.model.listStatements(null,${store.model.createProperty("${FOAF}","name")},null,null)})
<li>${stmt.object.string}</li>
#end
</ul></body></html>

After running JenaVelocity, I got the following result:

Staff



  • Jean-Daniel Fekete

  • Chris Bizer

  • Caroline Appert

  • Ralph Swick

  • Vincent Quint

  • Jean-Yves Vion-Dury

  • Yves Guiard

  • Eric Miller

  • Renaud Blanch

  • Emmanuel Pietriga

  • Jose Kahan

  • Eric Prud'hommeaux

  • Catherine Letondal

  • Olivier Chapuis

  • Michel Beaudouin-Lafon

  • Nicolas Roussel

  • Ryan Lee

  • Wendy Mackay

Example 2


Here, I've inserted an object called $sparql in the VelocityContext. This object is used to send a SPARQL query to the bio2rdf sparql endpoint and the Statements related to the rdf:type http://bio2rdf.org/ns/uniprot:Strain are fetched and displayed in a HTML table. For each Resource, we try to get a short form of its URI using our previously defined $store1. It the object of a statement is a literal, the quoted string is printed.
<html><body>
#set($RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#")
#set($FOAF="http://xmlns.com/foaf/0.1/")
<h1>Strains</h1>
<table>
#foreach($row in
$sparql.select("http://quebec.bio2rdf.org/sparql","select distinct ?s
?p ?o where { ?s a <http://bio2rdf.org/ns/uniprot:Strain> . ?s ?p ?o}
LIMIT 100
"))
<tr>
<td><a href="${row.get("s").getURI()}">${store1.shortForm(${row.get("s").getURI()})}</a></td>
<td><a href="${row.get("p").getURI()}">${store1.shortForm(${row.get("p").getURI()})}</a></td>
<td>#if(${row.get("o").isResource()})
<a href="${row.get("o").getURI()}">${store1.shortForm(${row.get("o").getURI()})}</a>
#else
<span>"$row.get("o").string"</span>
#end</td>
</tr>
#end
</table>
#end
</body></html>

After running JenaVelocity, I got the following result:

Strains

uniprot:Q8C7G5_5rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7G5_5dc:title"C57BL/6J"
uniprot:Q8C7G5_8rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7G5_8dc:title"FVB/N"
uniprot:Q8C7H1_2rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7H1_2dc:title"C57BL/6J"
uniprot:Q8C7K6_2rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7K6_2dc:title"C57BL/6J"
uniprot:Q8C7K6_5rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7K6_5dc:title"C57BL/6"
uniprot:Q8C7M3_2rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7M3_2dc:title"C57BL/6J"
uniprot:Q8C7M3_Ardf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7M3_Adc:title"C57BL/6"
uniprot:Q8C7N7_2rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7N7_2dc:title"C57BL/6J"
uniprot:Q8C7N7_3rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7N7_3dc:title"NOD"
uniprot:Q8C7N7_7rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7N7_7dc:title"C57BL/6"
uniprot:Q8C7Q4_3rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7Q4_3dc:title"C57BL/6J"
uniprot:Q8C7R4_2rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7R4_2dc:title"C57BL/6J"
uniprot:Q8C7R4_5rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7R4_5dc:title"C57BL/6"
uniprot:Q8C7U1_2rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7U1_2dc:title"C57BL/6J"
uniprot:Q8C7U1_3rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7U1_3dc:title"NOD"
uniprot:Q8C7U1_7rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7U1_7dc:title"FVB/N"
uniprot:Q8C7U7_4rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7U7_4dc:title"C57BL/6J"
uniprot:Q8C7U7_5rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7U7_5dc:title"NOD"
uniprot:Q8C7V3_4rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7V3_4dc:title"C57BL/6J"
uniprot:Q8C7V3_7rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7V3_7dc:title"C57BL/6"
uniprot:Q8C7V8_2rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7V8_2dc:title"C57BL/6J"
uniprot:Q8C7V8_3rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7V8_3dc:title"NOD"
uniprot:Q8C7V8_8rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7V8_8dc:title"C57BL/6"
uniprot:Q8C7W7_2rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7W7_2dc:title"C57BL/6J"
uniprot:Q8C7W7_3rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7W7_3dc:title"NOD"
uniprot:Q8C7W7_8rdf:typehttp://bio2rdf.org/ns/uniprot:Strain
uniprot:Q8C7W7_8dc:title"Czech II"
(...)(...)(...)


Conclusion: Velocity templates allow to handle and render some RDF data without compiling anything. However, a prior knowledge of the Jena API is required.

That's it.

Pierre