Part A2: Sidebar: Comparing document formats
...for data and relational information.
The same example follows in various languages.
There is person, Pat, known as "Pat Smith" and "Patrick Smith". Pat has a pet dog named "Rover".
Pat is a human with the names "Pat Smith" and "Patrick Smith". Pat has a pet, a dog, with the name "Rover".
@prefix : <http://www.w3.org/2000/10/swap/test/demo1/about-pat#> .
@prefix bio: <http://www.w3.org/2000/10/swap/test/demo1/biology#> .
@prefix per: <http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#> .
:pat a bio:Human;
per:name "Pat Smith",
"Patrick Smith";
per:pet [
a bio:Dog;
per:name "Rover" ] .

<rdf:RDF xmlns="http://www.w3.org/2000/10/swap/test/demo1/about-pat#"
xmlns:bio="http://www.w3.org/2000/10/swap/test/demo1/biology#"
xmlns:per="http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<bio:Human rdf:about="#pat">
<per:name>Pat Smith</per:name>
<per:name>Patrick Smith</per:name>
<per:pet>
<bio:Dog>
<per:name>Rover</per:name>
</bio:Dog>
</per:pet>
</bio:Human>
</rdf:RDF>
With @prefix. N-triples do not really have prefixes.
@prefix : <http://www.w3.org/2000/10/swap/test/demo1/about-pat#> . @prefix bio: <http://www.w3.org/2000/10/swap/test/demo1/biology#> . @prefix per: <http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>. :pat rdf:type bio:Human. :pat per:name "Pat Smith". :pat per:name "Patrick Smith". :pat per:pat _:genid1. _:genid1 rdf:type bio:Dog. _:genid1 per:name "Rover".
In standard form (yes, each statement must be on one line)
<http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/10/swap/test/demo1/biology#Human> . <http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat> <http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name> "Pat Smith" . <http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat> <http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name> "Patrick Smith" . <http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat> <http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet> _:genid1 . _:genid1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/10/swap/test/demo1/biology#Dog> . _:genid1 <http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name> "Rover" .
Without namespaces, this is very terse:
human(pat). dog(rover). % we have to assign a name name(pat, "Pat Smith"). name(pat, "Patrick Smith"). name(rover, "Rover"). pet(pat, rover).
One approach to namespaces:
ns(ns1_, "http://www.w3.org/2000/10/swap/test/demo1/about-pat"). ns(bio_, "http://www.w3.org/2000/10/swap/test/demo1/biology#"). ns(per_, "http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#"). bio_Human(ns1_pat). bio_Dog(rover). # unprefix could be be NodeIDs... per_name(ns1_pat, "Pat Smith"). per_name(ns1_pat, "Patrick Smith"). per_name(rover, "Rover"). per_pet(ns1_pat, rover).
CREATE TABLE uri (
id INT AUTO_INCREMENT PRIMARY KEY, # PRIMARY = UNIQUE and NOT NULL
uri BLOB, # BLOB is also called LONGVARBINARY
UNIQUE KEY uri (uri(64)) # length is just a tuning knob
);
INSERT INTO uri (uri) VALUES ('http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
INSERT INTO uri (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/biology#Human');
INSERT INTO uri (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/biology#Dog');
INSERT INTO uri (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name');
INSERT INTO uri (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet');
INSERT INTO uri (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat');
INSERT INTO uri (uri) VALUES (NULL); # this is rover, who has no URI
mysql> select * from uri;
+----+--------------------------------------------------------------+
| id | uri |
+----+--------------------------------------------------------------+
| 1 | http://www.w3.org/1999/02/22-rdf-syntax-ns#type |
| 2 | http://www.w3.org/2000/10/swap/test/demo1/biology#Human |
| 3 | http://www.w3.org/2000/10/swap/test/demo1/biology#Dog |
| 4 | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name |
| 5 | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet |
| 6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat |
| 7 | NULL |
+----+--------------------------------------------------------------+
This is a simple, intuitive approach, but...
CREATE TABLE resource ( id INT PRIMARY KEY, type INT, # http://www.w3.org/1999/02/22-rdf-syntax-ns#type name varchar(255), # http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name pet INT # http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet ); INSERT INTO resource (id, type, name, pet) VALUES (6, 2, 'Pat Smith', 7); INSERT INTO resource (id, type, name) VALUES (7, 3, 'Rover'); mysql> select * from resource; +----+------+-----------+------+ | id | type | name | pet | +----+------+-----------+------+ | 6 | 2 | Pat Smith | 7 | | 7 | 3 | Rover | NULL | +----+------+-----------+------+
CREATE TABLE human ( # http://www.w3.org/2000/10/swap/test/demo1/biology#Human id INT PRIMARY KEY, name varchar(255), # http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name pet INT # http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet ); CREATE TABLE dog ( # http://www.w3.org/2000/10/swap/test/demo1/biology#Dog id INT PRIMARY KEY, name varchar(255) # http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name ); INSERT INTO human VALUES (6, 'Pat Smith', 7); INSERT INTO dog VALUES (7, 'Rover'); mysql> select * from human, dog where human.pet=dog.id; +----+-----------+------+----+-------+ | id | name | pet | id | name | +----+-----------+------+----+-------+ | 6 | Pat Smith | 7 | 7 | Rover | +----+-----------+------+----+-------+
Here we can support duplicate values.
CREATE TABLE name ( # http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name subject INT NOT NULL, object varchar(255), INDEX(subject), UNIQUE INDEX(subject, object) ); CREATE TABLE pet ( # http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet subject INT NOT NULL, object INT, INDEX(subject), UNIQUE INDEX(subject, object) ); CREATE TABLE type ( # http://www.w3.org/1999/02/22-rdf-syntax-ns#type subject INT NOT NULL, object INT, INDEX(subject), UNIQUE INDEX(subject, object) ); INSERT INTO name VALUES (6, 'Pat Smith'); INSERT INTO name VALUES (6, 'Patrick Smith'); INSERT INTO name VALUES (7, 'Rover'); INSERT INTO pet VALUES (6, 7); INSERT INTO type VALUES (6, 2); INSERT INTO type VALUES (7, 3); mysql> select * from name; +---------+---------------+ | subject | object | +---------+---------------+ | 6 | Pat Smith | | 6 | Patrick Smith | | 7 | Rover | +---------+---------------+ mysql> select * from pet; +---------+--------+ | subject | object | +---------+--------+ | 6 | 7 | +---------+--------+ mysql> select * from type; +---------+--------+ | subject | object | +---------+--------+ | 6 | 2 | | 7 | 3 | +---------+--------+
If we redo our URIs table as a "resources" table, with literals as well as URIs, we have some more options.
CREATE TABLE resources (
id INT AUTO_INCREMENT PRIMARY KEY, # PRIMARY = UNIQUE and NOT NULL
# either provide a uri
uri BLOB,
# or a literal_value, which might have a datatype and language
literal_value BLOB,
datatype INT,
language VARCHAR(5),
UNIQUE KEY (uri(64)) # length is just a tuning knob
);
INSERT INTO resources (uri) VALUES ('http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
INSERT INTO resources (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/biology#Human');
INSERT INTO resources (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/biology#Dog');
INSERT INTO resources (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name');
INSERT INTO resources (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet');
INSERT INTO resources (uri) VALUES ('http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat');
INSERT INTO resources (uri) VALUES (NULL); # this is rover, who has no URI
INSERT INTO resources (literal_value) VALUES ('Pat Smith');
INSERT INTO resources (literal_value) VALUES ('Patrick Smith');
INSERT INTO resources (literal_value) VALUES ('Rover');
mysql> select * from resources;
+----+--------------------------------------------------------------+---------------+----------+----------+
| id | uri | literal_value | datatype | language |
+----+--------------------------------------------------------------+---------------+----------+----------+
| 1 | http://www.w3.org/1999/02/22-rdf-syntax-ns#type | NULL | NULL | NULL |
| 2 | http://www.w3.org/2000/10/swap/test/demo1/biology#Human | NULL | NULL | NULL |
| 3 | http://www.w3.org/2000/10/swap/test/demo1/biology#Dog | NULL | NULL | NULL |
| 4 | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name | NULL | NULL | NULL |
| 5 | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet | NULL | NULL | NULL |
| 6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat | NULL | NULL | NULL |
| 7 | NULL | NULL | NULL | NULL |
| 8 | NULL | Pat Smith | NULL | NULL |
| 9 | NULL | Patrick Smith | NULL | NULL |
| 10 | NULL | Rover | NULL | NULL |
+----+--------------------------------------------------------------+---------------+----------+----------+
Then we can have a simple table of triples:
CREATE TABLE triples (
subject INT NOT NULL,
predicate INT NOT NULL,
object INT NOT NULL,
UNIQUE INDEX(subject, predicate, object),
INDEX(predicate, object),
INDEX(object, predicate)
);
INSERT INTO triples VALUES (6, 4, 8);
INSERT INTO triples VALUES (6, 4, 9);
INSERT INTO triples VALUES (7, 4, 10);
INSERT INTO triples VALUES (6, 1, 2);
INSERT INTO triples VALUES (7, 1, 3);
INSERT INTO triples VALUES (6, 5, 7);
mysql> select * from triples;
+---------+-----------+--------+
| subject | predicate | object |
+---------+-----------+--------+
| 6 | 1 | 2 |
| 6 | 4 | 8 |
| 6 | 4 | 9 |
| 6 | 5 | 7 |
| 7 | 1 | 3 |
| 7 | 4 | 10 |
+---------+-----------+--------+
mysql> select s.id, s.uri, p.uri as "predicate",
o.id, o.uri, o.literal_value as "lit"
from triples, resources as s, resources as p, resources as o
where s.id=triples.subject AND
p.id=triples.predicate AND
o.id=triples.object;
+----+---------------------------------------------------------+--------------------------------------------------------------+----+---------------------------------------------------------+---------------+
| id | uri | predicate | id | uri | lit |
+----+---------------------------------------------------------+--------------------------------------------------------------+----+---------------------------------------------------------+---------------+
| 6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat | http://www.w3.org/1999/02/22-rdf-syntax-ns#type | 2 | http://www.w3.org/2000/10/swap/test/demo1/biology#Human | NULL |
| 6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name | 8 | NULL | Pat Smith |
| 6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name | 9 | NULL | Patrick Smith |
| 6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet | 7 | NULL | NULL |
| 7 | NULL | http://www.w3.org/1999/02/22-rdf-syntax-ns#type | 3 | http://www.w3.org/2000/10/swap/test/demo1/biology#Dog | NULL |
| 7 | NULL | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name | 10 | NULL | Rover |
+----+---------------------------------------------------------+--------------------------------------------------------------+----+---------------------------------------------------------+---------------+
<Human>
<uri>http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat</uri>
<name>Pat Smith</name>
<pet>
<Dog>
<name>Rover</name>
</Dog>
</pet>
</Human>
<!DOCTYPE Graph [
<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<!ENTITY bio "http://www.w3.org/2000/10/swap/test/demo1/biology#">
<!ENTITY ns1 "http://www.w3.org/2000/10/swap/test/demo1/about-pat#">
<!ENTITY per "http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#">
]>
<Graph>
<Triple>
<subject><uri>&ns1;pat</uri></subject>
<predicate><uri>&rdf;type</uri></predicate>
<object><uri>&bio;Human</uri></object>
</Triple>
<Triple>
<subject><uri>&ns1;pat</uri></subject>
<predicate><uri>&per;name</uri></predicate>
<object><literal>Pat Smith</literal></object>
</Triple>
<Triple>
<subject><uri>&ns1;pat</uri></subject>
<predicate><uri>&per;pet</uri></predicate>
<object><nodeID>genid1</nodeID></object>
</Triple>
<Triple>
<subject><nodeID>genid1</nodeID></subject>
<predicate><uri>&rdf;type</uri></predicate>
<object><uri>&bio;Dog</uri></object>
</Triple>
<Triple>
<subject><nodeID>genid1</nodeID></subject>
<predicate><uri>&per;name</uri></predicate>
<object><literal>Rover</literal></object>
</Triple>
</Graph>
pat = Human() rover = Dog() pat.name = "Pat Smith" rover.name = "Rover" pat.pet = rover
We can begin to consider cardinality:
pat = Human()
rover = Dog()
pat.name.append("Pat Smith")
rover.name.append("Rover")
pat.pet.append(rover)
But to be more complete, we need something like this which loses the simplicity of the built-in model:
pat = Resource() rover = Resource() pat.addProperty( ns.rdf.type, ns.bio.Human) rover.addProperty(ns.rdf.type, ns.bio.Dog) pat.addProperty( ns.per.name, "Pat Smith") rover.addProperty(ns.per.name, "Rover") pat.addProperty( ns.perpet, rover)
Beware of thinking of RDF as a format for serializing objects.
The semantic web is different - it is weblike.
Entity-Relationship and UML diagrams are useful for describing RDF -- so long as you remember the above.
Challenge: Blend n3 seamlessly into OO languages.
you should now understand
(end of section)