内容


使用 Java 技术将 Atom 转换为 RDF

轻松实现从聚合转换到语义

Comments

RDF 包含由 W3C 制定的各种规范。它本质上是一个元数据建模框架,该框架利用 Web 上分布的软件可读信息,具体方法是通过使用一些称为三元组 的 “主语-谓语-宾语”表达式识别这些信息。

例如下面这个英文表达式:“Perry the Platypus's arch-enemy is Dr. Doofenschmirtz.”。 在这个例子中,主语是 Perry the Platypus,谓语是 archenemy,宾语是 Dr. Doofenschmirtz。在 RDF 中,这个三元组将根据一种特殊格式编码,这种格式用于识别卡通人物和他们的主要敌人。

RDF 代表 “明天”,因为它是 Semantic Web(语义 Web)运动的一部分。实际上,它是该运动的重要组成部分。

Semantic Web 运动代表下一代万维网,其中的信息将通过语义识别。其理念是基于一种预定义格式显示数据,这些数据可以被软件和人类明确识别。想想看,这种预定义格式将使用 RDF 完成。(对 RDF 的详细分析超出了本文的范围,请参阅 参考资料 提供的链接了解更多信息)。

Atom:欢迎回到昨天

这部分的标题似乎对 Atom 不屑一顾,但事实上并非如此。相反,它意味着一种新出现的技术(RDF)和一种已经存在一段时间的技术(Atom)的对比。

Atom 是一系列基于 Web 的文档的聚合格式,它从 RSS 的固有限制开发而来。这种聚合格式通过 XML 语言表达,所以 Atom 文档即 XML 文档。

通常,Atom 文档通过一种称为提要阅读器(feed reader)的软件阅读,这种软件使用户能够查看来自一个特定站点的一些相关文档的摘要。用户可以决定要阅读哪些文件,然后只需单击相应的链接。这种 Atom 聚合格式还允许网络管理员显示站点上的提要。

但是,Atom 没有像新出现的 Semantic Web 活动那样定义便于理解的语义。为此,需要使用 RDF。

两个世界的精华

这样,问题来了:“有没有一种 RDF 规范能够利用聚合?能不能既享受语义的好处,同时又保留高曝光度的优势?”

答案是肯定的。

请走进 “另一个” RSS。这个 RSS 不是您所想到的那个 RSS,它表示 RDF Site Summary(RDF 站点摘要),以语义方式定义一种聚合格式。它允许网络管理员以 RDF 格式发布他们的文档,以便这些文档中包含的信息能够被 Semantic Web 所理解。

以 RDF 格式提供 feed 的好处在于:支持 Semantic Web 行为的资源将在其搜索结果中阅读、缓存和包含来自那些源的内容。随着 Semantic Web 不断涌现,那些采用 RDF Site Syndication(RDF 站点聚合)技术的网络管理员将发现自己置身于最新的、最先进的技术的最前沿。他们将拥有更高的曝光度,那意味着更多流量。更多流量意味着他们的广告商将给用户留下更深的印象。更深的印象意味着他们可以赚到更多钱。这肯定是一种值得投资的开发工作。

将 Atom 转换为 RDF

既然这种格式转换能够带来良好的经济效益,那么就让我们着手进行这项工作吧。本文将介绍如何使用 Java 编程语言将 Atom 文档转换为 RDF 文档。

幸运的是,Atom 和 RDF 文档都是 XML 文档,这意味着用于读取一种文档的工具将能够用于读取另一种文档。

Java 编程语言

您将使用 1.6 版 Java 编程语言编写转换代码。之所以选择这种语言,是因为它著名的 “一次编写到处运行” 的功能。您可以在拥有兼容 1.6 版 Java 软件开发工具箱(JDK)的任意平台上编译和运行本文提供的代码。

解析和创建 XML 文档的 API 是 Streaming API for XML (StAX),这是一个出色的界面,胜过了传统的 DOM 和 Simple API for XML (SAX) 解析方案。使用 StAX 时,XML 文档的解析是基于光标的,应用程序在运行过程中只使用 XML 中需要的内容。StAX 还允许开发人员创建 XML 文档。

元数据

元数据本质上是关于数据的数据,它在 Semantic Web 中的作用非常关键。它提供前面提到的三元组的识别和解释方法。

如前所述,您将对终端产品使用 RDF Site Syndication 规范。对于实现格式转换这个目的,这种规范简直堪称完美,因为它是一种遵守 Semantic Web 的聚合格式。

必须再次提起注意的是,RDF Site Syndication 格式是一种独立的规范,但它缺乏某些定义,比如日期。为了弥补这个缺陷,通常使用另一种 RDF 兼容规范,这种规范称为 Dublin Core Metadata Initiative (DCMI)。DCMI 是与 RDF 联用的最流行的 XML 语言之一。

编写代码

基本的思路是:先读取一个现有的 Atom 提要,然后将这个提要转换为 RDF。在这种情况下,需要将 Atom 格式的 Twitter public timeline 转换为 RDF Site Syndication 格式。为此,应使用标准 JavaBeans™ 来存储从 Atom 提要中读取的信息。您也许知道,JavaBeans 是包含一系列私有属性以及公共访问器和转变器的 Java 类。您可以使用这些类的内容来创建 RDF 文档。

一个 RDF Site Syndication 文档中包含两个重要的 “节”。一个是 <channel> 节,另一个是 <item> 节,后者可能会多次出现。<channel> 节描述整个提要,每个 <item> 节描述这个提要中的一个文档。清单 1 显示了一个 RDF Site Syndication 文档示例。

清单 1. RDF 文档示例(节选)
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
	xmlns="http://purl.org/rss/1.0/" 
	xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel rdf:about="http://www.twitter.com">
         <title>Twitter public timeline</title>
         <description>Twitter updates from everyone!</description>
         <link>http://twitter.com/public_timeline</link>
         <dc:date>2009-04-05T13:11:01+00:00</dc:date>
         <items>
              <rdf:Seq>
                   <rdf:li>http://twitter.com/TJalexander/statuses/1456808203</rdf:li>
                   <rdf:li>http://twitter.com/xElsiex/statuses/1456808201</rdf:li>
                   <rdf:li>http://twitter.com/mmama1215/statuses/1456808197</rdf:li>
                   <rdf:li>http://twitter.com/kennethmaxey/statuses/1456808196</rdf:li>
                   <rdf:li>http://twitter.com/katiestars/statuses/1456808195</rdf:li>
                   <rdf:li>http://twitter.com/Zweeal/statuses/1456808194</rdf:li>
                   <rdf:li>http://twitter.com/lilvicofficial/statuses/1456808193</rdf:li>
                   <rdf:li>http://twitter.com/PrettyNitti/statuses/1456808192</rdf:li>
                   <rdf:li>http://twitter.com/mrrobbo/statuses/1456808190</rdf:li>
                   <rdf:li>http://twitter.com/smd75jr/statuses/1456808189</rdf:li>
                   <rdf:li>http://twitter.com/BirdDiva/statuses/1456808188</rdf:li>
                   <rdf:li>http://twitter.com/nouwen/statuses/1456808185</rdf:li>
                   <rdf:li>http://twitter.com/gustavopereira/statuses/1456808184</rdf:li>
                   <rdf:li>http://twitter.com/sky_7/statuses/1456808183</rdf:li>
                   <rdf:li>http://twitter.com/fauzty/statuses/1456808182</rdf:li>
                   <rdf:li>http://twitter.com/Cheriefaery/statuses/1456808181</rdf:li>
                   <rdf:li>http://twitter.com/CarolineAttia/statuses/1456808180</rdf:li>
                   <rdf:li>http://twitter.com/ukyo_rst/statuses/1456808179</rdf:li>
                   <rdf:li>http://twitter.com/Len0r/statuses/1456808177</rdf:li>
                   <rdf:li>http://twitter.com/jhill444faceboo/statuses/1456808175</rdf:li>
              </rdf:Seq>
         </items>
    </channel>    
    <item rdf:about="http://twitter.com/TJalexander/statuses/1456808203">
         <dc:format>text/html</dc:format>
         <dc:date>2009-04-05T13:11:01+00:00</dc:date>
         <dc:source>http://www.twitter.com</dc:source>
         <dc:creator>t.j. alexander</dc:creator>
         <dc:date>2009-04-05T13:11:01+00:00</dc:date>
         <title>TJalexander: Photo: somethingtobelievein: i don</title>
         <link>http://twitter.com/TJalexander/statuses/1456808203</link>
         <description>TJalexander: Photo: somethingtobelievein: i don</description>
    </item>
    <item rdf:about="http://twitter.com/xElsiex/statuses/1456808201">
         <dc:format>text/html</dc:format>
         <dc:date>2009-04-05T13:11:01+00:00</dc:date>
         <dc:source>http://www.twitter.com</dc:source>
         <dc:creator>Elsie Constantinides</dc:creator>
         <dc:date>2009-04-05T13:11:01+00:00</dc:date>
         <title>xElsiex: my hairs gone all fluffy like :O !! nooooooooooooo !!!</title>
         <link>http://twitter.com/xElsiex/statuses/1456808201</link>
         <description>xElsiex: my hairs gone all</description>
    </item>
...

注意,清单 1 中的文档看起来与原来的 Really Simple Syndication 格式惊人地相似。这不是一个巧合,因为 RDF Site Syndication 规范背后的理念是创建一种与 RDF 兼容的聚合格式。

大多数元素是可以顾名思义的。RDF Site Syndication 和 Really Simple Syndication 之间的一个主要区别是 <items> 元素,它是 <channel> 元素的一个子元素。这个元素提供 RDF 文件中包含的所有文档链接的列表。该元素可以视为一个摘要的摘要。

考虑到上述因素,似乎应该创建两个 JavaBeans:一个主要 “节” 和一个 JavaBeans。清单 2 显示了 Channel 类。

清单 2. Channel 类
public class Channel {

	private String about;
	private String title;
	private String description;
	private String link;
	private String date;
	private List<String> items = new ArrayList<String>();
	
	
	
	public String getAbout() {
		return about;
	}
	public void setAbout(String about) {
		this.about = about;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public String getLink() {
		return link;
	}
	public void setLink(String link) {
		this.link = link;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	public List<String> getItems() {
		return items;
	}
	public void setItems(List<String> items) {
		this.items = items;
	}
}

如上所示,Channel 类无非是一个直观的 JavaBean,它描述包含在 <channel> 节中的信息。该类中的每一个属性和 <channel> 的每一个子元素之间都有一种直接联系。甚至有一个针对这些链接的 String 对象清单(List),这些链接是 <items> 元素的子元素。

清单 3 是另一个简单的 JavaBeans 类,这个类代表提要中的一个文档。

清单 3. Item 类
public class Item {
	
	private String format;
	private String date;
	private String link;
	private String creator;
	private String title;
	private String description;
	private String source;
	
	
	public String getSource() {
		return source;
	}
	public void setSource(String source) {
		this.source = source;
	}
	public String getFormat() {
		return format;
	}
	public void setFormat(String format) {
		this.format = format;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	public String getLink() {
		return link;
	}
	public void setLink(String link) {
		this.link = link;
	}
	public String getCreator() {
		return creator;
	}
	public void setCreator(String creator) {
		this.creator = creator;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}	
}

如上所示,这个类包含一个项目的相关信息:titlecreator(或 author)、description(摘要)和链接。

进一步深入代码之前,首先需要检查一个 Atom 示例文档。请看 清单 4

清单 4. 一个 Atom 示例文档(Twitter public timeline)
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Twitter public timeline</title>
  <id>tag:twitter.com,2007:Status</id>
  <link type="text/html" rel="alternate" href="http://twitter.com/public_timeline"/>
  <updated>2009-04-06T12:20:02+00:00</updated>
  <subtitle>Twitter updates from everyone!</subtitle>
    <entry>
      <title>UMaineExtension: Backyard Poultry course</title>
      <content type="html">UMaineExtension: Backyard Poultry course</content>
      <id>tag:twitter.com,2007:http://twitter.com/UMaineExtension/statuses/1462447470</id>
      <published>2009-04-06T12:20:00+00:00</published>
      <updated>2009-04-06T12:20:00+00:00</updated>
      <link type="text/html" rel="alternate" href="http://twitter.com//1462447470"/>
      <link type="image/jpeg" rel="image" href="http://UM-crest_normal.jpg"/>
      <author>
        <name>UMaine Extension</name>
        <uri>http://www.extension.umaine.edu</uri>
      </author>
    </entry>
    <entry>
      <title>tmj_mem_adv: Ecommerce Marketing Manager http://tinyurl.com/cthahs</title>
      <content type="html">tmj_mem_adv: Ecommerce Marketing Manager</content>
      <id>tag:twitter.com,2007:http://twitter.com/1462447468</id>
      <published>2009-04-06T12:19:59+00:00</published>
      <updated>2009-04-06T12:19:59+00:00</updated>
      <link type="text/html" rel="alternate" 
          href="http://twitter.com/statuses/1462447468"/>
      <link type="image/png" rel="image" href="http://83603474/twitter_normal.png"/>
      <author>
        <name>TMJ-MEM Advert Jobs</name>
        <uri>http://www.tweetmyjobs.com</uri>
      </author>
    </entry>  
...

注意,<title> 元素是 <feed> 的直接子元素。而另一个元素是 <entry> 的直接子元素。今后您需要在代码中处理这个问题。

现在模型已经完成,是时候进行实际编码,以解析 Atom 提要并创建 RDF 文件了。AtomToRdf 类用于完成这个任务。清单 5 显示了这个类本质。

清单 5. AtomToRdf 的本质
public class AtomToRdf {
	
	. . .
	private Channel channel = new Channel();
	private List<Item> itemList = new ArrayList<Item>();

	public static void main(String[] args) {
		AtomToRdf atomToRdf = new AtomToRdf();
		atomToRdf.go();
	}
	
	private void go() {
		parseAtom();
		createRdf();
	}
	. . .
}

如果一切都这样简单就好了!实际情况是 main() 方法只是在一个实例化的 AtomToRdf 类上执行了一个私有方法 go()。这是一种跳出静态上下文的方法。go() 方法反过来执行两个相当顾名思义的方法:parseAtom()createRdf()。第一个方法是阅读器,第二个方法是写入器。

为确保从 Atom 提要中读取的信息能够用于 AtomToRdf 对象中的所有方法,必须声明两个局部可用的对象变量,如 清单 5 所示。一个是 Channel 类的一个实例(称为 channel)。另一个是包含一个或多个 Item 对象的 List 对象(称为 itemList)。

清单 6 显示了 parseAtom() 方法的开始部分。该方法使用 StAX 来解析 Atom 提要。这段代码首先实例化一个新的 XMLInputFactory 对象,然后打开一个包含 Atom 格式的 Twitter public timeline 的 InputStream 对象。这个 StAX InputFactoryInputStream 创建一个 XMLEventReader 对象。在 “拖动—解析” Atom 提要的过程中,StAX 用这个对象来识别 事件。事件的一些例子比如文档启动、元素启动和元素结束。

清单 6. 开始解析 Atom
	private void parseAtom() {
        try {
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            InputStream in = new URL("http://twitter.com/statuses/public_timeline.atom")
			.openStream();
            
            XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
            
            boolean inEntry = false;
            Item currentItem = null;
            
            while (eventReader.hasNext()) {   
...

要处理这两个 <title> 元素,这个 isEntry Boolean 用于区分它们。如果 Boolean 为 True,解析器检查 <title> 元素,该元素是 <entry> 的一个子元素。

变量 currentItem 用于存储输出文件中的每个 <item> 节中将包含的信息。每次解析器遇到输入文件中的另一个 <entry> 元素时,一个新的 currentItem 对象将被实例化。每次解析器遇到 <entry> 元素的结尾时,现有的 currentItem 对象添加到 Item 对象列表(itemList)。

最后,清单 6 开始解析器循环。本质上,那条 while 语句的意思是 “只要解析器遇到 任何事件,它将重复执行大括号({})里面的代码。”

急需解决的问题是:将遇到哪种事件?如何处理这些事件?请看 清单 7

清单 7. 解析 Title 元素
if (event.isStartElement()) {
   StartElement startElement = event.asStartElement();
        	   
   if (event.asStartElement().getName().getLocalPart().equals("title")) {
     	   event = eventReader.nextEvent();
     	   String title = event.asCharacters().getData();
                       
     	   if (!inEntry) {
     		   channel.setTitle(title);
     	   } else {
     		   currentItem.setTitle(title);
     	   }
             	                          
         continue;
    } 
...

当这段代码遇到一个事件时,它首先检查这个事件是不是一个新元素的开端。如果是,则一个 StartElement 对象被实例化。然后检查这个元素的名字。如果这个元素的名字是 title,这段代码将把该元素的实际内容放到字符串变量 title 中。

还记得 isEntry 变量吗?这个变量将在这里使用,因为 — 您可能还记得 — 命名为 title 的元素出现在 Atom 提要的两个位置。如果 isEntry 设置为 True,代码知道检查一个文档的标题,而不是整个提要的标题。对于前一种情况,将设置 currentItem 对象的 title 属性;对于后一种情况,将设置 channel 对象的 title 属性。

最后,continue 语句是一条标准的 Java 语句,它的意思是 “只要到此就继续循环”。换句话说,当代码处理完这个事件后,将开始寻找更多事件。

如果您查看整个代码,您将发现有许多代码块与 清单 7 中的代码类似。区别在于每个代码块检查 Atom 提要中的一个不同元素,然后在正确的对象上设置适当的实例变量。

循环结束时,代码将拥有一个完全填充的 Channel 对象和一个完全填充的 Item 对象列表。这些对象将被读取,其中的信息将用于创建 RDF 文件。

在检查代码以创建 RDF 文档之前,首先必须理解已在 AtomToRdf 中定义的一些常量(见 清单 8)。

清单 8. 在 AtomToRdf 中定义的常量
private static final String DUBLIN_CORE_PREFIX	= "dc";
private static final String DUBLIN_CORE_URI	= "http://purl.org/dc/elements/1.1/";
private static final String RDF_PREFIX		= "rdf";
private static final String RDF_URI	= "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
private static final String RSS_URI			= "http://purl.org/rss/1.0/";

为何需要这些常量呢?让我们回头看看 清单 1 中的 RDF 示例文档。您将看到 RDF 输出需要名称空间,在很多情况下,这些名称空间是重复的。这些常量能够使您更轻松地引用那些名称空间和它们对应的 URI。清单 9 中的代码开始输出。

清单 9. 开始输出
   private void createRdf() {
   	try {
  		
		XMLOutputFactory xmlof = XMLOutputFactory.newInstance();       
    		XMLStreamWriter xmlw = xmlof.createXMLStreamWriter
			(new FileOutputStream ("c:/twitter.rdf"));    
    		xmlw.writeStartElement(RDF_PREFIX, "RDF", RDF_URI);     
    		xmlw.writeNamespace(RDF_PREFIX, RDF_URI); 
    		xmlw.writeNamespace("",RSS_URI);
    		xmlw.writeNamespace(DUBLIN_CORE_PREFIX, DUBLIN_CORE_URI);
    		xmlw.writeCharacters("\n");    
    		xmlw.writeCharacters("    "); 
    		
    		writeChannel(xmlw);
    		writeItems(xmlw);
    		    		   
    		xmlw.writeCharacters("\n");    
    		xmlw.writeEndElement();    
    		xmlw.writeEndDocument();    
    		xmlw.close();
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    }

再次使用了 StAX API。区别在于这一次它用于生成输出而不是读取输入。这段代码首先实例化一个新的 XMLOutputFactory 对象,然后从一个 FileOutputStream 对象创建一个 XMLStreamWriter,该对象指向 c:/twitter.rdf(输出文件的名称和位置)。您可能需要根据自己的环境更改文件位置。

这段代码开始写出这些元素。它首先从根元素开始,并对根元素使用前缀 rdf 和它对应的 URI。下面三行定义与根元素关联的各种名称空间和相应的前缀。注意,RSS_URI 常量代表默认前缀,因此一个空字符串用作前缀。

接下来两行的目的是格式化,使输出更适合人类阅读。您将在整个输出代码中看到大量这种情况。

下面两行调用单独的方法,它们用作输出例程的 “重要部分”。第一种方法写出 <channel> 节,第二种方法写出每个 <item> 节。

下面几行关闭根元素和文档本身。最后,XMLStreamWriter 对象关闭。

您可能注意到 清单 10 中的一种模式。首先,创建一个带有恰当 about 属性的父元素(通常命名为 channel)。注意,about 属性需要 rdf 名称空间。about 属性的值只是一个 URL,它指向 RDF Site Syndication 中包含的信息。为此,我使用了 Twitter 的 URL。

清单 10. writeChannel() 方法
    private void writeChannel(XMLStreamWriter xmlw) throws Exception {
		xmlw.writeStartElement("channel");
		xmlw.writeAttribute(RDF_PREFIX, RDF_URI, "about", 
			"http://www.twitter.com");
		xmlw.writeCharacters("\n");    
		xmlw.writeCharacters("         ");  
		xmlw.writeStartElement("title");
		xmlw.writeCharacters(channel.getTitle());
		xmlw.writeEndElement();
		xmlw.writeCharacters("\n");    
		xmlw.writeCharacters("         "); 
		xmlw.writeStartElement("description");
		xmlw.writeCharacters(channel.getDescription());
		xmlw.writeEndElement();
		xmlw.writeCharacters("\n");    
		xmlw.writeCharacters("         "); 
...

这是您第二次在输出中看到 about 属性。了解它为什么在那里很重要,其原因是 about 属性定义 “主语-谓语-宾语” 三元组中的主语。在这个例子中主语是一个 URL(这种情况很普遍)。每个子元素(比如 <title>)代表一个谓语。每个元素的内容是宾语。

在两个格式化行之后,创建 <title> 元素并使用从 Atom 提要收集的标题填充,然后创建 <description> 元素等。

即使 清单 10 中只提供了两个元素,您可能还是注意到了一种模式出现。首先创建一个元素,然后使用来自 Channel 对象的内容填充这个元素,然后元素结束。这个过程将对包含在 Channel 对象中的所有数据重复。

为了使事情更直观,Channel 对象中的属性名称与 <channel> 节中的元素名称相同,这使在代码和输出之间进行正确映射更加容易。

清单 11 中,writeItems() 方法有一些不同,因为它不是写一个节,而是很多节。它对 Atom 提要中的每个 <entry> 元素写一个节。指向该方法开始处的 for 循环确保这一点得以实现。

清单 11. writeItems() 方法
    private void writeItems(XMLStreamWriter xmlw) throws Exception {
    	xmlw.writeCharacters("\n"); 
    	xmlw.writeCharacters("    ");
    	
	for (Item item : itemList) {
		xmlw.writeStartElement("item");
		xmlw.writeAttribute(RDF_PREFIX, RDF_URI, 
			"about", item.getLink());
		xmlw.writeCharacters("\n");    
		xmlw.writeCharacters("         "); 
   		
		xmlw.writeStartElement(DUBLIN_CORE_PREFIX,"format",
			DUBLIN_CORE_URI);
		xmlw.writeCharacters(item.getFormat());  
		xmlw.writeEndElement();
		xmlw.writeCharacters("\n");    
		xmlw.writeCharacters("         ");
...

对于 itemList 中的每个 Item 对象,将创建一个新的 <item> 元素。同样,一个特定于名称空间的 about 属性指向该文档的链接。在这个例子中,这个链接指向 Twitter 上的一个特定用户的一篇文章。

经过一些格式化之后,创建了一个称为 format 的子元素。这个 format 元素描述文档中的输出格式。在这里,这个元素是 text/html 格式。注意,这里使用了 Dublin Core 元数据而不是 RDF Site Syndication 标准或 RDF 标准指定的元数据。那是因为这两种标准都不支持定义文档格式。

在以上代码块中,出现了一种模式。对于 Item 类中的每个属性,一个新元素被创建并关联到一个与该属性名对应的元素。

总之,这就是那段代码,现在让我们来看看它实际上是否像所说的那样有效。

测试代码

将包含本文的这个压缩文件 — AtomToRdf.zip — 解压到您选择的一个测试目录。您将看到已经大致介绍过的三个文件:Item.java、Channel.java 和 AtomToRdf.java。

使用您最钟爱的集成开发环境(IDE)或进入一个命令提示,然后使用与 1.6 版兼容的 Java 编译器编译那些类。然后不带命令行参数执行 AtomToRdf.class

如果您没有更改提供的代码的内容,您的 C 盘根目录下将创建一个文件:twitter.rdf。该文件的格式将与 清单 1 中的格式相同。

如何知道这是不是一个有效的 RDF 文件呢?只需用一个验证器检验一下。幸运的是,W3C 上的一些好伙伴为您创建了一个校验器,它位于:http://www.w3.org/RDF/Validator。访问这个 URL,然后将 twitter.rdf 的内容粘贴到文本区域。单击 Parse RDF。您将看到一个窗口,窗口顶部显示 “Your RDF document validated successfully.”。恭喜您,您成功了!

结束语

随着 Semantic Web 成为技术革命的前沿技术,站点发布与 Semantic Web 标准兼容的文档变得很重要。RDF 就是这些标准之一。

使用 RDF Site Syndication,网络管理员能够生成与 Atom 提要类似的、兼容 RDF 的文档。这将提供聚合和语义双重好处。

使用 Java 编程语言和 StAX API,可以轻松解析一个 Atom 提要并将其转换为一个 RDF 文档,然后可以用这个 RDF 文档来提供特定于语义的提要。


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML
ArticleID=417935
ArticleTitle=使用 Java 技术将 Atom 转换为 RDF
publish-date=08032009