Iterate over RDF with Jena

3.6k views Asked by At

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?

2

There are 2 answers

0
Joshua Taylor On BEST ANSWER

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
…
1
Blub On

What is exactly your problem? You can get all triples like this:

StmtIterator it =  model.listStatements();
while (it.hasNext()) {
     Statement stmt = it.next();
     // do your stuff with the Statement (which is a triple)
}

Does this solve your problem?

You can select specific triples with SimpleSelector. You provide three arguments: subject, predicate, object. You can leave some null, which means "any".

So if you wanted to have all triples with the binaryAvailability property (but any object or subject), you would do:

Selector selector = new SimpleSelector(null, model.getProperty(binaryAvailabilityURI), (RDFNode) null);  // you need to cast the last null as otherwise the method is ambigious
StmtIterator it =  model.listStatements(selector);

Try iterating like this to get your blocks. I haven't tested this, but I think it should work:

// select all resources that are of type Parking
ResIterator blockIt = model.listResourcesWithProperty(null, model.getProperty("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), model.getResource(parkingUri);
while (blockIt.hasNext()) {
    Resource currentParking = blockIt.next();
    // select all statements that have the current Parking entity as subject
    StmtIterator it = model.listStatements(currentParking, null, (RDFNode) null);
    while (it.hasNext()) {
         // here you will get all triples for the current Parking block
    }
}