<?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>An address book ontology</title><biblioid class="uri">http://norman.walsh.name/2005/11/25/contacts</biblioid>
<volumenum>8</volumenum>
<issuenum>151</issuenum>
<pubdate>2005-11-25T08:52:57-05:00</pubdate>
<date>$Date: 2005-11-29 10:25:33 -0500 (Tue, 29 Nov 2005) $</date>
<author>
      <personname>
<firstname>Norman</firstname>
	<surname>Walsh</surname>
</personname>
    </author>
<copyright>
      <year>2005</year>
      <holder>Norman Walsh</holder>
    </copyright>
<abstract>
<para>Modeling names and addresses. No, not that old debate, the sort
that appear in your address book.</para>
</abstract>
<dc:subject rdf:resource="http://norman.walsh.name/knows/taxonomy#RDF"/>
<dc:subject rdf:resource="http://norman.walsh.name/knows/taxonomy#Sidekick"/>
</info>

<para xml:id="p1">Years ago, when I was using a
<link xlink:href="http://en.wikipedia.org/wiki/Palm_%28PDA%29">Palm device</link>
for my address book, calendar, etc., I arranged to convert that data into
RDF. I described that work in
<citetitle xlink:href="http://nwalsh.com/docs/articles/extreme2002/">Generalized
Metadata in your Palm</citetitle>, a paper that I presented at
<citetitle xlink:href="http://www.extrememarkup.com/">Extreme Markup
Languages</citetitle> in 2002.</para>

<para xml:id="p2">When I converted from the Palm to the
<link xlink:href="http://en.wikipedia.org/wiki/T-Mobile_Sidekick">Sidekick</link>,
I temporarily lost the RDF. I had no trouble, thanks to
<personname>
      <firstname>Dan</firstname>
      <surname>Connolly</surname>
    </personname>
and the T-Mobile XML/RPC interface, getting XML out, but I wasn't getting
RDF. (I could have, Dan does, but I didn't because it was quicker to get
my local infrastructure running again just from the straight XML.)</para>

<para xml:id="p3">Recently, I decided it was time to get the RDF back. I want to
be able to combine the contacts in my address book with other data
sources in ways that RDF makes easy and I want to be able to do
inference over contacts again. In addition, I now have a tool that will
validate my RDF. Validation, does this instance conform to the model I've
described?, was one of the first things I asked about when I started using
RDF. Only after the publication of 
<link xlink:href="http://en.wikipedia.org/wiki/Web_Ontology_Language">OWL</link>
does it seem that such tools have actually been widely deployed.
(I'm using
<link xlink:href="http://www.mindswap.org/2003/pellet/index.shtml">pellet</link>
at the moment.)</para>

<section xml:id="ontology">
<title>Designing the ontology</title>

<para xml:id="p4">Given that I can now validate my RDF, I'm much more motivated to
write a schema for my model. Designing an RDF schema isn't unlike
other design exercises; it consists principally of dividing the world
into classes, properties on those classes, and defining the relationships
between classes and properties.</para>

<para xml:id="p5">My first instinct was to write my own ontology from scratch,
defining a class for contacts and properties on resources of that class:
first name, last name, email addresses, phone numbers, postal addresses,
etc. In fact, that's just what I did. But
there
was a significant overlap with the
<link xlink:href="http://en.wikipedia.org/wiki/FOAF_%28software%29">FOAF</link>
vocabulary. One of RDF's strengths is the ability to easily aggregate
different vocabularies, so I replaced many of my properties with
appropriate FOAF properties.</para>

<para xml:id="p6">In fact, I might propose to extend FOAF to cover more of this use
case since it seems so closely related. Instead of just asserting my extensions,
I've compromised and made some of my properties and classes subclasses and
subproperties of the FOAF terms.</para>

<section xml:id="corp">
<title>Classes or properties?</title>

<para xml:id="p7">Phone numbers, email addresses, postal addresses, and even to
some extent, instant messaging addresses have “labels” associated with
them. That is, a “work” phone number is distinct from a “home” phone
number, etc.</para>

<para xml:id="p8">This distinction is significant and has to be preserved in the
model. Let's consider phone numbers as a concrete example. Three
possibilities occur to me.</para>

<orderedlist>
<listitem>
<para xml:id="p9">Model the label directly: make a phone number a class of
resource that has two properties, a label and a phone number.
</para>
	</listitem>
<listitem>
<para xml:id="p10">Use classes: make a phone number a class of resources with
subclasses for a work phone number, a home phone number, etc.
</para>
	</listitem>
<listitem>
<para xml:id="p11">Use properties: make a phone number property with subproperties
for work phone number, home phone number, etc.
</para>
	</listitem>
</orderedlist>

<para xml:id="p12">After some thought and
<link xlink:href="http://chatlogs.planetrdf.com/swig/2005-11-22#T15-25-48">some
discussion</link> on the
<literal xlink:href="irc:irc.freenode.net#swig">#swig</literal> channel
on <systemitem class="domainname">irc.freenode.net</systemitem>,
I don't think there's a compelling argument in favor of any one solution,
except that the first seems less appealing than either of the others.
The label isn't open-ended free text, it's a string that identifies
the kind of phone number and both the class and property solutions seem
to do that more directly.</para>

<para xml:id="p13">My personal inclination is to use classes, but I see that FOAF has
already opted for the property approach (<literal>homepage</literal>,
<literal>workplaceHomepage</literal>, etc.) in several places, so I
decided to go that way too.</para>

</section>
<section xml:id="lists">
<title>Lists or not?</title>

<para xml:id="p14">Another decision that has to be made is whether or not to model
the various repeatable fields as lists. Certainly they're ordered in the
XML and they appear ordered on the Sidekick display, but lists in RDF
more-or-less suck, so I opted not to model them that way. It'll put a little
more burden on any software I eventually write to synchronize from the
RDF, but that seems better than dealing with the list problems everywhere.
And really, the list nature of the properties isn't intrinsically important.
If I want to call my friend's work phone number, I don't care if it's listed
first or second, do I?</para>
</section>
</section>

<section xml:id="design">
<title>The “final” design</title>

<para xml:id="p15">Taking into account the choices above, and considering that I'm aiming
to take advantage of FOAF as much as possible, let's consider how an
entry in my address book gets translated to RDF. Here's an entry:</para>

<programlisting>&lt;contact id="_950"&gt;
  &lt;last_modified&gt;2005-11-24T14:10:51Z&lt;/last_modified&gt;
  &lt;category&gt;Family&lt;/category&gt;
  &lt;firstname&gt;Norman&lt;/firstname&gt;
  &lt;middlename&gt;David&lt;/middlename&gt;
  &lt;surname&gt;Walsh&lt;/surname&gt;
  &lt;company&gt;Sun Microsystems, Inc.&lt;/company&gt;
  &lt;title&gt;XML Standards Architect&lt;/title&gt;
  &lt;birthday&gt;1967-06-16&lt;/birthday&gt;
  &lt;uris&gt;
    &lt;uri label="ID"&gt;#norman-walsh&lt;/uri&gt;
    &lt;uri label="Blog"&gt;http://norman.walsh.name/&lt;/uri&gt;
    &lt;uri label="Home"&gt;http://nwalsh.com/&lt;/uri&gt;
  &lt;/uris&gt;
  &lt;emails&gt;
    &lt;email label="Work"&gt;Norman.Walsh@Sun.COM&lt;/email&gt;
    &lt;email label="Home"&gt;ndw@nwalsh.com&lt;/email&gt;
  &lt;/emails&gt;
  &lt;phones&gt;
    &lt;phone label="Work"&gt;+1-413-303-1382&lt;/phone&gt;
    &lt;phone label="Work"&gt;+1-413-256-xxxx&lt;/phone&gt;
    &lt;phone label="Home"&gt;+1-413-256-xxxx&lt;/phone&gt;
    &lt;phone label="Mobile"&gt;+1-413-949-xxxx&lt;/phone&gt;
  &lt;/phones&gt;
  &lt;addresses&gt;
    &lt;address label="Home"&gt;
      &lt;street&gt;XX Xxxx Street&lt;/street&gt;
      &lt;city&gt;Belchertown&lt;/city&gt;
      &lt;state&gt;MA&lt;/state&gt;
      &lt;postcode&gt;01007&lt;/postcode&gt;
    &lt;/address&gt;
    &lt;address label="Work"&gt;
      &lt;street&gt;1 Network Drive, Building #2
MS UBUR02-201&lt;/street&gt;
      &lt;city&gt;Burlington&lt;/city&gt;
      &lt;state&gt;MA&lt;/state&gt;
      &lt;postcode&gt;01803&lt;/postcode&gt;
    &lt;/address&gt;
  &lt;/addresses&gt;
  &lt;notes&gt;rdf:
a g:Male
geo:lat 42.3382
geo:long -72.45
foaf:page http://norman.walsh.name/foaf

AccessLine is x53142&lt;/notes&gt;
  &lt;rdf:type rdf:resource="http://nwalsh.com/rdf/genealogy#Male"/&gt;
  &lt;geo:lat&gt;42.3382&lt;/geo:lat&gt;
  &lt;geo:long&gt;-72.45&lt;/geo:long&gt;
  &lt;foaf:page rdf:resource="http://norman.walsh.name/foaf"/&gt;
&lt;/contact&gt;</programlisting>

<para xml:id="p16">And here's the resulting RDF.</para>

<programlisting>&lt;rdf:Description rdf:about="http://norman.walsh.name/knows/who#norman-walsh"&gt;
  &lt;rdf:type rdf:resource="http://nwalsh.com/rdf/contacts#Contact"/&gt;
  &lt;rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/&gt;</programlisting>

<para xml:id="p17">The “ID” URI is used to construct the URI for the resource. All contacts
are members of the <literal>Contact</literal> class and contacts that have
a first or last name are <literal>foaf:Person</literal>s. Contacts that
have only company names are <literal>foaf:Organization</literal>s. I have
a third class, <literal>c:Place</literal>, for geographic locations, but
that's probably unique to my metadata collection.</para>

<programlisting>  &lt;c:lastModified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime"&gt;2005-11-24T14:10:51Z&lt;/c:lastModified&gt;
  &lt;c:category&gt;Family&lt;/c:category&gt;</programlisting>

<para xml:id="p18">The last modified date and the category are directly related to
the contact data in the address book.</para>

<programlisting>  &lt;foaf:firstName&gt;Norman&lt;/foaf:firstName&gt;
  &lt;c:middleName&gt;David&lt;/c:middleName&gt;
  &lt;foaf:surname&gt;Walsh&lt;/foaf:surname&gt;
  &lt;foaf:name&gt;Norman David Walsh&lt;/foaf:name&gt;</programlisting>

<para xml:id="p19">First and last names are available in FOAF. At the moment middle
names aren't, so I've created a <literal>middleName</literal>
property. Generating the full <literal>foaf:name</literal> is
straight-forward, so I do that as well.</para>

<programlisting>  &lt;c:associatedName&gt;Sun Microsystems, Inc.&lt;/c:associatedName&gt;
  &lt;c:associatedTitle&gt;XML Standards Architect&lt;/c:associatedTitle&gt;</programlisting>

<para xml:id="p20">These properties associate a company name and title with a contact.
(There's room for some additional modeling complexity in titles as person,
company, and title form a three-part relationship, but I've never seen an
electronic address book that tried to handle that situation, so let's not
worry about it.)</para>

<programlisting>  &lt;c:dateOfBirth rdf:datatype="http://www.w3.org/2001/XMLSchema#date"&gt;1967-06-16&lt;/c:dateOfBirth&gt;
  &lt;foaf:birthday&gt;06-16&lt;/foaf:birthday&gt;</programlisting>

<para xml:id="p21">The FOAF <literal>birthday</literal> property, unfortunately,
doesn't support full dates, so I've had to invent one. But I can
generate the FOAF version as well.</para>

<programlisting>  &lt;foaf:weblog rdf:resource="http://norman.walsh.name/"/&gt;
  &lt;foaf:homepage rdf:resource="http://nwalsh.com/"/&gt;</programlisting>

<para xml:id="p22">The URIs convert naturally to FOAF properties. Some of my contacts
have other sorts of URIs (entries in the
<link xlink:href="http://www.getty.edu/research/conducting_research/vocabularies/tgn/">Getty Thesaurus of Geographic Names®</link>, the
<link xlink:href="http://www.cia.gov/cia/publications/factbook/">CIA World
Factbook</link>, etc.) for which I've invented additional properties.</para>

<programlisting>  &lt;c:workMbox rdf:resource="mailto:Norman.Walsh@Sun.COM"/&gt;
  &lt;foaf:mbox_sha1sum&gt;9f5c771a25733700b2f96af4f8e6f35c9b0ad327&lt;/foaf:mbox_sha1sum&gt;
  &lt;c:personalMbox rdf:resource="mailto:ndw@nwalsh.com"/&gt;
  &lt;foaf:mbox_sha1sum&gt;5ddcd862514c327945dca20446e11cb54ceec68b&lt;/foaf:mbox_sha1sum&gt;</programlisting>

<para xml:id="p23">I've invented subproperties of <literal>foaf:mbox</literal> for various
kinds of email addresses.</para>

<programlisting>  &lt;c:workPhone rdf:resource="tel:+1-413-303-1382"/&gt;
  &lt;c:workPhone rdf:resource="tel:+1-413-256-xxxx"/&gt;
  &lt;c:homePhone rdf:resource="tel:+1-413-256-xxxx"/&gt;
  &lt;c:mobilePhone rdf:resource="tel:+1-413-949-xxxx"/&gt;</programlisting>

<para xml:id="p24">Similarly, I've invented subproperties of <literal>foaf:phone</literal>
for various kinds of phone numbers.</para>

<programlisting>  &lt;c:homeAddress rdf:parseType="Resource"&gt;
    &lt;rdf:type rdf:resource="http://nwalsh.com/rdf/contacts#Address"/&gt;
    &lt;c:street&gt;XX Xxxx Street&lt;/c:street&gt;
    &lt;c:city&gt;Belchertown&lt;/c:city&gt;
    &lt;c:stateOrProvince&gt;MA&lt;/c:stateOrProvince&gt;
    &lt;c:postcode&gt;01007&lt;/c:postcode&gt;
  &lt;/c:homeAddress&gt;
  &lt;c:workAddress rdf:parseType="Resource"&gt;
    &lt;rdf:type rdf:resource="http://nwalsh.com/rdf/contacts#Address"/&gt;
    &lt;c:street&gt;1 Network Drive, Building #2
MS UBUR02-201&lt;/c:street&gt;
    &lt;c:city&gt;Burlington&lt;/c:city&gt;
    &lt;c:stateOrProvince&gt;MA&lt;/c:stateOrProvince&gt;
    &lt;c:postcode&gt;01803&lt;/c:postcode&gt;
  &lt;/c:workAddress&gt;</programlisting>

<para xml:id="p25">Continuing to follow that pattern, I invented a class for postal
addresses, an <literal>address</literal> property, and subproperties of
it for various kinds of addresses.</para>

<programlisting>  &lt;c:notes&gt;rdf:
a g:Male
geo:lat 42.3382
geo:long -72.45
foaf:page http://norman.walsh.name/foaf

AccessLine is x53142&lt;/c:notes&gt;</programlisting>

<para xml:id="p26">Finally, the <literal>notes</literal> property holds notes about
the contact. I parse pseudo-N3 from the notes field to add additional
properties to the record.</para>

<programlisting>  &lt;rdf:type rdf:resource="http://nwalsh.com/rdf/genealogy#Male"/&gt;
  &lt;geo:lat&gt;42.3382&lt;/geo:lat&gt;
  &lt;geo:long&gt;-72.45&lt;/geo:long&gt;
  &lt;foaf:page rdf:resource="http://norman.walsh.name/foaf"/&gt;
&lt;/rdf:Description&gt;</programlisting>

<para xml:id="p27">The collected RDF for all my contacts are then augmented by
additional inference rules to build a final, combined model for my
“personal information manager”. One example of a rule is this one:</para>

<programlisting>{ ?c a foaf:Organization .
  ?c c:associatedName ?t .
  ?p a foaf:Person .
  ?p c:associatedName ?t } =&gt; { ?p c:associatedWith ?c } .</programlisting>

<para xml:id="p28">This rule says that if there's an organization (for example, an
entry in my address book with only a company name) and a person with
the same association, then that person is associated with that
organization. So, for example, when I format the address book entry
for that company, I get pointers to all the people I know who work for
that company. I also have a vocabulary for relationships inside Sun
(employee numbers, department numbers, reporting structures, etc.)
that I can “scrape” from the internal name finder. Rules associated
with terms in that vocabulary allow me to generate appropriate
cross-references between employees, departments, etc.</para>
</section>

<section xml:id="ont">
<title>The Ontology</title>

<para xml:id="p29">The
<link xlink:href="http://nwalsh.com/rdf/contacts">resulting ontology</link>
is:</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 c: &lt;http://nwalsh.com/rdf/contacts#&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; .
@prefix foaf: &lt;http://xmlns.com/foaf/0.1/&gt; .

&lt;http://nwalsh.com/rdf/contacts&gt; a owl:Ontology;
    rdfs:comment "Norm's ontology for his address book." .

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

# A contact in an address book
c:Contact a owl:Class;
    rdfs:subClassOf
        [
             a owl:Restriction;
             owl:cardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:lastModified ] .

# Timestamp of address book entry
c:lastModified a owl:DatatypeProperty;
    rdfs:domain c:Contact;
    rdfs:range xs:dateTime .

# Category in address book
c:category a owl:DatatypeProperty;
    rdfs:domain c:Contact .

# A middle name (other name properties come from FOAF)
c:middleName a owl:DatatypeProperty .

# Company and title
c:associatedName a owl:DatatypeProperty .
c:associatedTitle a owl:DatatypeProperty .

# Birthday
c:dateOfBirth a owl:DatatypeProperty;
    rdfs:range xs:dateTime .

# Email addresses
c:personalMbox a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:mbox .

c:workMbox a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:mbox .

c:pagerMbox a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:mbox .

c:obsoleteMbox a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:mbox .

# Phone numbers
c:dataPhone a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:phone .

c:fax a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:phone .

c:homePhone a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:phone .

c:workPhone a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:phone .

c:mobilePhone a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:phone .

c:pagerPhone a owl:ObjectProperty;
     rdfs:subPropertyOf foaf:phone .

# Notes
c:notes a owl:DatatypeProperty .

# Postal address
c:Address a owl:Class;
    rdfs:subClassOf
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:street ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:city ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:stateOrProvince ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:postcode ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:country ] .

# Addresses
c:address a owl:ObjectProperty;
     rdfs:range c:Address .

c:workAddress a owl:ObjectProperty;
     rdfs:subPropertyOf c:address .

c:homeAddress a owl:ObjectProperty;
     rdfs:subPropertyOf c:address .

# Fields of an address
c:street a owl:DatatypeProperty;
   rdfs:domain c:Address;
   rdfs:range xs:string .

c:city a owl:DatatypeProperty;
   rdfs:domain c:Address;
   rdfs:range xs:string .

c:stateOrProvince a owl:DatatypeProperty;
   rdfs:domain c:Address;
   rdfs:range xs:string .

c:postcode a owl:DatatypeProperty;
   rdfs:domain c:Address;
   rdfs:range xs:string .

c:country a owl:DatatypeProperty;
   rdfs:domain c:Address;
   rdfs:range xs:string .
</programlisting>

<para xml:id="p30">I have a few additional constraints that I think are limited
to my particular address book:</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 c: &lt;http://nwalsh.com/rdf/contacts#&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; .
@prefix foaf: &lt;http://xmlns.com/foaf/0.1/&gt; .

c:Contact
    rdfs:subClassOf
        [
             a owl:Restriction;
             owl:cardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:category ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty foaf:firstName ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty foaf:surname ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:middleName ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:associatedName ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:associatedTitle ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty c:dateOfBirth ],
        [
             a owl:Restriction;
             owl:maxCardinality "1"^^xs:nonNegativeInteger;
             owl:onProperty foaf:birthday ] .

foaf:Organization
    rdfs:subClassOf
        [
             a owl:Restriction;
             owl:cardinality "0"^^xs:nonNegativeInteger;
             owl:onProperty foaf:firstName ],
        [
             a owl:Restriction;
             owl:cardinality "0"^^xs:nonNegativeInteger;
             owl:onProperty foaf:surname ],
        [
             a owl:Restriction;
             owl:cardinality "0"^^xs:nonNegativeInteger;
             owl:onProperty foaf:name ],
        [
             a owl:Restriction;
             owl:cardinality "0"^^xs:nonNegativeInteger;
             owl:onProperty foaf:nick ] .

c:Place a owl:Class;
  rdfs:subClassOf foaf:Agent .

c:gettyTGN a owl:ObjectProperty;
   rdfs:subPropertyOf foaf:page .

c:ciaFactbook a owl:ObjectProperty;
   rdfs:subPropertyOf foaf:page .

c:weather a owl:ObjectProperty;
   rdfs:subPropertyOf foaf:page .

c:associatedWith a owl:ObjectProperty;
    rdfs:domain foaf:Person;
    rdfs:range foaf:Organization .

c:hasAssociated a owl:ObjectProperty;
    rdfs:domain foaf:Organization;
    rdfs:range foaf:Person .

</programlisting>

</section>

<section xml:id="openq">
<title>Open Questions</title>

<para xml:id="p31">Should some of this be incorporated into FOAF? Should I have
tried to use the
<link xlink:href="http://www.w3.org/TR/vcard-rdf">vCard</link> schema
instead? And of course, which bits could be modelled better?</para>
</section>

</essay>

