Comparing Formats
Deutsche Übersetzung

Original:
http://www.w3c.org/2000/10/swap/doc/formats.html
$ Id: formats.html,v 1.17 2003/04/16 00:23:27 sandro Exp $
Diese Übersetzung:
http://www.bitloeffel.de/DOC/2003/Formats-20030416-de.html
$Id: Formats-20030416-de.html,v 1.2 2004/03/25 11:31:44 hawe Exp $
Übersetzer:
Hans-Werner Heinzen, Bitloeffel.de , Hans-Werner.Heinzen@Bitloeffel.de

Dieses Dokument ist eine deutsche Übersetzung eines W3C -Textes. Sie enthält möglicherweise Fehler. Sie hat keinerlei durch das W3C legitimierte normative Wirkung. Das maßgebende Dokument ist das englische Original.

Der Übersetzer freut sich über Hinweise auf Fehler der deutschen Fassung, und ist als Neuling auf diesem Gebiet auch für Übersetzungstips dankbar.


W3C | Semantic Web | Advanced Development | SWAP | Tutorial | Comparing Formats

Formatvergleich

Heuzutage werden viele Sprachen dazu benutzt, um RDF-strukturierte Informationen auszutauschen. Hier wird ein Beispiel auf verschiedene Arten entwickelt. Zwischen einigen davon existieren bereits Konverter, zwischen anderen (noch) nicht.

Englisch (Sehr informell)

There is person, Pat, known as "Pat Smith" and "Patrick Smith". Pat has a pet dog named "Rover".

Englischer Hypertext (Informell)

Doppeldeutigkeiten werden hier behandelt, indem man Wörter zu Hypertextverweisen (englisch: hypertext links) macht. Dabei ist es egal, ob diese Verweise, die ja von den jeweils beteiligten Servern abhängen, funktionieren oder nicht.

Pat is a human with the names "Pat Smith" and "Patrick Smith". Pat has a pet , a dog , with the name "Rover".

N3

@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" ] .

Beschrifteter gerichteter Graph

RDF/XML

<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>

N-Tripel

Mit @prefix:

@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".

und in der Standardform:

<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" .

Prolog

Ohne Namensräume schreibt man kurz:

human(pat).
dog(rover).            % we have to assign a name
name(pat, "Pat Smith").
name(pat, "Patrick Smith").
name(rover, "Rover").
pet(pat, rover).

Eine Möglichkeit mit Namensräumen:

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).

SQL

Eine Tabelle verküpft URIs mit internen IDs

URIs sind große Schlüsselbegriffe variabler Länge. Umsetzen in interne IDs steigert die Effizienz. Ist die URI NULL, so handelt es sich um eine anonyme Ressource (ein bNode wie NodeID in RDF/XML).

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                                                         |
+----+--------------------------------------------------------------+

Option 1: Eine Tabelle, eine Spalte pro Prädikat

Dies ist ein einfacher, intuitiver Ansatz, aber ...

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 |
+----+------+-----------+------+

Option 2: Eine Tabelle ja Klasse, eine Spalte je Prädikat

Hier vermeiden wir so breite Tabellen und unser Modellieren entspricht eher dem üblichen Datenbankmodellieren. Andererseits, weil es keine Vererbung gibt, bleibt eine konzeptionelle Redundanz: human.name und dog.name.

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 |
+----+-----------+------+----+-------+

Option 3: Eine Tabelle je Prädikat

Damit unterstützen wir Mehrfachwerte.

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 |
+---------+--------+

Option 4: Eine Tabelle Tripel, eine Tabelle Ressourcen

Wenn wir unsere URI-Tabelle zu einer Ressource-Tabelle ändern, die ausser URIs auch Literale enthalten kann, haben wir einige neue Möglichkeiten.

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 .
+----+--------------------------------------------------------------+---------------+
|  1 | http://www.w3.org/1999/02/22-rdf-syntax-ns#type              | NULL          .
|  2 | http://www.w3.org/2000/10/swap/test/demo1/biology#Human      | NULL          .
|  3 | http://www.w3.org/2000/10/swap/test/demo1/biology#Dog        | NULL          .
|  4 | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name | NULL          .
|  5 | http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet  | NULL          .
|  6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat      | NULL          .
|  7 | NULL                                                         | NULL          .
|  8 | NULL                                                         | Pat Smith     .
|  9 | NULL                                                         | Patrick Smith .
| 10 | NULL                                                         | Rover         .
+----+--------------------------------------------------------------+---------------+

    +----------+----------+
    . datatype | language |
    +----------+----------+
    .     NULL | NULL     |
    .     NULL | NULL     |
    .     NULL | NULL     |
    .     NULL | NULL     |
    .     NULL | NULL     |
    .     NULL | NULL     |
    .     NULL | NULL     |
    .     NULL | NULL     |
    .     NULL | NULL     |
    .     NULL | NULL     |
    +----------+----------+

Damit brauchen wir nur noch eine einfache Tabelle, die Tripel enthält.

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                                                     .
+----+---------------------------------------------------------+
|  6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat .
|  6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat .
|  6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat .
|  6 | http://www.w3.org/2000/10/swap/test/demo1/about-pat#pat .
|  7 | NULL                                                    .
|  7 | NULL                                                    .
+----+---------------------------------------------------------+

    +--------------------------------------------------------------+
    . predicate                                                    .
    +--------------------------------------------------------------+
    . http://www.w3.org/1999/02/22-rdf-syntax-ns#type              .
    . http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name .
    . http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name .
    . http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#pet  .
    . http://www.w3.org/1999/02/22-rdf-syntax-ns#type              .
    . http://www.w3.org/2000/10/swap/test/demo1/friends-vocab#name .
    +--------------------------------------------------------------+

        +----+---------------------------------------------------------+---------------+
        . id | uri                                                     | lit           |
        +----+---------------------------------------------------------+---------------+
        .  2 | http://www.w3.org/2000/10/swap/test/demo1/biology#Human | NULL          |
        .  8 | NULL                                                    | Pat Smith     |
        .  9 | NULL                                                    | Patrick Smith |
        .  7 | NULL                                                    | NULL          |
        .  3 | http://www.w3.org/2000/10/swap/test/demo1/biology#Dog   | NULL          |
        . 10 | NULL                                                    | Rover         |
        +----+---------------------------------------------------------+---------------+

XML (nicht RDF/XML)

Der Ansatz der alternierenden Normalform (englisch: striped or alternating-normal form) benutzt eine für die jeweilige Anwendung entwickelte Markup-Sprache. Für die Konversion in Tripel und zurück benötigt man darauf spezialisierte Software.

<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>

Eine Alternative dazu sind XML Tripel. Man braucht also keine anwendungsspezifischen Markup-Tags. Verschiedene DTDs/Schemas sind vorgeschlagen worden; das hier ist nur ein Beispiel für viele. Für einige Anwendungen mag eine solche Syntax einfacher sein als RDF/XML oder die "striped" Syntax.

<!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>

Javascript und Python

Das RDF-Modell passt ziemlich gut zu einigen verbreiteten Programmierkonstrukten, insbesondere zu solchen, die man in interpretierten obketorientierten Sprachen finden kann, beispielsweise in Javascript oder Python. Die Umsetzung ist noch nicht perfekt.

Dieser einfache Ansatz ignoriert URI- und Kardinalitätsfragen. Er erlaubt Pat nur einen Namen und ein Haustier zu haben:

pat = Human()
rover = Dog()
pat.name = "Pat Smith"
rover.name = "Rover"
pat.pet = rover

Versuchen wir's mit Kardinalität:

pat = Human()
rover = Dog()
pat.name.append("Pat Smith")
rover.name.append("Rover")
pat.pet.append(rover)

Für bessere Vollständigkeit brauchen wir etwa so etwas, wobei alledings die Einfachheit verloren geht:

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.per.pet, rover)

Aber, nicht vergessen ...

Hüten Sie sich davor, RDF als Format nur zum Serialisieren von Objekten anzusehen. Das Semantische Netz ist ist anders - es ist netzartig.

Entity-Relationship- und UML-Diagramme sind hilfreich beim Beschreiben von RDF - solange Sie das gerade Gesagte nicht vergessen.

Spannend und herausfordernd ist auch, eine Sprache wie N3 in objektorientierte Sprachen einzubetten.