Ajax 时间线和语义网
Timeline 使用异步 JavaScript 和 XML (Ajax) 为浏览具有时间组件的信息提供了一个友好的界面。Timeline 网站将 Timeline 描述为 “...时间信息的 Google 地图”。
Timeline 允许您以直观的方式查看时间和持续时间的点。当上下文清晰时,我将这些称为时间事件或简称为事件。不同的粒度级别(小时、天、月、年等)可以向您展示事件之间的相互关系。您可以使用鼠标拖动显示,或双击 Timeline 以在该时间居中。所有事件都可以有点击气泡,显示带有链接和图像的少量 HTML。
使用 Timeline 本身不需要在客户端或 Web 服务器上安装软件。尽管安装 Timeline 没有要求,但在开发 Timeline 网站时,您可以通过在本地计算机上安装 Timeline 来提高重新加载速度。为此,从 Subversion 检出 Timeline 的副本,并在您的 Timeline HTML 文件中更改脚本路径,以指向您的本地副本。
列表 1. 从 Subversion 获取 Timeline 以加快重新加载速度。
$ svn checkout \ http://simile.mit.edu/repository/timeline/
Timeline 通常在 HTML 页面主体的 onLoad() JavaScript 函数中生成。定义一个 HTML div 元素,Timeline 本身将在其中生成。在 onLoad() JavaScript 函数中调用 Timeline.create(),传递此 div 元素的 ID 和用于 Timeline 的信息。
可以使用 Timeline.createBandInfo() 创建多个日、周、月和年滑块,它选择时间单位和屏幕大小,相对于每个频带将消耗的整个 Timeline。Timeline 使用 Timeline.loadXML() 从 XML 文件填充时间事件数据。还应在 onResize() 中调用更新函数,以允许 Timeline 重新绘制自身。
列表 2 中提供了一个显示 Timeline 的 HTML 文件。首先,我们直接从 mit.edu 包含 timeline-api JavaScript 文件。大部分工作在 onLoad() 函数中完成,该函数生成两个频带:一个显示天,另一个显示月。这两个频带作为数组传递到 Timeline.create() 中,以及我们希望 Timeline 创建的 div 标记的 HTML ID。这些频带连接到一个事件源对象,我们通过该对象加载 Timeline XML 文件。syncWith 设置确保当您拖动一个时间频带时,另一个频带将跟随。我们的 OnResize() 函数确保调用 Timelime.layout() 以更新我们的 Timeline。HTML 文件的其余部分仅定义了一些其他元素和一个 div 标记,我们希望在其中创建 Timeline。
列表 3 显示了包含日期的 XML 文件。这包含两种类型的持续时间:一种是我们确定的,另一种只是一个大致的时间窗口。由于 XML 文件不包含凡尔赛事件的 isDuration=“true”,因此它将在 Timeline 上以不同的方式显示。最后一个事件是我们的航班起飞的固定时间点。
事件可以具有链接、图像和与之关联的 HTML 内容。图 1 中的屏幕截图显示了 Firefox 如何呈现此示例。在这里,我单击了 Vierzehnheiligen 事件以显示其图像,其下方将是与此事件关联的 HTML。
Timeline 上的频带可以是非线性的。例如,此频带可以显示天作为其默认单位,直到它遇到繁忙期,此时它显示小时单位,持续三天,然后再恢复为天作为其默认单位。这是使用热区完成的,热区是通过调用 Timeline.createHotZoneBandInfo() 而不是 Timeline.createBandInfo() 并传递频带信息数组来创建的。
列表 2. 显示基本 Timeline 的 HTML
<html> <head> <title>Basic Timeline usage</title> <script src= "http://simile.mit.edu/timeline/api/timeline-api.js" type="text/javascript"> </script> <script> function onLoad() { var eventSource = new Timeline.DefaultEventSource(); var bandInfos = [ Timeline.createBandInfo({ eventSource: eventSource, date: "Sep 14 2006 00:00:00 GMT", width: "40%", intervalUnit: Timeline.DateTime.DAY, intervalPixels: 100 }), Timeline.createBandInfo({ eventSource: eventSource, date: "Sep 14 2006 00:00:00 GMT", width: "60%", intervalUnit: Timeline.DateTime.MONTH, intervalPixels: 200 }) ]; bandInfos[1].syncWith = 0; bandInfos[1].highlight = true; tl = Timeline.create( document.getElementById("my-timeline"), bandInfos); Timeline.loadXML("basic-example.xml", function(xml, url) { eventSource.loadXML(xml, url); }); } var resizeTimerID = null; function onResize() { if (resizeTimerID == null) { resizeTimerID = window.setTimeout(function() { resizeTimerID = null; tl.layout(); }, 500); } } </script> </head> <body onload="onLoad();" onresize="onResize();"> <h1>Basic Timeline usage</h1> <div id="my-timeline" style="height: 250px; border: 1px solid #aaa"> </div> </body> </html>
列表 3. 日期和持续时间在 XML 文件中定义。
<data> <event start="Sep 9 2006 09:00:00 GMT" end="Sep 14 2006 09:00:00 GMT" isDuration="true" title="Visit the Vierzehnheiligen" image="vierzehnheiligen-thumb.jpg" > Visit this impressive church in Germany. More information can be found at its <a href= "http://en.wikipedia.org/wiki/Vierzehnheiligen" >Wikipedia page</a>. </event> <event start="Sep 16 2006 00:00:00 GMT" end="Sep 26 2006 00:00:00 GMT" title="A visit to Versailles?" image="versailles-thumb.jpg" link="http://www.chateauversailles.fr/en/" > Sometime in this window I should get out to Versailles. </event> <event start="Sep 30 2006 00:00:00 GMT" title="Flight back home :(" > The joy has to end sometime :( </event> </data>
默认的 timeline 主题是低对比度的灰色字体和背景,事件以蓝色突出显示。可以使用 JavaScript 和层叠样式表 (CSS) 的组合来自定义此主题,具体取决于您要更改的内容。要更改背景颜色和某些时间频带,您可以创建默认主题 JavaScript 对象的实例,对该对象进行修改,然后将其传递给 Timeline.createBandInfo()。字体颜色使用 CSS 设置。
列表 4 显示了先前 HTML 文件所需的更改,以修改频带颜色和字体信息。在包含 timeline-api 之后,我们覆盖了两个 CSS 类以更改字体颜色并放大主要日期标记。频带颜色和点击气泡大小是主题对象的属性。然后,将此修改后的主题对象作为参数传递给创建频带时的 Timeline.createBandInfo() 函数。结果如图 2 所示。
列表 4. 更生动的主题
<script src= "http://simile.mit.edu/timeline/api/timeline-api.js" type="text/javascript"></script> <style type="text/css"> .timeline-ether-marker-bottom { width: 5em; height: 1.5em; border-left: 1px solid #aaa; padding-left: 2px; color: black; } .timeline-ether-marker-bottom-emphasized { width: 5em; height: 2em; border-left: 1px solid #aaa; padding-left: 2px; color: black; font-size: 120%; font-weight: bold; } </style> <script> function onLoad() { var eventSource = new Timeline.DefaultEventSource(); var theme = Timeline.ClassicTheme.create(); theme.ether.backgroundColors[0] = '#DFD'; theme.ether.backgroundColors[1] = '#EDD'; theme.ether.highlightColor = '#E00'; theme.ether.highlightOpacity = '30'; theme.event.bubble.width = 520; theme.event.bubble.height = 120; var bandInfos = [ Timeline.createBandInfo({ ... intervalPixels: 100, theme: theme }), Timeline.createBandInfo({ ... intervalPixels: 100, theme: theme }) }; ...
syslog 是高度时间相关信息的绝佳来源。Perl 使将 syslog 文件转换为 Timeline 所需的 XML 格式变得容易。在本示例中,我将 Fedora Core 5 中 /var/log/messages 使用的格式转换为 Timeline XML 文件,如列表 5 所示。主要复杂之处在于,默认情况下,syslog 文件中的日期和时间规范中不包含年份。这使得拆分输入的正则表达式更加复杂,因为我们希望分别获取日期和时间,以便我们可以在输出中在它们之间插入年份。
列表 5. 将来自 stdin 的 syslog 文件转换为 stdout 上的 Timeline XML 文件
#!/usr/bin/perl use XML::Writer; my $writer = XML::Writer->new(); $writer->xmlDecl(); $writer->startTag('data'); $thisyear=((localtime)[5]+1900); while( <> ) { # The if() is all one line. if( /([a-zA-Z ]+[0-9]+) ([0-9]+ :[0-9]+:[0-9]+) ([^:]+):(.*)/) { $date=$1; $time=$2; $src=$3; $msg=$4; $writer->startTag( 'event', 'start' => "$date $thisyear $time", 'title' => $src ); $writer->characters( $msg ); $writer->endTag('event'); } } $writer->endTag('data'); $writer->end();
使 Timeline 更高并包含三个频带可以更轻松地在日志中跳转,如列表 6 所示。
列表 6. 用于最佳地移动每日事件的三个频带
var bandInfos = [ Timeline.createBandInfo({ eventSource: eventSource, date: "Sep 7 2006 00:00:00", width: "40%", intervalUnit: Timeline.DateTime.MINUTE, intervalPixels: 100 }), Timeline.createBandInfo({ eventSource: eventSource, date: "Sep 7 2006 00:00:00", width: "30%", intervalUnit: Timeline.DateTime.HOUR, intervalPixels: 200 }), Timeline.createBandInfo({ eventSource: eventSource, date: "Sep 7 2006 00:00:00", width: "30%", intervalUnit: Timeline.DateTime.DAY, intervalPixels: 200 }) ]; bandInfos[1].syncWith = 0; bandInfos[1].highlight = true; bandInfos[2].syncWith = 0; bandInfos[2].highlight = true;
当与某些语义网技术结合使用时,生成和更新 Timeline 变得更简单。此处使用的两个主要技术是支持 SPARQL 查询语言的 RDF 存储和生成 JavaScript 对象表示法 (JSON) 文件的 XSLT 引擎。
使用 RDF 允许您维护单个信息存储,并使用查询选择任何感兴趣的数据。此外,使用 RDF,您可以轻松地将来自多个来源的信息合并到单个 Timeline 中。例如,在单个 Timeline 上查看文件修改时间和 syslog 事件可能很方便。
使用 JSON 允许页面的 JavaScript 以普通 JavaScript 对象的形式访问时间事件。因此,例如,您可以默认将页面居中于来自 JSON 数据的最旧、最新或命名事件。如果时间事件发生变化,这将非常方便,因为 JavaScript 仍然可以正确地将页面居中,而无需修改 HTML 文件以显式指向所需的时间。
RDF 是资源描述框架,它是语义网的最低层。一切都用 RDF 中的三元组来描述——例如,Ben,程序,C++。
与之前的示例不同,RDF 中的三元组是使用统一资源标识符 (URI) 和对象构建的。URI 与 URL 非常相似。主要区别在于,URI 不希望解析为您可以在网络上浏览的内容,而仅旨在唯一标识某些内容。许多人使用 http:// URL 作为 URI。之前的示例更可能在 RDF 中表示,如列表 7 所示。通常,人们不会仅通过他们的名字来唯一标识。
URI 的额外冗长性实际上并不令人担忧,因为大多数处理 RDF 的东西都会让您定义类似于 XML 的命名空间。例如,将 kvo 设置为扩展到 http://www.kvocentral.org/rdf/ 会将示例三元组的第一部分缩短为 kvo:person/Ben。三元组的三个部分被称为主体、谓词和对象。将主体视为定义您正在描述的事物,谓词视为定义您正在描述的主体的哪个部分,而对象视为描述本身是很方便的。
列表 7. 简单的 RDF 三元组
http://www.kvocentral.org/rdf/person/Ben, http://www.kvocentral.org/rdf/activity/programs, http://www.kvocentral.org/rdf/programming-language/C++
SPARQL 是 RDF 数据的查询语言。SPARQL 从 SQL 借用了一些符号。SPARQL 中的变量使用 ?varname 定义。当一个变量在 where 子句中出现多次时,它每次出现都必须具有相同的值。例如,列表 8 中的 SPARQL 查询可以返回多个 ?x, ?name 对,但每个返回的 ?x 都将具有 Sydney 的位置。可选子句意味着如果 ?x 恰好具有与之关联的数字经度,则也将返回该经度。
列表 8. 用于博客的类 SPARQL 查询
SELECT ?x ?name ?dlat WHERE { ?x has-name ?name . ?x has-location "Sydney" . OPTIONAL { ?x geospat:longitude ?dlat } . }
以下一些代码来自或基于 ESW SparqlTimeline 页面(参见在线资源),特别是 sparql2timeline.xsl 文件。
我尝试使用 Redland 和 Rasqal 组合进行 RDF+SPARQL,但在 SPARQL 处理方面遇到了问题。Redland 仍在开发其 SPARQL 查询实现。然后我转而使用 Jena 进行 RDF 处理。Jena 项目以其功能丰富且稳健的 RDF 库而闻名。有关使用 Jena 玩 RSS 博客提要的更多信息,请参阅我的文章“创建 Planet Me 博客聚合器”,该文章发表在 2006 年 4 月号的 Linux Journal 上。
Jena 是用 Java 编写的,因此,您需要 JRE。Jena 本身很容易安装;只需将其解压缩到某个位置,并将其 jar 文件添加到您的 CLASSPATH 环境变量中。对于 bash shell,如列表 9 所示。
列表 9. 设置 Jena 2.4
$ cd ~ $ unzip Jena-2.4.zip $ edit ~/.bashrc # append a handy classpath setup JenaSetup() { for if in ~/Jena-2.4/lib/*.jar; do export CLASSPATH=$CLASSPATH:$if; done } $ . ~/.bashrc $ JenaSetup
个人博客和 Planet 博客聚合器通常提供 RSS 1.0 提要。在 Timeline 上显示 Planet 的 shell 命令如列表 10 所示。planet GNOME RSS 提要 URL 可以直接包含在 Jena SPARQL 命令中。将其分开可以让您存档您的博客或将多个博客合并到一个 RDF 文件中进行查询。
最终命令将包含 SPARQL 查询结果的 XML 文件转换为 JSON 文件。由于 XSLT 输出纯文本,因此在浏览器不喜欢它们的地方可能会有很多换行符。这里的主要罪魁祸首是博客 HTML 内容中的换行符。由于输出是 JSON,博客条目的内容必须包含在 JavaScript 字符串声明中。仅通过用换行符结束每一行来使 JavaScript 字符串声明跨越多行会使许多浏览器感到困惑。一个简单的补救方法是使用 tr(1) 实用程序将换行符替换为无害的空格字符。
列表 10. 为 Planet GNOME 生成 Timeline。
wget -O planet-gnome.xml \ http://planet.gnome.org/rss10.xml java jena.sparql \ --data planet-gnome.xml \ --query rss.rq --results xml \ >|planet.xml xsltproc sparql2timeline.xsl planet.xml \ | tr '\n' ' ' >|planet.json
SPARQL 查询本身如列表 11 所示。每个博客帖子都是一个 RSS 项目。WHERE 子句中的第一行将结果限制为新闻项目(博客帖子)。随后的行选择我们感兴趣的关于每个博客帖子的信息,用于 SELECT 子句。
列表 11. 用于博客的 SPARQL 查询
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX rss: <http://purl.org/rss/1.0/> PREFIX rssc: <http://purl.org/rss/1.0/modules/content/> PREFIX dc: <http://purl.org/dc/elements/1.1/> SELECT distinct ?title ?link ?date ?description WHERE { ?x rdf:type rss:item . ?x rss:link ?link . ?x rss:title ?title . ?x dc:date ?date . ?x rssc:encoded ?description } ORDER BY DESC(?date)
可以对驱动 HTML 文件进行一些更改,以简化查看博客查询结果。第一个选项是将默认目标日期设置为当前时间前几个小时。我们从当前时间向后移动几个小时,因为 Timeline 上最精细的粒度时间频带是小时。这会将最近的帖子放在 Timeline 的右侧,而不是中心。需要更改的片段围绕 bandInfos 声明,如列表 12 所示。
列表 12. 将时间线聚焦于当前时间和日期。
var moveRightOffetInHours = 4; var gmtd = new Date(); var ms = gmtd.getTime() + (gmtd.getTimezoneOffset() * 60000) - moveRightOffetInHours *3600000; var d = new Date(ms); var bandInfos = [ Timeline.createBandInfo({ eventSource: eventSource, date: d, ...
使用 JSON 保留时间事件的一个主要优点是它们可以作为 JavaScript 数组对象访问。为了支持查看任意查询的输出,方便的做法是在 HTML 中使用 JavaScript 将显示居中于 Timeline 上最新的时间事件。尽管获取日期非常容易,但不幸的是,我们必须在 Timeline API 的一些私有区域中进行探索才能做到这一点,这需要调用 layout() 才能使 Timeline 更新其标签以反映时间变化。如列表 13 所示。Timeline 如图 3 所示。
列表 13. 将时间线聚焦于最新的博客帖子。
function onLoad() { ... tl.loadJSON("planet.json", function(json, url) { if( json.events.length ) { var td = Timeline.DateTime.parseIso8601DateTime( json.events[0].start); tl._bands[0]._ether.setDate( td ); tl._bands[1]._ether.setDate( td ); } eventSource.loadJSON(json, url); tl.layout(); }); ...
Evolution 支持日历显示上的时间事件。由于 Timeline 是轻量级的并且完全基于浏览器,因此它也可以在许多袖珍设备上使用。将您的 Evolution 日历信息导出到 Timeline 文件以便随身携带可能很方便。
我正在使用 Evolution 版本 2.6.3;更高版本可能已修复以下一些问题。
要导出您的 Evolution 日历,请右键单击“在此计算机/个人”,然后选择“保存到磁盘”。有两种方法可以获得 RDF 结果:直接导出为 RDF,以及导出为 iCalendar 格式,然后稍后将其转换为 RDF。
从 Evolution 导出事件的主要问题是导出重复事件。在直接 RDF 导出中,结果中只会存在重复事件的第一个实例。在 iCalendar 导出中,您将拥有事件的 RRULE 标记,其中包含有关重复的信息。不幸的是,w3.org 的 fromIcal.py(将 iCalendar 转换为 RDF)对此 RRULE 感到困惑。
直接导出到 RDF 时,您可能会遇到使用已弃用的 RDF 功能的情况,即不显式命名空间 rdf:about 标记。Jena 提供了关于隐式命名空间的警告,不幸的是,它们在 stdout 上而不是 stderr 上。我们希望 stdout 仅包含来自我们查询的有效 RDF 文档。列表 14 中命令顶部的少量 sed 将正确命名空间 about 标记,从而使 Jena 静音。mycal.rdf 是从 Evolution 导出的。
列表 14. 使用 stdout 命名空间 about 标记。
$ sed 's/<Vevent about=/<Vevent rdf:about=/g' \ mycal.rdf >|mycal-clean.rdf $ java jena.sparql \ --data mycal-clean.rdf \ --query evolution-to-timeline.rq \ --results xml >| evolution.xml $ xsltproc sparql2timeline.xsl evolution.xml \ | tr '\n' ' ' >| evolution.json
列表 15 中显示的 SPARQL 查询在 SELECT 子句中使用了与博客查询 SPARQL 相同的名称。由于许多日历事件都将具有持续时间,因此我已将 enddate 添加到 SELECT 子句。
通过在 SELECT 子句中使用相同的名称,我们可以使用相同的 sparql2timeline.xsl 文件进行一些小的修改,以生成我们的 Timeline 的 JSON 数据。sparql2timeline.xsl 的差异如列表 16 所示。
列表 15. 用于 Evolution 日历的 SPARQL 查询 (evolution-to-timeline.rq)
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX ical: <http://www.w3.org/2002/12/cal/ical#> SELECT distinct ?uid ?title ?date ?enddate ?description WHERE { ?x ical:uid ?uid . ?x ical:summary ?title . ?x ical:dtstart ?date . ?x ical:dtend ?enddate . ?x ical:description ?description } ORDER BY DESC(?date)
列表 16. 对 sparql2timeline.xsl 的轻微修改,以将 Evolution 日历数据转换为 JSON
... <xsl:variable name="date"> ... </xsl:variable> <xsl:variable name="enddate"> <xsl:call-template name="escape"> <xsl:with-param name="text" select="res:binding[@name='enddate']/res:literal"/> </xsl:call-template> </xsl:variable> ... </xsl:variable> {'start': '<xsl:value-of select="$date" />', 'end': '<xsl:value-of select="$enddate" />', 'title': '<xsl:value-of select="$title" />', ...
驱动 HTML 文件可以只是 planet.html 的副本,修改为包含 evolution.json 而不是 planet.json。
文件系统信息可以直接写入 XML Timeline 文件,就像上面的 syslog 部分中所做的那样。从文件系统搜索生成 RDF 允许您稍后使用不同的 SPARQL 查询来改进您的 Timeline。
find 命令的结果可以使用 Perl 和 Redland 快速转换为 RDF。Redland 库遵循 ./configure; make; make install; 三步过程。安装 Perl 绑定需要您配置绑定包,启用 Perl 包装器,如列表 17 所示。
列表 17. 安装 Redland Perl 绑定
tar xzvf redland-bindings-1.0.4.1.tar.gz cd redland-bindings-1.0.4.1 ./configure --with-perl cd ./perl make make install
列表 18 中显示的脚本将来自 find 调用的空分隔输出转换为 RDF 文件。每个文件的 inode 构成输出 RDF 中的主体。每个文件的元数据都与其 inode 主体关联。一些值得注意的事情:我创建了 basename 的缩短版本作为 Timeline 上的标签,并且 mtime 被转换为 RDF 中的字符串表示形式。目前,Timeline 不会为标签过长的时间事件标签显示任何标签。此外,描述将在每个事件的点击气泡中显示文件的内容。
列表 18. 用于将 find 结果转换为 RDF 的粘合代码
#!/usr/bin/perl use POSIX; use File::Basename; use RDF::Redland; $storage=new RDF::Redland::Storage( "hashes", "test", "new='yes',hash-type='memory'"); $model=new RDF::Redland::Model($storage, ""); $rdfns = "http://witme.sf.net/rdf/filesystem/"; $/="\0"; while( <> ) { $url=$_; # remove pesky null char at end-of-string chomp($url); ($dev, $ino, $mode, $nlink, $uid,$gid,$rdev, $size,$atime,$mtime,$ctime) = lstat($_); $model->add( new RDF::Redland::URI( "${rdfns}${ino}" ), new RDF::Redland::URI( "${rdfns}inode" ), new RDF::Redland::LiteralNode( "$ino" ) ); $model->add( new RDF::Redland::URI( "${rdfns}${ino}" ), new RDF::Redland::URI( "${rdfns}url" ), new RDF::Redland::LiteralNode( "$url" ) ); $model->add( new RDF::Redland::URI( "${rdfns}${ino}" ), new RDF::Redland::URI( "${rdfns}basename" ), new RDF::Redland::LiteralNode(basename("$url"))); $model->add( new RDF::Redland::URI( "${rdfns}${ino}" ), new RDF::Redland::URI( "${rdfns}title" ), new RDF::Redland::LiteralNode( substr basename("$url"), 0, 25 ) ); $model->add( new RDF::Redland::URI( "${rdfns}${ino}" ), new RDF::Redland::URI( "${rdfns}mtime" ), new RDF::Redland::LiteralNode( strftime( "%Y-%m-%d %H:%M:%S", localtime($mtime)) ) ); $model->add( new RDF::Redland::URINode( "${rdfns}${ino}" ), new RDF::Redland::URINode( "${rdfns}size" ), new RDF::Redland::LiteralNode( "$size" ) ); $model->add( new RDF::Redland::URI( "${rdfns}${ino}" ), new RDF::Redland::URI( "${rdfns}content" ), new RDF::Redland::LiteralNode( "$url<br>" ) ); $desc = "<a href=\"${url}\">$url</a><br></br>" . "<iframe src=\"${url}\" " . "width=\"95%\" height=\"75%\"></iframe>"; $model->add( new RDF::Redland::URI( "${rdfns}${ino}" ), new RDF::Redland::URI( "${rdfns}description" ), RDF::Redland::Node->new_xml_literal( $desc ) ); } $model->sync(); print $model->to_string() , "\n";
SPARQL 查询如列表 19 所示。sparql2timeline.xsl 可以从上述任何示例中重用。命令也非常相似,如列表 20 所示。evolution.html 可以复制到 filesystem.html 并修改为包含 filesystem.json,我们就有了新的 Timeline。
列表 19. 用于查询 RDF 存储以获取文件系统数据的 SPARQL
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX fs: <http://witme.sf.net/rdf/filesystem/> SELECT distinct ?uid ?title ?date ?description WHERE { ?x fs:inode ?uid . ?x fs:title ?title . ?x fs:mtime ?date . ?x fs:description ?description . } ORDER BY DESC(?date)
列表 20. 我本周的文件修改
$ find ~ -name ".*" -prune -o -name "*~" -prune \ -o -mtime -7 -print0 | \ ./find-to-rdf.pl >| filesystem.rdf $ java jena.sparql \ --data filesystem.rdf \ --query filesystem-to-timeline.rq \ --results xml >| filesystem.xml $ xsltproc sparql2timeline.xsl filesystem.xml \ | tr '\n' ' ' >| filesystem.json
当为新的数据源创建 Timeline 时,使用 RDF 和 SPARQL 可能是一个很大的优势。sparql2timeline.xsl 文件可以重用于将 SPARQL 查询结果转换为 JSON。需要的两个主要内容是将数据放入 RDF 和 SPARQL 查询本身。我在本文中仅涉及了 SPARQL 的一些可能性。使用 SPARQL,很容易确保结果中的值与正则表达式匹配或具有某些其他属性,例如在两个日期之间。结果可以使用 UNION 关键字来自多个数据源。例如,很容易将上述任何 SPARQL 查询组合成单个查询,以在单个 Timeline 上显示多种类型的时间事件。
本文资源: /article/9463。
Ben Martin 从事文件系统工作已超过十年。他目前正在澳大利亚伍伦贡大学攻读博士学位,将语义文件系统与形式概念分析相结合,以改善人机文件系统交互。