<?xml version='1.0' encoding='utf-8'?>
<?xml-stylesheet href="/style/browser.xsl" type="text/xsl"?>
<essay 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/"
       xml:lang="en"
       version='5.0'>
<info>
<title>PIM Example</title>
<volumenum>8</volumenum>
<issuenum>163</issuenum>
<pubdate>2005-12-16T12:36:44-05:00</pubdate>
<date>$Date: 2005-12-16 16:26:00 -0500 (Fri, 16 Dec 2005) $</date>
<author><personname>
<firstname>Norman</firstname><surname>Walsh</surname>
</personname></author>
<copyright><year>2005</year><holder>Norman Walsh</holder></copyright>
<abstract>
<para>An example of how I use the vCard ontology and all this XML+RDF stuff.
</para>
</abstract>
</info>

<epigraph>
<attribution><personname><firstname>Franklin P.</firstname>
<surname>Adams</surname></personname></attribution>
<para xml:id='p2'>I find that a great part of the information I have was acquired
by looking up something and finding something else on the way.
</para>
</epigraph>

<para xml:id='p1'>A couple of people expressed interested in
my <link xlink:href="http://en.wikipedia.org/wiki/XML">XML</link>+<link xlink:href="http://en.wikipedia.org/wiki/Resource_Description_Framework">RDF</link>
“<link xlink:href="http://en.wikipedia.org/wiki/Personal_information_manager">personal information manager</link>”
setup.
<personname><firstname>Dave</firstname><surname>Pawson</surname>
</personname>
<link xlink:href="http://norman.walsh.name/2005/12/12/vcard#comment0007">wants</link>
to see some examples and someone else wants
to know why I bother with all the
RDF. I
<link xlink:href="http://nwalsh.com/docs/presentations/extreme2002/">presented</link>
these ideas at
<link xlink:href="http://www.extrememarkup.com/">Extreme Markup Languages</link>
2002, but some of the details have changed, so I think it's probably worth
running through it again.</para>

<para xml:id='p3'>The main points are: a lot of the actual entries in my PIM are
related to each other (hotels are related to conferences are related to
<link xlink:href="http://norman.walsh.name/2005/itinerary/11-14-xml">trip itineraries</link>;
individuals are related to each other; meetings on my
calendar take place at facilities in my address book; teleconferences use
phone numbers in my address book; etc.). A PIM represents a model of the
real world and human beings are really good at making inferences about
the real world. Well, RDF can easily express the relationships in my
PIM, RDF makes aggregation easy, and RDF can be used to make inferences
in the model. Win, win, win, from my point of view.</para>

<para xml:id='p4'>To make the explanation interesting, let's work through a
concrete example. Let's say I have two friends, Dick and Jane; they're
married, they have a child. We can draw lots of inferences from this
information, but let's see if we can teach the machine to do it for
us. Along the way, we'll avoid the evils of duplicated data.</para>

<para xml:id='p5'>Our example begins with the
<link xlink:href="examples/contact.xml">XML data</link>
that comes straight off my
<link xlink:href="http://en.wikipedia.org/wiki/T-Mobile_Sidekick">Sidekick</link>.
Here's a fragment of the entry for Dick:</para>

<programlisting><![CDATA[<contact id='_1109'>
  <category>Friends</category>
  <first_name>Richard</first_name>
  <last_name>Smith</last_name>
  <addresses>
    <item>
      <city>Anytown</city>
      <zip>01010</zip>
      <label>Work</label>
      <state>MA</state>
      <street>123 Corporate Plaza</street>
    </item>
  </addresses>
  <nick_name>Dick</nick_name>
  <notes>rdf:
p:livesWith #jane-jones
p:child #robbie-jones
a g:Male</notes>
  <id>1109</id>
  <phone_numbers>
    <item>
      <number>+1-413-555-1234</number>
      <label>Work</label>
    </item>
  </phone_numbers>
  ...]]></programlisting>

<para xml:id='p6'>We can see that Dick has the information you'd expect in a PIM:
a work address (but importantly, not a home address), a phone number,
etc. There's also a notes field where I've encoded a little bit of RDF
in a subset of
<link xlink:href="http://en.wikipedia.org/wiki/Notation_3">N3</link>.
That's how I add arbitrary additional metadata to each entry.
That'll be important in just a little bit.</para>

<para xml:id='p7'>The first step in our journey is to transform this data into
<link xlink:href="examples/addrbook.xml">something more palatable</link>.
The little bit of
<link xlink:href="http://en.wikipedia.org/wiki/Python_programming_language">Python</link> that does this extracts the RDF encoded in the notes and makes certain
other adjustments (for example, for appointments that are classified as flights,
it extracts departure and arrival airports, carrier, and flight number
data from the title field). The fragment above comes out like this:</para>

<programlisting><![CDATA[<contact id="_1109">
  <category>Friends</category>
  <firstname>Richard</firstname>
  <surname>Smith</surname>
  <nickname>Dick</nickname>
  <phones>
    <phone label="Work">+1-413-555-1234</phone>
  </phones>
  <addresses>
    <address label="Work">
      <street>123 Corporate Plaza</street>
      <city>Anytown</city>
      <state>MA</state>
      <postcode>01010</postcode>
    </address>
  </addresses>
  <notes>rdf:
p:livesWith #jane-jones
p:child #robbie-jones
a g:Male</notes>
  <p:livesWith rdf:resource="http://norman.walsh.name/knows/who#jane-jones"/>
  <p:child rdf:resource="http://norman.walsh.name/knows/who#robbie-jones"/>
  <rdf:type rdf:resource="http://nwalsh.com/rdf/genealogy#Male"/>
</contact>]]></programlisting>

<para xml:id='p8'>From here, it's
<link xlink:href="examples/addr2rdf.xsl">an easy step</link> to
<link xlink:href="examples/addrbook.rdf">RDF</link>. This is where
the vCard markup comes into play. In fact, I could (maybe should) do this
transformation in two steps: going from my address book to vCard and then
from vCard to more “colloquial RDF”. If I was really starting with vCards that's
what I'd do. But since I'm starting with my own markup, I combine the two
steps, producing colloquial RDF directly. The advantage of colloquial
RDF is that it uses shared vocabularies and is therefore more amenable to reuse
and aggregation. Here's a fragment of Dick's entry in RDF:</para>

<programlisting><![CDATA[<foaf:Person rdf:about="http://norman.walsh.name/knows/who#dick-smith">
   <rdf:type rdf:resource="http://nwalsh.com/rdf/contacts#Contact"/>
   <c:category>Friends</c:category>
   <foaf:firstName>Richard</foaf:firstName>
   <foaf:surname>Smith</foaf:surname>
   <foaf:name>Richard Smith</foaf:name>
   <foaf:nick>Dick</foaf:nick>
   <c:workPhone rdf:resource="tel:+1-413-555-1234"/>
   <v:workAdr rdf:parseType="Resource">
      <rdf:type rdf:resource="http://nwalsh.com/rdf/vCard#Address"/>
      <v:street-address>123 Corporate Plaza</v:street-address>
      <v:locality>Anytown</v:locality>
      <v:region>MA</v:region>
      <v:postal-code>01010</v:postal-code>
      <v:country-name>US</v:country-name>
   </v:workAdr>
   <p:livesWith rdf:resource="http://norman.walsh.name/knows/who#jane-jones"/>
   <p:child rdf:resource="http://norman.walsh.name/knows/who#robbie-jones"/>
   <rdf:type rdf:resource="http://nwalsh.com/rdf/genealogy#Male"/>
   ...</foaf:Person>]]></programlisting>

<para xml:id='p9'>Now we've got data we can really <emphasis>use</emphasis>. Before
we get started, let's take a look at the extra bits of RDF associated with
Jane:</para>

<programlisting><![CDATA[<foaf:Person rdf:about="http://norman.walsh.name/knows/who#jane-jones">
   ...
   <c:notes>rdf:
p:spouse #dick-smith
p:child #robbie-jones
p:anniversary "1990-09-19"
a g:Female</c:notes>
   <p:spouse rdf:resource="http://norman.walsh.name/knows/who#dick-smith"/>
   <p:child rdf:resource="http://norman.walsh.name/knows/who#robbie-jones"/>
   <bio:event>
      <bio:Marriage>
         <bio:date rdf:datatype="http://www.w3.org/2001/XMLSchema#date">1990-09-19</bio:date>
      </bio:Marriage>
   </bio:event>
   <rdf:type rdf:resource="http://nwalsh.com/rdf/genealogy#Female"/>
</foaf:Person>]]></programlisting>

<para xml:id='p10'>Note that I've expressed the “p:anniversary” relationship (which is
easy to type in a note) using
a more standard vocabulary.</para>

<para xml:id='p11'>As we can see, Dick lives with Jane; Dick has a child, Robbie; and
Dick's a guy; Jane is married to Dick; Robbie is Jane's biological child too;
Jane's anniversary is 19 September 1990; and Jane's a girl.</para>

<para xml:id='p12'>Now, what are some inferences that we could make? (I'm going to
use <link xlink:href="http://www.w3.org/2000/10/swap/doc/cwm.html">cwm</link>
so I'm using N3 notation for the inference rules.)</para>

<para xml:id='p13'>Well, for one
thing, we know that “lives with” is a reflexive relationship:</para>

<programlisting>{ ?p p:livesWith ?q } => { ?q p:livesWith ?p } .</programlisting>

<para xml:id='p14'>The way you read that is: considering all individuals, if
there's some individual “?p” that has the relationship “p:livesWith”
some other individual “?q”, that implies that “?q” has the relationship
“p:livesWith” “?p”. (There's no relationship between the “p:”
namespace prefix and the variable name “?p”, that's just an unfortunate
coincidence.)</para>

<para xml:id='p15'>In fact, “lives with” is more than reflexive, it's transitive as
well:</para>

<programlisting>{ ?p p:livesWith ?q .
  ?r p:livesWith ?q .
  ?p log:notEqualTo ?r } => { ?r p:livesWith ?p } .</programlisting>

<para xml:id='p16'>(Because “lives with” is both reflexive and transitive,
the last line of that rule avoids “living with” ourselves.)</para>

<para xml:id='p17'>Spouse is a kind of “significant other” relationship:</para>

<programlisting>{ ?p p:spouse ?q } => { ?p p:sigother ?q } .</programlisting>

<para xml:id='p18'>And “significant other” is also a reflexive relationship:</para>

<programlisting>{ ?p p:sigother ?q } => { ?q p:sigother ?p } .</programlisting>

<para xml:id='p19'>Marriage anniversaries are reflexive too.</para>

<programlisting>{ ?p p:spouse ?q .
  ?p bio:event ?b .
  ?b a bio:Marriage . } => { ?q bio:event ?b } .</programlisting>

<para xml:id='p20'>The inference that one draws from “living together” is that the

parties involved share a home address and (ignoring for the moment
teenagers with their own phones) a home phone number:</para>

<programlisting>{ ?p p:livesWith ?q .
  ?q v:homeAdr ?r } => { ?p v:homeAdr ?r } .

{ ?p p:livesWith ?q .
  ?q c:homePhone ?r } => { ?p c:homePhone ?r } .</programlisting>

<para xml:id='p21'>I also store
genealogical data in my address book. We can make some inferences
in that space too about mothers and fathers and siblings:</para>

<programlisting>{ ?p p:mother ?q } => { ?q p:child ?p } .

{ ?p p:father ?q } => { ?q p:child ?p } .

{ ?p p:father ?q .
  ?r p:father ?q .
  ?p log:notEqualTo ?r } => { ?p p:sibling ?r } .

{ ?p p:mother ?q .
  ?r p:mother ?q .
  ?p log:notEqualTo ?r } => { ?p p:sibling ?r } .

{ ?p p:child ?q .
  ?p a g:Female } => { ?q p:mother ?p } .

{ ?p p:child ?q .
  ?p a g:Male } => { ?q p:father ?p } .</programlisting>

<para xml:id='p22'>One piece that's missing so far is the address book entry for
Robbie. Now, in fact, Robbie is only 10 and I don't really need an entry
in my address book for him. I might someday, but not now. So I have an
<link xlink:href="examples/extra.n3">extra little file</link>
where I store such entries:</para>

<programlisting>kwho:robbie-jones a foaf:Person; a c:Contact;
  c:category "Friends";
  foaf:firstName "Robert";
  foaf:surname "Jones";
  foaf:name "Robert Jones";
  foaf:nick "Robbie";
  bio:event [
    a bio:Birth;
    bio:date "1995-05-05"^^xs:date ];
  a g:Male;
  p:livesWith kwho:dick-smith .</programlisting>

<para xml:id='p23'>All that's left now is to shake well, stir, and
serve hot!</para>

<para xml:id='p24'>It's from
<link xlink:href="examples/pim.rdf">this data</link>
that I actually generate the HTML PIM that I use
when I'm working on my computer. Here's the entry for Dick:</para>

<mediaobject>
<imageobject>
<imagedata fileref="examples/dick-smith.png"/>
</imageobject>
<textobject>
<phrase>Richard's address book entry in HTML.</phrase>
</textobject>
</mediaobject>

<para xml:id='p25'>Note, in particular, that Dick has a home address and a home
phone number and I didn't have to duplicate that data in my actual
address book. Dick is also related to Jane:</para>

<mediaobject>
<imageobject>
<imagedata fileref="examples/jane-jones.png"/>
</imageobject>
<textobject>
<phrase>Jane's address book entry in HTML.</phrase>
</textobject>
</mediaobject>

<para xml:id='p26'>and Robbie (who are, in turn, related to each other and Dick):</para>

<mediaobject>
<imageobject>
<imagedata fileref="examples/robbie-jones.png"/>
</imageobject>
<textobject>
<phrase>Robbie's address book entry in HTML.</phrase>
</textobject>
</mediaobject>

<para xml:id='p27'>I use this aggregated data in other ways too. For example, whenever
I start a terminal session, I get a reminder about today's schedule.
On July 5, I'll see something like this:</para>

<screen>Schedule for 05 Jul 2006

              Coming up:
............. Richard Smith's Birthday (06 Jul 2006; tomorrow)

11:00a-12:00p XML Core
02:00p-03:00p XML CG</screen>

<para xml:id='p28'>That data is generated from my PIM. The fact that
Dick's entry in my address book has a birthday associated with it
automatically generates an event in my calendar.</para>

<para xml:id='p29'>And that's the sort of added value that makes XML+RDF worth it
for me.</para>

</essay>
