Real Web 2.0: Practical linked, open data with Exhibit

Discover a tool for managing data the right way, while reducing burdens on developers and users

In the previous installment of this column you learned about Linking Open Data (LOD), a community initiative for moving the Web from separated documents to a broad information space of data. That article covered the main ideas of LOD, and in this article you will see how to quickly put these ideas to use. Learn about the Exhibit Web library from the MIT Simile project, which allows you to construct functional and visually attractive user interfaces without much work, once you have good LOD available.

Share:

Uche Ogbuji (uche@ogbuji.net), Partner, Zepheira, LLC

Uche photoUche Ogbuji is Partner at Zepheira, LLC, a solutions firm specializing in the next generation of Web technologies. Mr. Ogbuji is lead developer of 4Suite, an open source platform for XML, RDF and knowledge-management applications and lead developer of the Versa RDF query language. He is a Computer Engineer and writer born in Nigeria, living and working in Boulder, Colorado, USA. You can find more about Mr. Ogbuji at his Weblog Copia.



13 May 2008

Also available in Chinese

Last time in Real Web 2.0 I discussed Linking Open Data (LOD), a movement focusing on a few simple principles for increasing the value of collections of data published on the Web (see the previous article). I mentioned once again that Ajax is not the true essence of LOD nor even Web 2.0, but that it is valuable because of how, when used well, it can enhance the usability of Web sites. This fact is not lost on the LOD community, and in addition to promoting sound Web architecture, the community has been developing tools to show off attractive results. A major hub of such development is SIMILE (Semantic Interoperability of Metadata and Information in unLike Environments), a research project developing tools to share diverse collections of data and digital media. SIMILE is a joint project of Massachusetts Institute of Technology (MIT) and the W3C, and it has produced some real gems. One of these is Exhibit, which allows you to produce Web pages with widgets the user can use to quickly comb through large collections of data. Exhibit makes this easy and requires little programming. It is developed by David Huynh, with contributions from others on the SIMILE team. In this article I'll show you how to use Exhibit to publish LOD without tears.

It's all about the data

First I'll focus on the data to be published with Exhibit. Exhibit works on JSON input following a simple set of conventions. Listing 1 is a basic outline you can use for a starting point on most Exhibit ventures.

Listing 1. Exhibit JSON skeleton
    {
  items: [
    {
      "label": ...,
      ...
    },
    {
      "label": ...,
      ...
    },
    ...
  ]
}

This is the outline of a JSON object with a single property named items, whose value is an array of objects. Each of the item objects can have any set of properties, and these properties are what Exhibit uses to construct the user interface.

A good data source

I'd like to create an Exhibit from the Web feed of recent contributions to the Open Clip Art Library, a collection of clip art available under generous licenses. A Web feed is a nice showcase for Exhibit, as it includes linked data with titles, dates, and categories (also know as tags) that are useful for users looking for information. Open Clip Art Library includes images in its Atom 1.0 feed, which is also nice for showing off Exhibit. The Atom 1.0 flavor of Web feed is especially useful because it is designed with solid, LOD-compatible principles. Listing 2 (clipart.feed.xml) is a representative sample trimmed from a recent snapshot of the feed in question.

Listing 2 (clipart.feed.xml). Atom 1.0 feed of recent contributions to the Open Clip Art Library
                <feed xmlns="http://www.w3.org/2005/Atom">
  <title>Open Clip Art Library (clip_art)</title>
  <link rel="self" href="http://openclipart.org/media/feed/atom/clip_art"></link>
  <link rel="alternate" href="http://openclipart.org/media/feed/atom/clip_art"></link>
  <updated>2008-03-11T20:06:06+00:00</updated>
  <id>http://openclipart.org/media/feed/atom/clip_art</id>
  <entry>
      <id>http://openclipart.org/media/files/adriano/8006</id>
      <title>Hard Hat</title>
      <author>
        <name>Adriano Ribeiro</name>
      </author>
      <logo>http://openclipart.org/people/adriano/avatar.gif</logo>
      <link rel="alternate" href="http://openclipart.org/media/files/adriano/8006"
 type="text/html"></link>
      <link rel="enclosure"
href="http://openclipart.org/people/adriano/adriano_Hard_Hat.svg"
 length="9353" type="image/svg+xml"></link>
         <category term="unchecked"></category>
         <category term="public_domain"></category>
         <category term="image"></category>
         <category term="tool"></category>
         <category term="man"></category>
         <category term="hat"></category>
         <category term="hard"></category>
         <category term="work"></category>
         <category term="wrench"></category>
      <updated>2008-03-11T20:06:06+00:00</updated>
      <content type="text/plain">A yellow hard hat and a wrench</content>
      <link rel="license" href="http://creativecommons.org/licenses/publicdomain"
 type="text/html"></link>
  </entry><entry>
      <id>http://openclipart.org/media/files/Caggles/8005</id>
      <title>Ship's Badge</title>
      <author>
        <name>Caggles</name>
      </author>
      <logo>http://openclipart.org/ccimages/person.png</logo>
      <link rel="alternate" href="http://openclipart.org/media/files/Caggles/8005"
 type="text/html"></link>
      <link rel="enclosure"
href="http://openclipart.org/people/Caggles/Caggles_Ship_s_Badge.svg"
 length="99224" type="image/svg+xml"></link>
         <category term="unchecked"></category>
         <category term="public_domain"></category>
         <category term="image"></category>
         <category term="svg"></category>
         <category term="png"></category>
         <category term="badge"></category>
         <category term="heraldry"></category>
         <category term="crest"></category>
         <category term="navy"></category>
         <category term="ship"></category>
         <category term="insignia"></category>
      <updated>2008-03-11T16:45:01+00:00</updated>
      <content type="text/plain">Blank outline for a Royal Navy ship's crest.
      </content>
      <link rel="license" href="http://creativecommons.org/licenses/publicdomain"
 type="text/html"></link>
  </entry>
</feed>

From Atom to JSON

There are many ways to turn Atom 1.0 into JSON, and several people have already written XSLT scripts, of varying quality, for the purpose. I generally use Python code, however, having had a lot of luck combining a very friendly library for processing arbitrary XML with a very friendly library for processing JSON. The former is Amara XML Toolkit, and the latter is simplejson. Listing 3 is a complete script (atom2json.py) to generate Exhibit JSON from Atom such as in Listing 2.

Listing 3 (atom2json.py). script to convert Atom to Exhibit JSON
                import sys
import amara
import simplejson

#Parse Atom XML from the file name or URL given on the command line
source = sys.argv[1]
doc = amara.parse(source)

#This is a list comprehension.  It iterates over the list of entry elements
#And creates a Python dictionary for each, with keys and values drawn from
#Each entry.
entries = [
    #Result spec of the list comprehension
    {
        u"label": unicode(e.id),
        u"type": u"Entry",
        u"title": unicode(e.title),
        #Nested list comprehension to select the alternate link,
        #then select the first result ([0]) and gets its href attribute
        u"link": [ l for l in e.link if l.rel == u"alternate" ][0].href,
        u"author": unicode(e.author.name),
        u"logo": unicode(e.logo),
        #Nested list comprehension to create a list of category values
        u"categories": [ unicode(c.term) for c in e.category ],
        u"updated": unicode(e.updated),
        u"content": unicode(e.content),
    }
    #Iteration spec of the list comprehension
    for e in doc.feed.entry
]

exhibit_obj = {'items': entries}

#Write the result as JSON to the console
simplejson.dump(exhibit_obj, sys.stdout, indent=4)

Amara allows access to the XML document in a very simple way, as if it were a structure of Python. (It tries to balance this with preserving the basic nature of XML.) simplejson allows you to read or write JSON using Python equivalents, such as a Python list for a JSON array or a Python dictionary (an associative array or hash table type). Listing 4 (feed.js) is the output from running Listing 3, invoked as follows: python atom2json.py clipart.feed.xml > feed.js. Use whatever tools and technology you prefer for generating the JSON, and then you're on to the fun part.

Listing 4 (feed.js). Exhibit JSON created using Listing 3
                {
    "items": [
        {
            "updated": "2008-03-11T20:06:06+00:00",
            "title": "Hard Hat",
            "author": "Adriano Ribeiro",
            "label": "http:\/\/openclipart.org\/media\/files\/adriano\/8006",
            "content": "A yellow hard hat and a wrench",
            "link": "http:\/\/openclipart.org\/media\/files\/adriano\/8006",
            "logo": "http:\/\/openclipart.org\/people\/adriano\/avatar.gif",
            "type": "Entry",
            "categories": [
                "unchecked",
                "public_domain",
                "image",
                "tool",
                "man",
                "hat",
                "hard",
                "work",
                "wrench"
            ]
        },
        {
            "updated": "2008-03-11T16:45:01+00:00",
            "title": "Ship's Badge",
            "author": "Caggles",
            "label": "http:\/\/openclipart.org\/media\/files\/Caggles\/8005",
            "content": "Blank outline for a Royal Navy ship's crest. \n      ",
            "link": "http:\/\/openclipart.org\/media\/files\/Caggles\/8005",
            "logo": "http:\/\/openclipart.org\/ccimages\/person.png",
            "type": "Entry",
            "categories": [
                "unchecked",
                "public_domain",
                "image",
                "svg",
                "png",
                "badge",
                "heraldry",
                "crest",
                "navy",
                "ship",
                "insignia"
            ]
        }
    ]
}

Setting up the page

Now that I have the data ready, Exhibit makes the rest fairly simple. Listing 5 (feed.html) is a basic Web page to present the feed.

Listing 5 (feed.html). Basic Web page
                <html>
<head>
  <title>Open Clip Art Library--recent contributions</title>
  <link href="feed.js" type="application/json" rel="exhibit/data" />
    <script src="http://static.simile.mit.edu/exhibit/api-2.0/exhibit-api.js"
          type="text/javascript"></script>
<script src="http://static.simile.mit.edu/exhibit/extensions-2.0/time/time-extension.js"
          type="text/javascript"></script>

    <style>
       #main { width: 100%; }
       #timeline { width: 100%; }
       .entry { border: thin solid black; width: 100%; }
       #facets  { padding: 0.5em; vertical-align: top; }
       div.title { font-weight: bold; font-size: 150%; }
       .updated { font-style:  italic; }
       .tags { color:  purple; }
       .label { display: none; }
   </style>
</head>
<body>
  <h1>Open Clip Art Library--recent contributions</h1>
  <table id="main">
    <tr>
      <!-- The main display area for Exhibit -->
      <td ex:role="viewPanel">
        <div id="what-lens" ex:role="exhibit-view"
                            ex:viewClass="Exhibit.TileView"
                            ex:label="What">

          <!-- Custom view ("lens") for the feed data -->
          <table ex:role="lens" class="entry">
            <!-- The tr acts as a template.
                Each item object in the JSON generates one such tr -->
            <tr>
              <td><img ex:src-content=".logo" /></td>
              <td>
                <div ex:content=".label" class="label"></div>
                <a ex:href-content=".link">
                  <div ex:content=".title" class="title"></div>
                </a>
                <div>
                  by <span ex:content=".author" class="author"></span>,
                  updated <span ex:content=".updated" class="updated"></span>
                </div>
                <div ex:content=".content" class="content"></div>
                Tags: <div ex:content=".categories" class="tags"></div>
              </td>
            </tr>
          </table>

        </div>
        <!-- Timeline view for the feed data -->
        <div id="timeline" ex:role="view"
             ex:viewClass="Timeline"
             ex:label="When"
             ex:start=".updated"
             ex:colorKey=".author"
             ex:topBandUnit="day"
             ex:topBandPixelsPerUnit="200"
             ex:topBandUnit="week">
         </div>
       </td>
       <!-- Boxes to allow users narrow down their view of feed data -->
       <td id="facets">
           <div ex:role="facet" ex:facetClass="TextSearch"></div>
           <div ex:role="facet" ex:expression=".author" ex:facetLabel="Author"></div>
           <div ex:role="facet" ex:expression=".categories" ex:facetLabel="Tag"></div>
       </td>
     </tr>
   </table>
</body>
</html>

The script elements in the header pull in the Exhibit code from the public service at MIT. The second one is only needed if you want to use Exhibit's timeline capability, discussed later in this section. In the first td element you'll notice the first special instruction attribute for Exhibit, ex:role. This allows you to map constructs in the HTML to processing hooks for Exhibit's JavaScript. This first example sets up the overall view area where Exhibit will operate. Within that role there are additional blocks of different roles. The first sets up the default view for Exhibit, which is just a table of the contents of the feed. I wanted close control over how the data was rendered in HTML, so I used a lens role.

A lens allows you to say things like: "fill this span with the contents of the title property in the data". In this case I'm filling up a table, and the tr serves as a template for displaying each entry. I generate element content by using an ex:content instruction. I generate an href attribute (for a hyperlink) by using ex:href-content, a src attribute (for an image) using ex:src-content, and so on. Exhibit automatically turns the list property categories into comma-separated values.

I also create a view with ex:viewClass="Timeline". This sets up Exhibit to generate a very neat timeline display, which is better illustrated than described (see next section). Finally, Exhibit offers facets, a set of tools to help users search and narrow down the data to find what they need. In Listing 5 these are defined in the facets div. There are three boxes, one an incremental search field. The user can just start typing in this box and the entries shown will be narrowed down to those that contain the search text. The other two boxes are lists of properties (author and tag, respectively) the user can select to narrow down the entries to only those that match.


Show and tell

Exhibit is definitely more effective to show than to describe. Figure 1 is what Listing 5 looks like in the Safari browser on Mac OS X Leopard.

Figure 1. Open Clip Art contributions Exhibit
Open Clip Art contributions Exhibit

The left-hand side has the output from the lens. Notice the ungrammatical "2 Entry" caption. You can tell Exhibit how to spell the plural, but I left that out of this example. In general, you can tweak and customize almost every aspect of Exhibit, and after you get familiar with the basics in this article, be sure to experiment and learn how to get the most from the tool. You can control the sorting of entries based on properties, but in this simplified example, with only two entries, sorting is hardly an issue. On the right-hand side are the facets. The text search box is on top, and the boxes allow you to select properties to narrow down the list of entries. The user can click the "When" link on the top to get the timeline view, shown in Figure 2.

Figure 2. Open Clip Art contributions timeline view
Open Clip Art contributions timeline view

In Listing 5 I specified two Exhibit instructions that set up this view. ex:start=".updated" tells Exhibit to plot the updated property of each entry against a time axis, using ex:topBandUnit="day" and ex:topBandPixelsPerUnit to tailor the axis. By default, timeline uses the label property for the label of each entry. The user can click within the timeline box and drag left or right to pan the view.


The Exhibit way

There are a few things to keep in mind as you prepare data for Exhibit. You need a label property, which Exhibit actually treats as an identifier (in other words, it folds together objects with the same label). Use a type property, which Exhibit uses to organize the data. If you omit it, the default is type Item. Provide dates in the W3C's recommended flavor of ISO-8601. If you have location information, provide it in terms of latitude and longitude so Exhibit can create a map view within Google Maps. Finally, make sure you have links: for your items, for their types, and more. Learn how Exhibit uses schemata to organize data sets. Exhibit's details are sometimes odd and idiosyncratic, but considering what it achieves in such a difficult space (dynamic, cross-browser display), it's worthwhile to get a rich sense of how Exhibit organizes information. The nice thing is that it's so easy to experiment with that you can learn its ways quickly.

The principles of LOD are very important, but when a Web developer has a deadline looming it's not always easy to put "important" into perspective. Exhibit is one of those tools that takes a grand idea and uses it to actually make a developer's life easier. If you have a collection of information and you need to present it to users so they can easily see it in context and find details they care about, take advantage of the large head start Exhibit offers.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=307361
ArticleTitle=Real Web 2.0: Practical linked, open data with Exhibit
publish-date=05132008