IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Web development  >

真正的 Web 2.0: 用 Exhibit 真正链接开放数据

探索一种既可以有效管理数据又能减少开发人员和用户负担的工具

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

英文原文

英文原文


级别: 中级

Uche Ogbuji (uche@ogbuji.net), 合伙人, Zepheira, LLC

2008 年 6 月 05 日

在本专栏的 前一期 文章中,您了解了有关 Linking Open Data(LOD)的知识,LOD 是一个社区项目,旨在将 Web 从多个单独文档转移到更为宽广的数据信息空间。前期文章涵盖了 LOD 的主要思想。在本文中,您会看到如何将这些思想付诸实践,并能了解 MIT Simile 项目的 Exhibit Web 库,只要有了好的 LOD,这个库可以让您不需要很多工作就能构建功能齐备且视觉上吸引人的用户界面。

真正的 Web 2.0 的上一期文章中,我讨论了 Linking Open Data(LOD),关注的焦点是一些简单原则,旨在提高 Web 上所发布的数据集价值(请参见 前一期文章)。我还要再次说明的是,Ajax 不是 LOD(甚至 Web 2.0)的真正本质,但它仍然极为重要,因为如果很好地利用,它能增强 Web 站点的可用性。这一事实亦未被 LOD 社区忽略,而且除了促进 Web 架构的完善之外,该社区还在开发各种工具以展示迷人的结果。这类开发的中心是 SIMILE (差异环境内元数据和信息的语义互通性,Semantic Interoperability of Metadata and Information in unLike Environments),这个研究项目开发各种工具来共享形形色色的数据和数字媒体集。SIMILE 是麻省理工学院(MIT)和 W3C 合作的联合项目,它已经产出了很多真正的宝物。Exhibit 就是其中的一个,它让您能够用小部件生成 Web 页面,用户可以用这些小部件来快速梳理大量数据。Exhibit 让该过程变得十分简单,而且需要的编程也很少。它由 David Huynh 开发,并得到 SIMILE 团队中其他人的贡献。在本文中,我将向您展示如何使用 Exhibit 轻松发布 LOD。

一切都与数据有关

首先,我将重点放在那些需要用 Exhibit 发布的数据上面。Exhibit 在处理 JSON 输入时遵守一组简单约定。清单 1 是一个基本概览,可作为大多数 Exhibit 冒险历程的起点。


清单 1. JSON 骨架结构
                
    {
  items: [
    {
      "label": ...,
      ...
    },
    {
      "label": ...,
      ...
    },
    ...
  ]
}

    

上述是一个 JSON 对象的概览,该对象具有一个单一属性,名为 items,其值为一个对象数组。每个这样的条目对象可以具有任何一组属性,而 Exhibit 用这些属性来构造用户界面。

一个很好的数据源

我愿意从人们对 Open Clip Art Library 所做的最新贡献的 Web 提要创建一个 Exhibit,该库内有一组经授权可以使用的艺术剪图。Web 提要是 Exhibit 的一个很好的展示示例,因为它所包括的链接数据具有标题、日期和类别(也称标记),这对于想要寻找信息的用户非常有用。Open Clip Art Library 在其 Atom 1.0 提要中包括了图片,这也是 Exhibit 的一个很好的展示示例。Atom 1.0 格式的 Web 提要非常有用,因为它是用坚实的、与 LOD 兼容的原则创建的。清单 2(clipart.feed.xml)节选自该提要最近的快照,是一个很具代表性的示例。


清单 2 (clipart.feed.xml). 对 Open Clip Art Library 所做最新贡献的 Atom 1.0 提要
                <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>
    

从 Atom 到 JSON

有很多方式可以将 Atom 1.0 转变成 JSON,为此,已经有人编写了多个质量各异的 XSLT 脚本。我通常习惯使用 Python 代码,但幸运的是能够将非常友好的处理 XML 的库和处理 JSON 的库结合起来。前者是 Amara XML Toolkit,后者是 simplejson。清单 3 是完整的脚本 (atom2json.py),用来从 清单 2 所示的 Atom 生成 Exhibit JSON。


清单 3 (atom2json.py). 将 Atom 转变成 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 允许以一种很简单的方式访问 XML 文档,就如同这类文档是 Python 的一种结构一样(它也试图通过保留 XML 的基本特征来在二者之间取得均衡)。simplejson 则允许使用 Python 中的等效工具来读写 JSON,例如,用一个 Python 列表来表示 JSON 数组,或一个 Python dictionary(关联数组或哈希表类型)。清单 4 (feed.js) 是 清单 3 的运行结果,清单 3 可以这么调用:python atom2json.py clipart.feed.xml > feed.js。您可以使用任何自己喜欢的工具和技术来生成 JSON,这样一来,您就能尽享其中的快乐了。


清单 4 (feed.js). 由清单 3 创建的 Exhibit JSON
                {
    "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"
            ]
        }
    ]
}
    





回页首


设置页面

有了这些数据之后,Exhibit 让剩余的工作变得非常简单。清单 5 (feed.html) 是一个用来显示此提要的基本 Web 页面。


清单 5 (feed.html). 基本 Web 页
                <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>

    

头部的 script 元素从 MIT 的公共服务中引入 Exhibit 代码。第二个只有在您想要使用 Exhibit 的时间线功能时才需要,这将在本节的稍后部分讨论。在第一个 td 元素,您会注意到 Exhibit 的第一个特定指令属性 ex:role。该属性用来将 HTML 的构造函数影射到 Exhibit 的 JavaScript 的过程挂钩。第一个例子设立了完整的视图区域,Exhibit 在该区域内执行。在这个角色内还有若干不同角色的附加块。第一个为 Exhibit 设置默认视图,该视图只是此提要的内容表。我需要对数据如何在 HTML 内呈现进行严格控制,所以我使用了 lens

借助 lens,可以表达这类愿望:“用数据内的 title 属性的内容填充这个 span”。在本例中,我填充的是一个表,tr 可充当显示每个条目的模板。我使用 ex:content 指令生成元素内容。我使用 ex:href-content 生成 href 属性(用于超级链接),使用 ex:src-content 生成 src 属性(用于图像),以此类推。Exhibit 会自动将列表属性 categories 转变成以逗号分隔的值。

我还用 ex:viewClass="Timeline" 创建了一个视图。此视图设置 Exhibit 来生成一个十分整齐的时间线显示,这在本文下一节将会得到很好的展示。最后,Exhibit 提供了 facet,这是一组工具,可用来帮助用户搜索和缩小搜索范围以便找到他们所需的数据。这些工具在 清单 5facets div 内定义。内有三个框,一个累加搜索字段。用户在框内开始键入时,框内所显示的输入的范围就会缩小到包含搜索文本的那些。另外两个框是属性列表(分别为作者和标记),用户可以对其进行选择,以便将输入进一步缩小范围到只包括匹配的那些。





回页首


眼见为实

实际展示 Exhibit 比描述更为有效。 图 1清单 5 在 Safari 浏览器(运行于 Mac OS X Leopard)内的显示效果。


图 1. Open Clip Art 对 Exhibit 的贡献

左侧是 lens 的输出。请注意不合文法的 “2 Entry” 标题。您可以告诉 Exhibit 如何拼写名词复数,但我没有在本例中说明。总之,您几乎可以调整和定制 Exhibit 的各个方面,熟悉了本文内的基础知识之后,一定要实践和了解如何最大限度地利用此工具。您也可以基于属性控制输入项的排序,但在这个简单的示例中,只有两个输入项,排序并不是什么急需处理的问题。右侧是 facet。文本搜索框在顶部,这些框允许您选择属性来缩小输入项的范围。用户可以单击顶部的 “When” 链接来获得时间线视图,如 图 2 所示。


图 2. Open Clip Art 时间线视图

清单 5 中,我指定了用来设置这一视图的两个 Exhibit 指令。ex:start=".updated" 告知 Exhibit 根据一个时间轴来设置每一条目的 updated 属性,使用 ex:topBandUnit="day"ex:topBandPixelsPerUnit 来绘制这一轴。默认地,时间线为每个条目的标签使用 label 属性。用户可以在时间线框内单击并向左或向右拖动以展开此视图。





回页首


Exhibit 方式

在为 Exhibit 准备数据时要特别注意几个问题。您要使用 label 属性,实际上,Exhibit 将其视为一个标识符(换言之,它将具有相同标签的对象合拢在一起)。还要使用 type 属性,Exhibit 用该属性来组织数据。如果忽略了,默认的类型将是 Item。请按 W3C 建议的 ISO-8601 标准提供日期。如果具有位置信息,请提供位置的纬度和经度,以便 Exhibit 在 Google Maps 内创建地图视图。最后,请确保具备各类链接:针对条目的、类型的等等。了解 Exhibit 是如何使用 schemata 组织数据集的。Exhibit 的详细信息有时有些怪异,但考虑它在如此困难的空间(动态、跨浏览器显示)所实现的成就,就很值得深入了解 Exhibit 是如何组织信息的。由于实践起来不难,所以您可以很快掌握其中的奥秘。

LOD 的规则非常重要,但当 Web 开发人员疲于应付限期要求时,即使重要的事情也通常很难被注意到。Exhibit 是这样一个工具:它不仅立意很棒,还能应用该立意简化开发人员的工作。如果您有一组信息想要展现给用户,以便用户能在上下文中很容易地看到它并找到详细信息,那么就好好地利用 Exhibit 所提供的巨大优势吧。



参考资料

学习

获得产品和技术

讨论


关于作者

Uche Ogbuji 的照片

Uche Ogbuji 是 Zepheira, LLC 的合伙人,该公司致力于研究下一代 Web 技术的解决方案。Ogbuji 先生是 4SuiteVersa RDF 查询语言的首席开发人员,前者是一个用于 XML、RDF 和知识管理应用程序的开放源码平台。他是一名出生于尼日利亚的计算机工程师和作家,现在美国科罗拉多州的博耳德生活和工作。您可以在他的 Weblog Copia 进一步了解 Ogbuji 先生。




对本文的评价








IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款