Using RDF::Redland On Debian

This had me fooled for a few hours, so I thought i’d just record it here incase anyone else is having the same problem.

When installing the RDF::Redland Perl modules to use Dave Beckett’s Redland on Debian with a custom compiled version of Perl, the libraries on CPAN will not work.

Instead, the version of Redland on the current Debian (11th September 2005) is version 1.0.0.2, so you need to download the redland-bindings for 1.0.0.2 on librdf.org, and compile them yourself by running perl Makefile.PL and make, make test and finally make install.

You should now be able to use the RDF::Redland modules successfully.

Parsing RDF In Perl With RDF::Simple

In this article I’ll describe how to parse and extract data from an RDF file using Jo Walsh‘s RDF::Simple::Parser module in Perl.

RDF::Simple::Parser does what it says on the tin, it provides a simple way to parse RDF. Unfortunately, that can make it hard to extract data. All it returns from a successful parse of the RDF file, is what Jo calls a “bucket-o-triples”. This is just an array of arrays. The first array contains an list of all the triples. The second array contains the actual triples broken down so Subject is in position 0, Predicate is in position 1 and Object in position 2.

Let’s define these as constants in Perl as they’re not going to be changing.

use constant SUBJECT => 0;
use constant PREDICATE => 1;
use constant OBJECT => 2;

I’m going to use my usual example of my parsing my FOAF file, and I’ll be extracting the addresses of my friend’s FOAF files from it. See the example in What Is An RDF Triple, for a full breakdown of this.

We’ll define the two predicates we need to look for as constants.

use constant KNOWS_PREDICATE => 'http://xmlns.com/foaf/0.1/knows';
use constant SEEALSO_PREDICATE => 'http://www.w3.org/2000/01/rdf-schema#seeAlso';

We need to load in the FOAF file, so we’ll take advantage of File::Slurp’s read_file method to do this and put it in a variable called $file.

my $file = read_file('./foaf.rdf');

Before we can use RDF::Simple::Parser, we need to create an instance of it. I’ll set the base address to www.robertprice.co.uk in this case.

my $parser = RDF::Simple::Parser->new(base => 'http://www.robertprice.co.uk/');

Now we have the instance, we can pass in our FOAF file for parsing and get back our triples.

my @triples = $parser->parse_rdf($file);

Let’s take a quick look at my FOAF file to get an example triple.

I know Cal Henderson, and this is represented in my FOAF file as…

<foaf:knows>
<foaf:Person>
<foaf:nick>Cal</foaf:nick>
<foaf:name>Cal Henderson</foaf:name>
<foaf:mbox_sha1sum>2971b1c2fd1d4f0e8f99c167cd85d522a614b07b</foaf:mbox_sha1sum>
<rdfs:seeAlso rdf:resource="http://www.iamcal.com/foaf.xml"/>
</foaf:Person>
</foaf:knows>

Using the RDF validator we can get a the list of triples represented in this piece of RDF.


Triple Subject Predicate Object
1 genid:ARP40722 http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Person
2 genid:ARP40722 http://xmlns.com/foaf/0.1/nick "Cal"
3 genid:ARP40722 http://xmlns.com/foaf/0.1/name "Cal Henderson"
4 genid:ARP40722 http://xmlns.com/foaf/0.1/mbox_sha1sum "2971b1c2fd1d4f0e8f99c167cd85d522a614b07b"
5 genid:ARP40722 http://www.w3.org/2000/01/rdf-schema#seeAlso http://www.iamcal.com/foaf.xml
6 genid:me http://xmlns.com/foaf/0.1/knows genid:ARP40722

The part we are interested are triples 5 and 6. We can see that triple 6 has Predicate value the same as our KNOWS_PREDICATE constant, and triple 5 has the Predicate value of our SEEALSO_PREDICATE constant. The part this links the two is that triple 6 has the Object value of triple 5’s Subject.

We know if we search for triples with the same predicate as our KNOWS_PREDICATE we’ll get triples that are to do with people I know. We can use Perl’s grep function to get these triples, then we can interate over them in a foreach loop.

foreach my $known (grep { $_->[PREDICATE] eq KNOWS_PREDICATE } @triples) {

We are only interest in the triples that have the same Subject as matching triple’s Object. Again, we can use grep to get these out so we can interate over them.

foreach my $triple (grep { $_->[SUBJECT] eq $known->[OBJECT] } @triples) {

Now we just need to make sure that the triple’s Predicate matches our SEEALSO_PREDICATE constant, and if it does, we can print out the value of it from it’s Object.

if ($triple->[PREDICATE] eq SEEALSO_PREDICATE) {
print $triple->[OBJECT], "n"
}

Let’s put this all together into a working example…

#!/usr/bin/perl -w
use strict;
use File::Slurp;
use RDF::Simple::Parser;
## constants defining position of triple components in
## RDF::Simple triple lists.
use constant SUBJECT => 0;
use constant PREDICATE => 1;
use constant OBJECT => 2;
## some known predicates.
use constant KNOWS_PREDICATE => 'http://xmlns.com/foaf/0.1/knows';
use constant SEEALSO_PREDICATE => 'http://www.w3.org/2000/01/rdf-schema#seeAlso';
## read in my foaf file and put it in $file.
my $file = read_file('./foaf.rdf');
## create a new parser, using my domain as a base.
my $parser = RDF::Simple::Parser->new(base => 'http://www.robertprice.co.uk/');
## parse my foaf file, and return a list of triples.
my @triples = $parser->parse_rdf($file);
## iterate over a list of triples matching the KNOWN_PREDICATE value.
foreach my $known (grep { $_->[PREDICATE] eq KNOWS_PREDICATE } @triples) {
## iteratve over a list of triples that have the same subject
## as one of our KNOWN_PREDICATE triples object.
foreach my $triple (grep { $_->[SUBJECT] eq $known->[OBJECT] } @triples) {
## find triples that match the SEEALSO_PREDICATE
if ($triple->[PREDICATE] eq SEEALSO_PREDICATE) {
## print out the object, should be the address
## of my friends foaf file.
print $triple->[OBJECT], "n"
}
}
}

The example will load in the FOAF file, parse it and print out any friends of mine that have FOAF files defined by the seeAlso predicate.

Querying RDF In Perl With RDFStore

Apart from RDF::Core and Redland, another option for parsing and querying RDF in Perl is RDFStore. This also provides the Perl RDQL::Parser module used by the very useful DBD::RDFStore driver.

Following on from the previous examples showing how to extract information from my FOAF file using RDF::Core (Query RDF In Perl With RDF::Core) and RDF::Redland (Querying RDF In Perl With RDF::Redland), here I’ll re-implement the query using RDFStore.

As a quick recap from the previous articles, here is the bit of RDF we want to extract information from.

<foaf:knows>
<foaf:Person>
<foaf:nick>Cal</foaf:nick>
<foaf:name>Cal Henderson</foaf:name>
<foaf:mbox_sha1sum>2971b1c2fd1d4f0e8f99c167cd85d522a614b07b</foaf:mbox_sha1sum>
<rdfs:seeAlso rdf:resource="http://www.iamcal.com/foaf.xml"/>
</foaf:Person>
</foaf:knows>

The solution used to extract the data from the RDF looks a lot more Perl-like than the previous examples we have seen.

If you have ever queried databases using SQL in Perl, then you have certainly come across the powerful DBI module. This abstracts the common database usage making it possible to very easily port your applications between various databases. One of the best things about using RDFStore is that it provides a DBD driver allowing you to use standard DBI methods when querying your RDF data. Unlike other modules that make you create triple stores and factory methods, RDFStore lets that be hidden from you.

To start with we’ll need to create a database handle using DBI and the DBD::RDFStore modules and store it in the variable $dbh.

my $dbh = DBI->connect("DBI:RDFStore:");

This creates a database on the fly, but we can connect to an existing database on a local or remote server if we so wished.

Now we need to create our RDQL query. It looks very similar to the query we used in the Redland example.

my $query = $dbh->prepare(<<QUERY);
SELECT ?name ?nick ?seeAlso ?mbox_sha1sum
FROM <file:foaf.rdf>
WHERE
(?x <rdf:type> <foaf:Person>),
(?x <foaf:name> ?name)
(?x <foaf:nick> ?nick)
(?x <rdfs:seeAlso> ?seeAlso)
(?x <foaf:mbox_sha1sum> ?mbox_sha1sum)
AND
(?nick eq 'Cal')
USING
foaf for <http://xmlns.com/foaf/0.1/>,
QUERY

Here we’re selecting the values the name, nick, seeAlso and mbox_sha1sum triples for a Person with the nick of Cal. We’ve explicitly set where our triples come from using the FROM clause. In this case, it’s the file foaf.rdf, which contains my FOAF information.

We have the query in the variable $query, so lets execute it.

$query->execute();

We can use standard DBI methods to fetch the data from our query. Here I’m going to create some bound variables to keep any matching data in.

my ($name, $seeAlso, $mbox_sha1sum, $nick);
$query->bind_columns($name, $nick, $seeAlso, $mbox_sha1sum);

Now we just have to fetch each row that matches our query and print them out.

while ($query->fetch()) {
print $name->toString, "n";
print $nick->toString, "n";
print $seeAlso->toString, "n";
print $mbox_sha1sum->toString, "n";
}

The values returned are either RDFStore::Literal or RDFStore::Resource objects, so we have to use their toString methods to print them.

To tidy up, we’ll finish our query and disconnect from our database.

$query->finish;
$dbh->disconnect;

That’s it! It really is as simple as that.

Let’s put this all together now to produce our final example code listing.

#!/usr/bin/perl -w
## An example showing how to use RDFStore and RDQL::Parser to
## extract information from a FOAF file.
## Copyright 2004 - Robert Price - http://www.robertprice.co.uk/
use strict;
use DBI;
## create a DBI connection to our NodeFactory.
my $dbh = DBI->connect("DBI:RDFStore:");
## prepare our query.
my $query = $dbh->prepare(<<QUERY);
SELECT ?name ?nick ?seeAlso ?mbox_sha1sum
FROM <file:foaf.rdf>
WHERE
(?x <rdf:type> <foaf:Person>),
(?x <foaf:name> ?name)
(?x <foaf:nick> ?nick)
(?x <rdfs:seeAlso> ?seeAlso)
(?x <foaf:mbox_sha1sum> ?mbox_sha1sum)
AND
(?nick eq 'Cal')
USING
foaf for <http://xmlns.com/foaf/0.1/>,
QUERY
## execute the query.
$query->execute();
## define some holding variables and bind them to our query results.
my ($name, $seeAlso, $mbox_sha1sum, $nick);
$query->bind_columns($name, $nick, $seeAlso, $mbox_sha1sum);
## while we have results being returned...
while ($query->fetch()) {
## print out the values.
## As these can be RDFStore::Literal or RDFStore::Resource's we
## need to use the toString method of these objects to print.
print $name->toString, "n";
print $nick->toString, "n";
print $seeAlso->toString, "n";
print $mbox_sha1sum->toString, "n";
}
## end the query and disconnect.
$query->finish;
$dbh->disconnect;

In conclusion, RDFStore provides a very clean and Perlish interface to querying RDF data. The code implements a DBD module allowing standard DBI methods to be used, making it quick and simple for Perl developers to learn and use effectively.

Querying RDF In Perl With RDF::Core

Extracting data from an RDF file seems like an easy job for Perl.

I have discussed how to parse RDF in Perl using the RDF::Core module before. In that example I used the getStmts functionality. This is fine for simple things, but it’s a bit messy. Thankfully RDF::Core provides us with a query language similar to RDQL to help us get the data we want.

Let’s take a quick look at my FOAF file for some example RDF to query. I know Cal Henderson, and this is represented in my FOAF file as…

<foaf:knows>
<foaf:Person>
<foaf:nick>Cal</foaf:nick>
<foaf:name>Cal Henderson</foaf:name>
<foaf:mbox_sha1sum>2971b1c2fd1d4f0e8f99c167cd85d522a614b07b</foaf:mbox_sha1sum>
<rdfs:seeAlso rdf:resource="http://www.iamcal.com/foaf.xml"/>
</foaf:Person>
</foaf:knows>

For a detailed explantion of the above RDF, have a look at my previous article – What Is An RDF Triple?

How could I find Cal’s foaf file using RDF::Core’s query language? It’s really simple and we’d use the following query.

select ?x->rdfs:seeAlso,
from ?x->foaf:nick{?y}
where ?y='Cal'

That just means we want to select the value of the triple rdfs:seeAlso where the parent triple has the foaf:nick of the value of Cal.

Why stop there? Lets get some more information on Cal.

select ?x->foaf:name, ?x->foaf:nick, ?x->rdfs:seeAlso, ?x->foaf:mbox_sha1sum
from ?x->foaf:nick{?y}
where ?y='Cal'

Now we have Cal’s name, nickname, address of his FOAF file and the checksum of his email address.

Let’s see how to get this all in Perl now.

We need to setup some RDF::Core objects and parse the FOAF file before we can query it. We’ll use this code to do so.

## list of known namespaces we might need.
my $namespaces = {
'foaf' => 'http://xmlns.com/foaf/0.1/',
'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'dc' => 'http://purl.org/dc/elements/1.1/',
};
## create our model and storage for triples.
my $store = RDF::Core::Storage::Memory->new;
my $model = RDF::Core::Model->new(Storage => $store);
## create node factory for query
my $factory = RDF::Core::NodeFactory->new;
## create our parse and parse the Source file.
my $parser = RDF::Core::Model::Parser->new(
Model => $model,
BaseURI => 'http://xmlns.com/foaf/0.1/',
Source => './foaf.rdf',
SourceType => 'file'
);
$parser->parse;

For a full explanation of the above code, have a look at my previous article – How To Parse RDF In Perl.

We now need to add the new code.

Firstly we need to a RDF::Core::Evaluator and a RDF::Core::Query object. These two objects handle the querying of the data held in our $model.

## create an evaluator based on our model, factory and namespaces.
my $evaluator = RDF::Core::Evaluator->new(
Model => $model,
Factory => $factory,
Namespaces => $namespaces,
);
## create a query object based on the evaluator.
my $query = RDF::Core::Query->new(Evaluator => $evaluator);

As we have a query object, we can just insert our query statement using it’s query method.

## run our query and save the results in $results.
my $results = $query->query("select ?x->foaf:name, ?x->foaf:nick, ?x->rdfs:seeAlso, ?x->foaf:mbox_sha1sum from ?x->foaf:nick{?y} where ?y='Cal'");

This executes the query and returns the results as a reference to an array in the $results variable. We need to use the first arrayref returned in $results to get the data we need. This will be a list of RDF::Core::Literal or RDF::Core::Resource objects. As these both inherit from RDF::Core::Node, let’s just use that object’s getLiteral method to return the string values of the data we need and print it out.

## go over the results and print the data out.
foreach my $result (@{$results->[0]}) {
print $result->getLabel, "n";
}

This will return us the following data.

Cal Henderson
Cal
http://www.iamcal.com/foaf.xml
2971b1c2fd1d4f0e8f99c167cd85d522a614b07b

Here’s the final code in all it’s glory.

#!/usr/bin/perl -w
use strict;
use RDF::Core::Evaluator;
use RDF::Core::Model;
use RDF::Core::Model::Parser;
use RDF::Core::NodeFactory;
use RDF::Core::Query;
use RDF::Core::Resource;
use RDF::Core::Storage::Memory;
## list of known namespaces we might need.
my $namespaces = {
'foaf' => 'http://xmlns.com/foaf/0.1/',
'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'dc' => 'http://purl.org/dc/elements/1.1/',
};
## create our model and storage for triples.
my $store = RDF::Core::Storage::Memory->new;
my $model = RDF::Core::Model->new(Storage => $store);
## create node factory for query
my $factory = RDF::Core::NodeFactory->new;
## create our parse and parse the Source file.
my $parser = RDF::Core::Model::Parser->new(
Model => $model,
BaseURI => 'http://xmlns.com/foaf/0.1/',
Source => './foaf.rdf',
SourceType => 'file'
);
$parser->parse;
## create an evaluator based on our model, factory and namespaces.
my $evaluator = RDF::Core::Evaluator->new(
Model => $model,
Factory => $factory,
Namespaces => $namespaces,
);
## create a query object based on the evaluator.
my $query = RDF::Core::Query->new(Evaluator => $evaluator);
## run our query and save the results in $results.
my $results = $query->query("select ?x->foaf:name, ?x->foaf:nick, ?x->rdfs:seeAlso, ?x->foaf:mbox_sha1sum from ?x->foaf:nick{?y} where ?y='Cal'");
## go over the results and print the data out.
foreach my $result (@{$results->[0]}) {
print $result->getLabel, "n";
}

If you see warnings (when running using -w or use warnings;) from RDF::Core about use of an uninitialised value before the results are printed don’t worry. This is just a small bug in RDF::Core and won’t affect the running of the code.

Parsing RDF In Perl With RDF::Core

It is often said that parsing RDF files is hard. It’s not. What most people really find hard is turning the RDF/XML into a series of triples and extracting data from them.

When stored in RDF/XML, triples can be written in a variety of various ways, but still mean the same thing. This means using an XML parser may not always give you the same results. To solve this we use an RDF parser to get the triples for us. An RDF parser is usually built on top of an existing XML parser but with enough logic to know how to turn the data contained in an XML file into a list of triples correctly.

There are various RDF parsers for Perl. These include RDF::Core, RDF::Simple, RDF::Redland and several others.

Parsing is all well and good, each one of the above can give us a list of triples. What we really need is a way to query the data to extract the data we need.

In this article I’m going to use RDF::Core.

RDF::Core is a bit of a beast and doesn’t have a very Perl’ish interface.

I’m going to parse my FOAF file and extract a list of my friends FOAF files.

FOAF means Friend of a Friend and it allows you to describe relationships between people in a machine readable RDF format. Details of it can be found on the FOAF project website.

So how do we do this using RDF::Core?

Firstly we need to set it up. We’ll need to a model and define the storage method we want. RDF::Core allows data to be stored in a database, DB_File or memory. In this example I’ll just use memory as it’s the simplest.

my $store = RDF::Core::Storage::Memory->new;
my $model = RDF::Core::Model->new(Storage => $store;

Now we need create a parser, and parse the the RDF file. To do this we pass in our Model, BaseURI, Source, SourceType of the RDF data. In this example I’m going to use the file foaf.rdf so I’ll have to set the SourceType parameter to file. The BaseURI is used to resolve relative URI’s, so we’ll use the FOAF namespace URI http://xmlns.com/foaf/0.1/ for this. Once we have our parser built, we just call it’s parse method.

my $parser = RDF::Core::Model::Parser->new(
Model => $model,
BaseURI => 'http://xmlns.com/foaf/0.1/',
Source => './foaf.rdf',
SourceType => 'file'
);
$parser->parse;

We now have a list of triples in our memory store. That’s great, but we want to find out if any of my friends have FOAF files.

If you look at the example in my previous article on RDF triples, you’ll know that my friends details are referenced by the #knows predicate. So we need to find out all the triples that have that as a predicate and get their objects. Once we have these, we can look for all triples that have this as their subject and also have the predicate of #seeAlso. The object of all these triples will be the address of my friend’s FOAF files.

Refer to my article What Is An RDF Triple for a detailed explanation and commented example of the above.

RDF::Core needs all resources to be created as RDF::Core::Resource objects. We’ll need to create resources for #seeAlso and #knows if we are to query with them, so lets do that now.

my $seealso = RDF::Core::Resource->new('http://www.w3.org/2000/01/rdf-schema#seeAlso');
my $knows = RDF::Core::Resource->new('http://xmlns.com/foaf/0.1/knows');

We can use the getStmts method in the model to get triples matching a given subject, predicate or object. We can either pass in RDF::Core::Resource’s with the values we want to check against, or undef if we want to match everything. This returns an enumerator that we can use to get each matching triple in turn.

To start with we need to get a list of any triples that match our #knows predicate. This is done like this.

my $knows_enum = $model->getStmts(undef, $knows, undef);

Next we need to enumerate over any triples we have.

my $statement = $knows_enum->getFirst;
while (defined $statement) {
my $knows_object = $statement->getObject;
## code to handle each statement goes here
$statement = $knows_enum->getNext;
}

Now we know have a list of triples whose object represents the subject of the triples we want to query, We need to match those with this value as the subject and with the predicate of #seeAlso.

We get get the triples using code very similar to code just used. If we insert the following code into the while loop, we can extract this information.

my $seealso_enum = $model->getStmts($knows_object, $seealso, undef);
my $seealso_object = $seealso_enum->getFirst;
if (defined $seealso_object) {
print $seealso_object->getObject->getLabel, "n";
}

As we only wanted the first #seeAlso value per #knows triple, we don’t have to worry about going through every object in the enumerator, only the first.

Putting it all together, we have a simple script to parse a FOAF file, and print out address of our friend’s FOAF files.

#!/usr/bin/perl -w
## Extract a list of seeAlso triples from a FOAF file
## Robert Price - http://www.robertprice.co.uk/
use strict;
use RDF::Core::Model;
use RDF::Core::Storage::Memory;
use RDF::Core::Model::Parser;
use RDF::Core::Resource;
## create our model and storage for triples.
my $store = RDF::Core::Storage::Memory->new;
my $model = RDF::Core::Model->new(Storage => $store);
## create our parse and parse the Source file.
my $parser = RDF::Core::Model::Parser->new(
Model => $model,
BaseURI => 'http://xmlns.com/foaf/0.1/',
Source => './foaf.rdf',
SourceType => 'file'
);
$parser->parse;
## create a resource for seeAlso and knows triples.
my $seealso = RDF::Core::Resource->new('http://www.w3.org/2000/01/rdf-schema#seeAlso');
my $knows = RDF::Core::Resource->new('http://xmlns.com/foaf/0.1/knows');
## create an enumerator with all the knows triples.
my $knows_enum = $model->getStmts(undef, $knows, undef);
## enumerate over each knows triple.
my $statement = $knows_enum->getFirst;
while (defined $statement) {
## get the object of the current triple.
my $knows_object = $statement->getObject;
## look for subject of the enumerator (knows), and predicate of
## seealso
my $seealso_enum = $model->getStmts($knows_object, $seealso, undef);
my $seealso_obj = $seealso_enum->getFirst;
## if it has a seealso triple, show the value of it.
if (defined $seealso_obj) {
print $seealso_obj->getObject->getLabel, "n";
}
## get the next knows statement.
$statement = $knows_enum->getNext;
}

I hope this has started to demystify RDF parsing with Perl.

What Is An RDF Triple?

An RDF file should parse down to a list of triples.

A triple consists of a subject, a predicate, and an object. But what do these actually mean?

The subject is, well, the subject. It identifies what object the triple is describing.

The predicate defines the piece of data in the object we are giving a value to.

The object is the actual value.

Let’s take a quick look at my FOAF file to get an example triple.

I know Cal Henderson, and this is represented in my FOAF file as…

<foaf:knows>
<foaf:Person>
<foaf:nick>Cal</foaf:nick>
<foaf:name>Cal Henderson</foaf:name>
<foaf:mbox_sha1sum>2971b1c2fd1d4f0e8f99c167cd85d522a614b07b</foaf:mbox_sha1sum>
<rdfs:seeAlso rdf:resource="http://www.iamcal.com/foaf.xml"/>
</foaf:Person>
</foaf:knows>

Using the RDF validator we can get a the list of triples represented in this piece of RDF.


Triple Subject Predicate Object
1 genid:ARP40722 http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Person
2 genid:ARP40722 http://xmlns.com/foaf/0.1/nick "Cal"
3 genid:ARP40722 http://xmlns.com/foaf/0.1/name "Cal Henderson"
4 genid:ARP40722 http://xmlns.com/foaf/0.1/mbox_sha1sum "2971b1c2fd1d4f0e8f99c167cd85d522a614b07b"
5 genid:ARP40722 http://www.w3.org/2000/01/rdf-schema#seeAlso http://www.iamcal.com/foaf.xml
6 genid:me http://xmlns.com/foaf/0.1/knows genid:ARP40722

But what does this actually mean? Lets go through it line by line.

Triple 1 – This has a subject of genid:ARP40722. You would have noticed that this didn’t appear in our original RDF, so where did it come from? It’s actually a bnode, and the value is generated by the RDF Validator. It’s purpose is to make sure we can identify the subject where it hasn’t been specifically named. In this case, we look to triple 6 and see that it has been generated there as the value of that object. The predicate of line 1 is the rdf:type, and the object is foaf:Person. This all corresponds to the code in <foaf:Person> in our FOAF extract.

Triple 2 – You’ll notice this has the same subject as triple 1. This isn’t a coincidence as the triple is part of the same foaf:Person. The predicate says we are defining the foaf:nick property, and the object is Cal. So we know that this foaf:Person has a nickname of Cal. This all corresponds to the line <foaf:nick>Cal</foaf:nick> in our FOAF extract.

Triple 3 – Yet again the subject is the same as triple 1. The predicate is foaf:name, and the object is Cal Henderson. So we know the name of the person in this foaf:Person is Cal Henderson. This represents the line <foaf:name>Cal Henderson</foaf:name>

Triple 4 – Yet again the subject is the same as triple 1. The predicate is foaf:mbox_sha1sum and the object is the SHA1 sum relating to Cal’s email address. This represents the line <foaf:mbox_sha1sum>2971b1c2fd1d4f0e8f99c167cd85d522a614b07b</foaf:mbox_sha1sum>

Triple 5 – Yet again the subject is the same. The predicate is rdfs:seeAlso and the object is http://www.iamcal.com/foaf.xml. We now know that if we want more information on Cal, we can see his FOAF file at that URL. This represents the line <rdfs:seeAlso rdf:resource="http://www.iamcal.com/foaf.xml"/>

Triple 6 – Here the subject is genid:me. This is because at the start of my FOAF file, in an area not show above I defined the id as me. The predicate is foaf:knows and the object is genid:ARP40722. This is saying that I know the person defined by the subject genid:ARP40722. In this case, it’s Cal, and his details have been shown in the previous 5 triples. This relates to the <foaf:knows> block.

Hopefully this has shown how the RDF has been parsed into triples, and how they relate to each other.

Shelley Powers, in her excellent book Practical RDF, helpfully describes triples as the following.

  • Each RDF triple is made up of subject, predicate and object.
  • Each RDF triple is a complete and unique fact.
  • An RDF triple is a 3-tuple, which is made up of a subject, predicate and object – which are respectively a uriref or bnode; a uriref; and a uriref, bnode or literal.
  • Each RDF triple can be joined with other RDF triples, but it still retains its own unique meaning, regardless of the complexity of the models in which it is included.