Iterate over RDF with Jena

java, jena, rdf, turtle-rdf

Solution

If you actually want to manually iterate over the data that you're concerned with and select what you want by hand, then you can do that using the Jena Model API. However, I think it would be easier to select the data using a SPARQL query and then iterate over the ResultSet that that produces. The rest of this answer shows how you could implement each of these approaches.

Using the Jena Model API

If you want to do this manually, you can do something like this (the comments explain exactly what's going on):

import java.io.IOException;
import java.io.InputStream;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;


public class ParkingExample {
    public static void main(String[] args) throws IOException {
        // Read the model from whereever it comes from.  For this example, 
        // I made a local copy in parking.ttl and so I'm loading it as a 
        // resource.  You're already able to load the model, so this 
        // isn't so important.
        Model model = ModelFactory.createDefaultModel();
        try ( final InputStream in = ParkingExample.class.getResourceAsStream( "/parking.ttl" ) ) {
            model.read( in, null, "TTL" );
        }

        // Create some properties in advance for convenience.
        final Property g_lat = model.createProperty( "http://www.w3.org/2003/01/geo/wgs84_pos#lat" );
        final Property g_long = model.createProperty( "http://www.w3.org/2003/01/geo/wgs84_pos#long" );
        final Property p_binaryAvailability = model.createProperty( "http://parking.kmi.open.ac.uk/ontologies/parking#binaryAvailability" );

        // In N3, Turtle, and SPARQL, `a` is a shorthand for rdf:type.  That means
        // that each of the triples of the form 
        //
        //   <http://parking.kmi.open.ac.uk/data/parks/4934.1> a o:Parking
        //
        // is saying that the subject has rdf:type o:Parking.  That's how we'll retrieve
        // these resources.  We'll select subjects that have o_Parking as a value for 
        // rdf:type.  We'll predefine o_Parking for convenience.
        final Resource o_Parking = model.createResource( "http://linkedgeodata.org/ontology/Parking" );

        // Now we get an iterator over the resources that have type o_Parking.
        for ( final ResIterator res = model.listResourcesWithProperty( RDF.type, o_Parking ); res.hasNext(); ) {
            final Resource r = res.next();

            // For each one of them, it appears that they have a mandatory lat, lon, and binAvailability, 
            // so we can retrieve those values, assuming that they'll be there.
            final float lat = r.getRequiredProperty( g_lat ).getObject().asLiteral().getFloat();
            final float lon = r.getRequiredProperty( g_long ).getObject().asLiteral().getFloat();
            final boolean binAvailibility = r.getRequiredProperty( p_binaryAvailability ).getObject().asLiteral().getBoolean();

            // Some of the Parkings have an rdfs:label, but not all of them do.  For this, we'll retrieve
            // a statement, but since there might not be one, we have to check whether it's null.  If it 
            // is, then we'll make the label null, but otherwise we'll get the string value out of it.
            final Statement s = r.getProperty( RDFS.label );
            final String label = s == null ? null : s.getObject().asLiteral().getString();

            // Now you can do whatever you want with these values.  You could create an instance of another 
            // class, for instance.. I'll just print the values out.
            System.out.println( r + ":" +
                    "\n\tlatitude: " + lat +
                    "\n\tlongitude: " + lon +
                    "\n\tavailibility: " + binAvailibility +
                    "\n\tlabel: " + label );
        }
    }
}

This produces output like this:

http://parking.kmi.open.ac.uk/data/parks/4751.3:
    latitude: 50.85094
    longitude: -0.983707
    availibility: true
    label: null
http://parking.kmi.open.ac.uk/data/parks/41378.7:
    latitude: 50.851734
    longitude: -0.949425
    availibility: true
    label: null
http://parking.kmi.open.ac.uk/data/parks/25125:
    latitude: 50.824787
    longitude: -1.083873
    availibility: true
    label: null
…

Using a SPARQL query

I think that this is much easier to do using a SPARQL query. A SPARQL query lets your write the the exactly type of data that you're looking for, including optional values, and you can use the ResultSet API to get the particular values that you want back. In this case, you'd want a query like:

prefix d: <http://www.w3.org/2001/XMLSchema#>
prefix p: <http://parking.kmi.open.ac.uk/ontologies/parking#>
prefix s: <http://www.w3.org/2000/01/rdf-schema#>
prefix g: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix o: <http://linkedgeodata.org/ontology/>

select ?parking ?lat ?lon ?availability ?label where {
  ?parking a o:Parking ;
             g:lat ?lat ;
             g:long ?lon ;
             p:binaryAvailability ?availability .
  optional { ?parking s:label ?label }
}

Here's how you could use it in code:

import java.io.IOException;
import java.io.InputStream;

import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;


public class ParkingExample {
    public static void main(String[] args) throws IOException {

        final String query = 
         "prefix d: <http://www.w3.org/2001/XMLSchema#>\n" +
         "prefix p: <http://parking.kmi.open.ac.uk/ontologies/parking#>\n" +
         "prefix s: <http://www.w3.org/2000/01/rdf-schema#>\n" +
         "prefix g: <http://www.w3.org/2003/01/geo/wgs84_pos#>\n" +
         "prefix o: <http://linkedgeodata.org/ontology/>\n" +
         "\n" +
         "select ?parking ?lat ?lon ?availability ?label where {\n" +
         "  ?parking a o:Parking ;\n" +
         "             g:lat ?lat ;\n" +
         "             g:long ?lon ;\n" +
         "             p:binaryAvailability ?availability .\n" +
         "  optional { ?parking s:label ?label }\n" +
         "}";

        Model model = ModelFactory.createDefaultModel();
        try ( final InputStream in = ParkingExample.class.getResourceAsStream( "/parking.ttl" ) ) {
            model.read( in, null, "TTL" );
        }

        final QueryExecution exec = QueryExecutionFactory.create( query, model );
        final ResultSet rs = exec.execSelect();
        while ( rs.hasNext() ) {
            final QuerySolution qs = rs.next();
            System.out.println( qs.get( "parking" ) +
                    "\n\t" + qs.get( "lat" ) +
                    "\n\t" + qs.get( "lon" ) +
                    "\n\t" + qs.get( "availability" ) +
                    "\n\t" + qs.get( "label" ));
        }
    }
}

The output is:

http://parking.kmi.open.ac.uk/data/parks/38470.10
    50.849454^^http://www.w3.org/2001/XMLSchema#double
    -0.939969^^http://www.w3.org/2001/XMLSchema#double
    true^^http://www.w3.org/2001/XMLSchema#boolean
    null
http://parking.kmi.open.ac.uk/data/parks/28356.7
    50.997992^^http://www.w3.org/2001/XMLSchema#double
    -0.926222^^http://www.w3.org/2001/XMLSchema#double
    true^^http://www.w3.org/2001/XMLSchema#boolean
    null
http://parking.kmi.open.ac.uk/data/parks/33791.11
    50.894162^^http://www.w3.org/2001/XMLSchema#double
    -0.927854^^http://www.w3.org/2001/XMLSchema#double
    true^^http://www.w3.org/2001/XMLSchema#boolean
    Locked at 17:30
…

Problem

I am working on a project for my studies right now and I need some help. Basically, I need to convert the following RDF to representations of a Java class. I read the RDF to a model and from there I am stuck. ``` StringReader in = new StringReader(resultTemp); Model model = ModelFactory.createDefaultModel(); model.read(in, null, "TURTLE"); ``` I tried working with the function listSubjectsWithProperty(Property arg0, RDFNode arg1) and the StmtIterator but I just can't figure it out. I would greatly appreciate some help. RDF: ``` @prefix d: <http://www.w3.org/2001/XMLSchema#> . @prefix p: <http://parking.kmi.open.ac.uk/ontologies/parking#> . @prefix s: <http://www.w3.org/2000/01/rdf-schema#> . @prefix g: <http://www.w3.org/2003/01/geo/wgs84_pos#> . @prefix o: <http://linkedgeodata.org/ontology/> . <http://parking.kmi.open.ac.uk/data/parks/4751.3> a o:Parking ; g:lat "50.8509406"^^d:double ; g:long "-0.983707"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/4934.6> a o:Parking ; g:lat "50.8737457"^^d:double ; g:long "-0.9731118"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/4934.8> a o:Parking ; g:lat "50.873617"^^d:double ; g:long "-0.9722267"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/4934.3> a o:Parking ; g:lat "50.8696495"^^d:double ; g:long "-0.9767757"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/4934.2> a o:Parking ; g:lat "50.8698594"^^d:double ; g:long "-0.9775482"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/4934.1> a o:Parking ; g:lat "50.8704349"^^d:double ; g:long "-0.9774731"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/4934.7> a o:Parking ; g:lat "50.8732887"^^d:double ; g:long "-0.9725968"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/28356.7> a o:Parking ; g:lat "50.997992"^^d:double ; g:long "-0.926222"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/40865.5> a o:Parking ; g:lat "50.995467"^^d:double ; g:long "-1.036603"^^d:double ; s:label "Workhouse Lane" ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/7185.1> a o:Parking ; g:lat "50.9885711"^^d:double ; g:long "-1.0811721"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/33791.10> a o:Parking ; g:lat "50.887628"^^d:double ; g:long "-0.929626"^^d:double ; s:label "Locked at 17:30" ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/20810.1> a o:Parking ; g:lat "50.891515"^^d:double ; g:long "-0.964029"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/33791.11> a o:Parking ; g:lat "50.894162"^^d:double ; g:long "-0.927854"^^d:double ; s:label "Locked at 17:30" ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/41308.7> a o:Parking ; g:lat "50.848336"^^d:double ; g:long "-0.937472"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/41308.6> a o:Parking ; g:lat "50.849124"^^d:double ; g:long "-0.937969"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/38470.10> a o:Parking ; g:lat "50.849454"^^d:double ; g:long "-0.939969"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/33030.4> a o:Parking ; g:lat "50.850708"^^d:double ; g:long "-0.913150"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/33030.3> a o:Parking ; g:lat "50.850421"^^d:double ; g:long "-0.914416"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/41378.7> a o:Parking ; g:lat "50.851734"^^d:double ; g:long "-0.949425"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/23937.9> a o:Parking ; g:lat "50.854045"^^d:double ; g:long "-0.979164"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/23834.6> a o:Parking ; g:lat "50.849214"^^d:double ; g:long "-0.987087"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/23937.8> a o:Parking ; g:lat "50.847012"^^d:double ; g:long "-0.986388"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/23937.7> a o:Parking ; g:lat "50.845044"^^d:double ; g:long "-0.989708"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/23937.12> a o:Parking ; g:lat "50.844084"^^d:double ; g:long "-1.008944"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/30510.6> a o:Parking ; g:lat "50.821892"^^d:double ; g:long "-0.983163"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/30554.10> a o:Parking ; g:lat "50.822039"^^d:double ; g:long "-0.982497"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/25125.2> a o:Parking ; g:lat "50.825640"^^d:double ; g:long "-1.078993"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/25125.1> a o:Parking ; g:lat "50.824621"^^d:double ; g:long "-1.082243"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/25125> a o:Parking ; g:lat "50.824789"^^d:double ; g:long "-1.083873"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/7345.6> a o:Parking ; g:lat "50.8249235"^^d:double ; g:long "-1.0734443"^^d:double ; s:label "Cycle-World" ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/21282> a o:Parking ; g:lat "50.836295"^^d:double ; g:long "-1.071699"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/25113.1> a o:Parking ; g:lat "50.829433"^^d:double ; g:long "-1.065990"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/25125.5> a o:Parking ; g:lat "50.834706"^^d:double ; g:long "-1.074678"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/29282.1> a o:Parking ; g:lat "50.836060"^^d:double ; g:long "-1.075153"^^d:double ; p:binaryAvailability "true"^^d:boolean . <http://parking.kmi.open.ac.uk/data/parks/41323.3> a o:Parking ; g:lat "50.853264"^^d:double ; g:long "-0.990290"^^d:double ; p:binaryAvailability "true"^^d:boole...` ``` Hi there, I need to iterate over every one of theses blocks: ``` <http://parking.kmi.open.ac.uk/data/parks/4751.3> a o:Parking ; g:lat "50.8509406"^^d:double ; g:long "-0.983707"^^d:double ; p:binaryAvailability "true"^^d:boolean . ``` Is there some iterator or other method which allows me to do so?

Original source