<?xml version="1.0" encoding="UTF-8"?>
<essay xml:lang="en" version="5.0" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:gal="http://norman.walsh.name/rdf/gallery#" xmlns:foaf="http://xmlns.com/foaf/0.1/">
<info>
    
    
    
    
    
    
    
    
<title>Modelling vCards in RDF</title><biblioid class="uri">http://norman.walsh.name/2005/12/05/vcard</biblioid>
<volumenum>8</volumenum>
<issuenum>157</issuenum>
<pubdate>2005-12-05T22:40:37-05:00</pubdate>
<date>$Date: 2005-12-05 23:24:41 -0500 (Mon, 05 Dec 2005) $</date>
<author>
      <personname>
<firstname>Norman</firstname>
	<surname>Walsh</surname>
</personname>
    </author>
<copyright>
      <year>2005</year>
      <holder>Norman Walsh</holder>
    </copyright>
<abstract>
<para>Yet another stab at modelling names and addresses.</para>
</abstract>
<dcterms:replaces>http://norman.walsh.name/2005/11/25/contacts</dcterms:replaces>
<dcterms:replaces>http://norman.walsh.name/2005/11/30/contacts</dcterms:replaces>
<dc:subject rdf:resource="http://norman.walsh.name/knows/taxonomy#RDF"/>
</info>

<para xml:id="p1">For all
<link xlink:href="/2005/11/30/contacts">the appeal</link> of
<link xlink:href="http://rdfweb.org/topic/AddressVocab">AddressVocab</link>,
it's just too hard to use. Starting from my “contacts” data, there's no
way to get to the fine granularity of that vocabulary except by painful
heuristics. And really, it's way too fine for my purposes.</para>

<para xml:id="p2">Much better, as
<personname>
      <firstname>Roberto</firstname>
      <surname>Garcia</surname>
    </personname>
<link xlink:href="http://norman.walsh.name/2005/11/25/contacts#comment0007">suggested</link>, would be to simply use
<link xlink:href="http://en.wikipedia.org/wiki/Vcard">vCard</link>.</para>

<para xml:id="p3">The problem with vCard is that the
<link xlink:href="http://www.w3.org/TR/vcard-rdf">existing RDF/XML
vocabulary</link> for vCards isn't very good. With all due respect to the
author, RDF and RDF best practices have evolved since it's inception in
early 2001.</para>

<para xml:id="p4"><personname>
      <firstname>Dan</firstname>
      <surname>Connolly</surname>
</personname> suggested that (a) some work in the area of defining a more
modern RDF ontology for vCard data would be valuable and (b) that starting
with what the
<link xlink:href="http://www.microformats.org/">microformats</link>
folks have done with
<link xlink:href="http://www.microformats.org/wiki/hcard-profile">a
profile</link>
of vCard for
<link xlink:href="http://www.microformats.org/wiki/hcard">hCard</link>
would be a good place to start.</para>

<para xml:id="p5">Well, heck, lead me far enough down the path and even I can figure
out what direction to go.</para>

<para xml:id="p6">So I started with the hCard profile and the
<link xlink:href="http://www.ietf.org/rfc/rfc2426.txt">vCard MIME
Directory Profile</link> and tried to construct an ontology in the
most straightforward way I could.</para>

<para xml:id="p7"><link xlink:href="http://nwalsh.com/rdf/vCard">The result</link> has
five classes and about forty properties. In broad strokes:</para>

<itemizedlist>
<listitem>
<para xml:id="p8">There's a <literal>VCard</literal> class (with the bulk of the properties:
<literal>fn</literal>,
<literal>n</literal>,
<literal>adr</literal>,
<literal>email</literal>,
<literal>phone</literal>, etc.)
for vCards themselves,</para>
</listitem>
<listitem>
<para xml:id="p9">a <literal>Name</literal> class to hold the structured name properties
(<literal>family-name</literal>, <literal>given-name</literal>, etc.),
</para>
</listitem>
<listitem>
<para xml:id="p10">an <literal>Address</literal> class to hold the structured (postal)
address properties (<literal>post-office-box</literal>, <literal>street-address</literal>, <literal>locality</literal>, etc.),
</para>
</listitem>
<listitem>
<para xml:id="p11">an <literal>Organization</literal> class to hold the properties
associated with an organization (<literal>organization-name</literal> and
<literal>organization-unit</literal>),
</para>
</listitem>
<listitem>
<para xml:id="p12">and a <literal>Key</literal> class to hold the properties associated
with a key (<literal>key-value</literal> and possibly
<literal>encoding</literal>).
</para>
</listitem>
</itemizedlist>

<para xml:id="p13">I borrrowed the <literal>Point</literal> class from the
<uri>http://www.w3.org/2003/01/geo/wgs84_pos#</uri> vocabulary for the
<literal>geo</literal> property. I was tempted to borrow the FOAF name
properties but decided there wasn't quite enough correlation between the
vCard parts and the FOAF parts.</para>

<para xml:id="p14">Here's what I ended up with:</para>

<programlisting># -*- N3 -*-

@prefix owl: &lt;http://www.w3.org/2002/07/owl#&gt; .
@prefix xs: &lt;http://www.w3.org/2001/XMLSchema#&gt; .
@prefix v: &lt;http://nwalsh.com/rdf/vCard#&gt; .
@prefix geo: &lt;http://www.w3.org/2003/01/geo/wgs84_pos#&gt; .
@prefix foaf: &lt;http://xmlns.com/foaf/0.1/&gt; .
@prefix rdf: &lt;http://www.w3.org/1999/02/22-rdf-syntax-ns#&gt; .
@prefix rdfs: &lt;http://www.w3.org/2000/01/rdf-schema#&gt; .

&lt;http://nwalsh.com/rdf/vCard&gt; a owl:Ontology;
    rdfs:comment "Norm's attempt at a vCard/hCard RDF ontology." .

# ------------------------------------------------------------

v:VCard a owl:Class;
    rdfs:comment "Resources that are vCards." .

v:Name a owl:Class;
    rdfs:comment "Resources that are vCard personal names." .

v:Address a owl:Class;
    rdfs:comment "Resources that are vCard (postal) addresses." .

v:Organization a owl:Class;
    rdfs:comment "Resources that are vCard organizations." .

v:Key a owl:Class;
    rdfs:comment "Resources that are vCard keys." .

# ------------------------------------------------------------

v:type a owl:DatatypeProperty;
    rdfs:comment "Several vCard resources can have an associated type." .

v:encoding a owl:DatatypeProperty;
    rdfs:comment "Several vCard resources can have an associated encoding." .

# ------------------------------------------------------------

v:fn a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A formatted personal name." .

v:n a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:range v:Name;
    rdfs:comment "A vCard personal name resource." .

v:family-name a owl:DatatypeProperty;
    rdfs:domain v:Name;
    rdfs:comment "A person's family name." .

v:given-name a owl:DatatypeProperty;
    rdfs:domain v:Name;
    rdfs:comment "A person's given name." .

v:additional-name a owl:DatatypeProperty;
    rdfs:domain v:Name;
    rdfs:comment "A person's additional name." .

v:honorific-prefix a owl:DatatypeProperty;
    rdfs:domain v:Name;
    rdfs:comment "A person's honorific prefix." .

v:honorific-suffix a owl:DatatypeProperty;
    rdfs:domain v:Name;
    rdfs:comment "A person's honorific suffix." .

v:photo a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A photograph." .

v:bday a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:range xs:date;
    rdfs:comment "A birthday." .

v:adr a owl:ObjectProperty;
    rdfs:range v:Address;
    rdfs:comment "A vCard address resource" .

v:post-office-box a owl:DatatypeProperty;
    rdfs:domain v:Address;
    rdfs:comment "The post office box of a postal address." .

v:extended-address a owl:DatatypeProperty;
    rdfs:domain v:Address;
    rdfs:comment "The extended address of a postal address." .

v:street-address a owl:DatatypeProperty;
    rdfs:domain v:Address;
    rdfs:comment "The street address of a postal address." .

v:locality a owl:DatatypeProperty;
    rdfs:domain v:Address;
    rdfs:comment "The locality (e.g., city) of a postal address." .

v:region a owl:DatatypeProperty;
    rdfs:domain v:Address;
    rdfs:comment "The region (e.g., state or province) of a postal address." .

v:postal-code a owl:DatatypeProperty;
    rdfs:domain v:Address;
    rdfs:comment "The postal code (e.g., U.S. ZIP code) of a postal address." .

v:country-name a owl:DatatypeProperty;
    rdfs:domain v:Address;
    rdfs:comment "The country of a postal address." .

v:label a owl:DatatypeProperty;
    rdfs:domain v:Address;
    rdfs:comment "The formatted version of a postal address (a string with embedded line breaks, punctuation, etc.)." .

v:tel a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A telephone number." .

v:email a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:comment "An email address." .

v:mailer a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "The mailer associated with a vCard." .

v:tz a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "The timezone." .

v:geo a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:range geo:Point;
    rdfs:comment "Geographic information (a latitude and longitude)" .

v:title a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A person's title." .

v:role a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "The role a person plays within an organization." .

v:logo a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A logo." .

v:agent a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:range v:VCard;
    rdfs:comment "A person that acts as one's agent." .

v:org a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:range v:Organization;
    rdfs:comment "An organization." .

v:organization-name a owl:DatatypeProperty;
    rdfs:domain v:Organization;
    rdfs:comment "The name of an organization." .

v:organization-unit a owl:DatatypeProperty;
    rdfs:domain v:Organization;
    rdfs:comment "The name of a unit within a larger organization." .

v:category a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A category." .

v:note a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "Notes." .

# How do I make the range a date or a dateTime?
v:rev a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:range xs:dateTime;
    rdfs:comment "The timestamp of a revision." .

v:sort-string a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A sort string." .

v:sound a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A sound (e.g., a greeting)." .

v:uid a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A UID." .

v:url a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:comment "A URL." .

v:class a owl:DatatypeProperty;
    rdfs:domain v:VCard;
    rdfs:comment "The class (e.g., public, private, etc.) of a vCard." .

v:key a owl:ObjectProperty;
    rdfs:domain v:VCard;
    rdfs:range v:Key;
    rdfs:comment "The key (e.g, PKI key)." .

v:key-value a owl:DatatypeProperty;
    rdfs:domain v:Key;
    rdfs:comment "The key value." .
</programlisting>

<para xml:id="p15">There's certainly room for discussion about whether this is
exactly the right selection of properties to include, and whether these
are exactly the right modelling choices, but it “feels” pretty good.
I'll try to incorporate what feedback I get.</para>

<para xml:id="p16">In the larger context of my address book, I'm currently just
using the <literal>adr</literal> property on my
<literal>Contact</literal> class, instead of trying to model each of
my contacts as a vCard. But that's something I can change later if
there seems to be value in modelling them as vCards.</para>

</essay>

