服务通过 Atom 服务文档告知我们哪些内容可用。每一个服务表示一个或多个工作空间,每个工作空间表示一个或多个集合(collection)。集合由一些资源个体组成。例如,可以在 http://local hosts:8080/roller/app 上检索 Blogapps 服务文档。(如清单 1 所示)。
清单 1. 服务文档
<?xml version="1.0" encoding="UTF-8"?>
<app:service xmlns:app="http://purl.org/atom/app#"
xmlns:atom="http://www.w3.org/2005/atom">
<app:workspace>
<atom:title>AdminBlog</atom:title>
<app:collection
href="http://localhost:8080/roller/app/adminblog/entries">
<atom:title>Weblog Entries</atom:title>
<app:categories app:fixed="yes"
app:scheme="http://localhost:8080/roller/adminblog/">
<atom:category atom:term="/General" atom:label="General" />
<atom:category atom:term="/Status" atom:label="Status" />
</app:categories>
<app:accept>entry</app:accept>
</app:collection>
<app:collection
href="http://localhost:8080/roller/app/adminblog/resources">
<atom:title>Media Files</atom:title>
<app:accept>image/*</app:accept>
</app:collection>
</app:workspace>
<app:workspace>
...
</app:workspace>
</app:service>
|
通过这个文档,我们可以创建一个包含侧栏的 servlet,侧栏中将显示出所有可用的服务和提要,连同到它们的 HTML 版本的链接。
第一步,创建基本的 servlet,包括侧栏的空间(如清单 2 所示)。
清单 2. 基本 servlet
package com.backstop.atom;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
public class SideBarServlet extends javax.servlet.http.HttpServlet
implements javax.servlet.Servlet {
String APPNS = "http://purl.org/atom/app#";
String AtomNS = "http://www.w3.org/2005/atom";
String AtomNS2 = "http://www.w3.org/2005/Atom";
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().print(
"<div style='width:25%; float: right;'>");
Document doc = URLContents.getContentsAsXMLDoc(
"http://localhost:8080/roller/app" );
Element root = (Element)doc.getDocumentElement();
NodeList workspaces = root.getElementsByTagNameNS(APPNS,
"workspace");
for (int i = 0; i < workspaces.getLength(); i++){
Element thisWorkspace = (Element)workspaces.item(i);
response.getWriter().print(
"<div style='border: 1px solid green; padding: 5px;'>");
String wsTitle =
thisWorkspace.getElementsByTagNameNS(AtomNS,
"title").item(0).getTextContent();
response.getWriter().print(
"<h3 class='wstitle'>"+wsTitle+"</h3>");
response.getWriter().print("</div>");
}
response.getWriter().print("</div>");
}
}
|
类包含了所有需要的导入语句和表示名称空间的变量。(Blogapps 有一个很小的 bug,即服务文档有一个稍微有误的名称空间;如果没有修正该 bug,则需要同时声明两个版本:http://www.w3.org/2005/atom 和 http://www.w3.org/2005/Atom)
下一步,添加实际的工作空间到侧栏。为此,遍历文档中的工作空间元素。所有这些文档都受到 Blogapps 服务器的密码保护,因此为了简单起见,我将元素的实际检索移动到了一个单独的工具类 URLContents 中。可以从本文提供的源代码中找到这个类。(如果您要自己实现这个检索,请确保将 DocumentBuilderFactory 设置为名称空间感知(namespace-aware))。
有了 XML 文档对象之后,遍历各个工作空间元素,并在页面上为每个元素都创建一个 div。对于每个元素,提取标题元素的文本并将其放入页面,如图 1 所示。
图 1. 工作空间
接下来看看如何添加集合。
在页面中添加集合的操作所涉及的过程大致相同。有了各个工作空间之后,就可以检索其中的各个集合了(如清单 3 所示)。
清单 3. 遍历集合
...
response.getWriter().print(
"<h3 class='wstitle'>"+wsTitle+"</h3>");
NodeList collections =
thisWorkspace.getElementsByTagNameNS(APPNS, "collection");
for (int j = 0; j < collections.getLength(); j++){
Element thisCollection = (Element)collections.item(j);
String colTitle =
thisCollection.getElementsByTagNameNS(AtomNS,
"title").item(0).getTextContent();
String feedURL = thisCollection.getAttribute("href");
response.getWriter().print(
"<h4 class='collection'>"+colTitle);
response.getWriter().print(" -- <a href='"+feedURL+
"'><img border='0' src='images/feed-icon.gif' /></a>");
response.getWriter().print("</h4>");
}
response.getWriter().print("</div>");
}
response.getWriter().print("</div>");
}
}
|
对于每一个集合,除了显示其标题外还有一些其他事情。每个集合还包含了一个 href 属性,用于表示该集合的 Atom 提要的位置。要利用这点,提取该信息并添加一个提要图标,并将其链接到提要的 URL。最后的结果类似于图 2。
图 2. 添加提要
我们还可以为每个集合中的内容添加一个类别提示(如清单 4 所示)。
清单 4. 添加类别
...
response.getWriter().print(" -- <a href='"+feedURL+
"'><img border='0' src='images/feed-icon.gif' /></a>");
response.getWriter().print("</h4>");
NodeList categories =
thisCollection.getElementsByTagNameNS(AtomNS,
"category");
if (categories.getLength() > 0){
response.getWriter().print(
"Categories in this collection: ");
}
for (int k = 0; k < categories.getLength(); k++){
Element thisCategory = (Element)categories.item(k);
String catName = thisCategory.getAttributeNS(AtomNS,
"label");
if (k > 0){
response.getWriter().print(", ");
}
response.getWriter().print(catName);
}
}
response.getWriter().print("</div>");
}
response.getWriter().print("</div>");
}
}
|
结果类似图 3 所示。
图 3. 添加类别
最后一步,加入该信息的 HTML 表示的链接。遗憾的是,该信息并没有实际存在于服务文档中。要检索它,我们还要看看提要本身(如清单 5 所示)。
清单 5. 检索提要信息
...
for (int j = 0; j < collections.getLength(); j++){
Element thisCollection = (Element)collections.item(j);
String colTitle =
thisCollection.getElementsByTagNameNS(AtomNS,
"title").item(0).getTextContent();
String feedURL = thisCollection.getAttribute("href");
String webURL = getWebURL(feedURL);
response.getWriter().print(
"<h4 class='collection'><a href='"+webURL+"'>"+>
colTitle+"</a>");
...
}
response.getWriter().print("</div>");
}
response.getWriter().print("</div>");
}
private String getWebURL(String feedURL){
String webURL = "";
Document doc = URLContents.getContentsAsXMLDoc(feedURL);
Element root = (Element)doc.getDocumentElement();
NodeList links = root.getElementsByTagNameNS(AtomNS2, "link");
for (int i = 0; i < links.getLength(); i++){
Element thisLink = (Element)links.item(i);
if (thisLink.getAttribute("rel").equals("alternate") &&
thisLink.getParentNode().equals(root)){
webURL = thisLink.getAttribute("href");
}
}
return webURL;
}
}
|
在本例中,我们通过服务文档检索提要 URL,然后检索实际文档,其中包含一个链接元素,比如 <link rel="alternate" href="http://localhost:8080/roller/adminBlog" /> 表示提要所表示数据的 HTML 版本。然后便可以将该信息加入到侧栏中。最后的结束类似于图 4。
图 4. 添加类别
服务文档并不仅仅用于自省;经过精心规划,我们可以使用服务文档提供实际的内容和到内容的链接。
| 描述 | 名字 | 大小 | 下载方法 |
|---|---|---|---|
| Atom 侧栏示例 | x-atomsidebar-source.zip | 3KB | HTTP |
学习
- 您可以参阅本文在 developerWorks 全球网站上的 英文原文。
-
Atom 1.0 Syndication Format 概述(James Snell,developerWorks,2005 年 8 月):看看该流行的 Web 内容联合格式是如何构成的。
-
“认识 Atom 发布协议”系列(James Snell,developerWorks,2007 年 1 月):在该系列的三篇文章中获取有关 Atom API 的知识:
- 认识 Atom 发布协议,第 1 部分: 使用 Atom 发布协议创建和编辑 Web 资源:探究协议的高级概述及其基本操作和功能。
- 认识 Atom 发布协议,第 2 部分: 应用 Atom 发布协议: 学习使用 APP 与大量现实世界中部署好的应用程序进行交互。
- 认识 Atom 发布协议,第 3 部分: Apache Abdera 项目简介:开始使用新兴的开放源码项目(称作 Abdera,目前正处于 Apache Software Foundation 的筹划之中)实现支持 Atom 的应用程序。
-
RSS and Atom in Action(Dave Johnson,Manning Publications,2006 年 7 月):如果您更想了解物理实现方面的内容,可以阅读本书。该书介绍了新闻提要格式和协议发布的 blog 技术以及如何将这些技术结合起来(本书附有 blog 应用程序)。
-
Atom 1.0 规范:通过阅读了解这个基于 XML 的 Web 内容和元数据联合格式。
-
Atom 1.0 兼容软件:访问 Atom Working Group 的 Wiki,获取已知 Atom 1.0 提要用户的列表。
-
Thinking XML: 使用 Atom 格式连锁新闻及其他内容(Uche Ogbuji,developerWorks,2004 年 5 月):通过阅读了解更多有关这个基于 XML 的标准、格式和 API 的知识,以便对 Web 元数据进行互换和交叉引用。
-
developerWorks 中国网站 XML 专区:其中包括大量 XML 资料。
-
IBM XML 认证:看看如何才能成为一名 IBM 认证的 XML 及相关技术的开发人员。
-
XML 技术文档库:developerWorks XML 专区提供了大量技术文章、提示、教程、标准以及 IBM 红皮书。
-
developerWorks 技术活动和网络广播:随时关注技术的最新进展。
-
技术书店:浏览有关本文所述主题及其他技术主题的书籍。
获得产品和技术
-
Blogapps 服务器:下载这个服务器,其中包含了各种有用的 RSS 和 Atom 工具及例子。
-
IBM 试用版软件:使用可从 developerWork 直接下载的试用软件构建您的下一个开发项目。
讨论
- 参与论坛讨论。
-
XML 专区讨论论坛:参与任何以 XML 为中心的论坛。
-
developerWorks blogs:查阅这些 blog 并加入 developerWorks 社区。