Informa不仅提供了对不同版本的RSS Feed source的读入和解析,同样也提供了将channel object导出为不同协议版本的XML文件的功能。这个功能是通过exporters包下的各个导出类来完成的。目前仅支持对RSS协议的导出,不支持Atom协议、OPML协议的导出。
所有的导出类都实现了ChannelExporterIF接口
/** *//**
* A channel exporter is used to write channel objects in an
* implementation dependent way to an implicit destination.</p>
*
* @author Niko Schmuck (niko@nava.de)
*/
public interface ChannelExporterIF {
/** *//**
* Writes the given channel to an implicit implementation dependent
* destination.
*
* @param channel - The channel to be exported/written;
* an object implementing ChannelIF.
* @throws IOException - Thrown if writing the channel fails.
*/
void write(ChannelIF channel) throws IOException;
}
★RSS_0_91_Exporter
在RSS_0_91_Exporter中提供了几种构造方法
public RSS_0_91_Exporter(String filename) throws IOException {
this(new File(filename), "utf-8");
}
public RSS_0_91_Exporter(File file) throws IOException {
this(file, "utf-8");
}
public RSS_0_91_Exporter(File file, String encoding) throws IOException {
this.writer = new OutputStreamWriter(new FileOutputStream(file),
encoding);
this.encoding = encoding;
}
public RSS_0_91_Exporter(Writer writer, String encoding) {
this.writer = writer;
this.encoding = encoding;
}
真正的生成XML文件的过程其实很简单,就是按照RSS 0.9.1规范的格式将channel object的属性映射到XML文件的element去。
// create items for channel
Collection<ItemIF> items = channel.getItems();
Iterator<ItemIF> it = items.iterator();
while (it.hasNext()) {
ItemIF item = (ItemIF) it.next();
Element itemElem = new Element("item");
itemElem.addContent(new Element("title").
setText(item.getTitle()));
if (item.getLink() != null) {
itemElem.addContent(new Element("link").
setText(item.getLink().toString()));
}
if (item.getDescription() != null) {
itemElem.addContent(new Element("description").
setText(item.getDescription()));
}
if (item.getDate() != null) {
itemElem.addContent(new Element("pubDate").
setText(ParserUtils.formatDate(item.getDate())));
}
channelElem.addContent(itemElem);
}
这是write(Channel)方法的其中一个片段,是用于导出channel中的item节点的。
★RSS_2_0_Exporter
和RSS 0.9.1的导出类似,2.0版本的导出同样需要实现ChannelExporterIF接口,同样提供了和上面一样参数类型的构造方法。不同的是在2.0的版本,由于新增了几个定义,所以增加了对应的构建方法。例如下面的getCategoryElements方法
// ------------------------------------------------------------
// Build a hierarchical category String from CategoryIF
// ------------------------------------------------------------
private Element getCategoryElements(Element elem, CategoryIF category,
StringBuffer catString) {
StringBuffer l_catString;
if (catString == null || catString.length() < 1)
l_catString = new StringBuffer(category.getTitle());
else
l_catString = catString.append("/").append(category.getTitle());
Collection<CategoryIF> categories = category.getChildren();
if (categories.size() == 0) {
elem.addContent(new Element("category").setText(l_catString
.toString()));
} else {
Iterator<CategoryIF> catIt = categories.iterator();
while (catIt.hasNext()) {
CategoryIF childCat = (CategoryIF) catIt.next();
elem = getCategoryElements(elem, childCat, l_catString);
}
}
return elem;
}
这个方法采用递归的方式,获取一个channel所属于的category,因为在Category对象中,关系是以级联的方式存在的,要把这种对象的级联关系展开为平行的字符串,只能通过递归的方式访问到最底层的category对象,得到其title后,再用分隔符"/"拼接后返回给上一层。
在2.0的write方法中,新增了对Namespace的支持
Namespace dcNs = Namespace.getNamespace("dc", NS_DC);
Namespace syNs = Namespace.getNamespace("sy", NS_SY);
Namespace adminNs = Namespace.getNamespace("admin", NS_ADMIN);
其余的生成过程和0.9.1的基本相同,除了在category方面
if (channel.getCategories() != null) {
Collection<CategoryIF> categories = channel.getCategories();
Iterator<CategoryIF> catIt = categories.iterator();
while (catIt.hasNext()) {
CategoryIF cat = (CategoryIF) catIt.next();
channelElem = getCategoryElements(channelElem, cat, null);
}
}
★RSS_1_0_Exporter
RSS_1_0_Exporter导出和0.9.1和2.0协议的过程有些不同,区别在于item方面和部分属性,这里重点介绍一下item方面的导出过程
// ===========================================
Element itemsElem = new Element("items", defNs);
Element seqElem = new Element("Seq", rdfNs);
Collection<ItemIF> items = channel.getItems();
Iterator<ItemIF> it = items.iterator();
while (it.hasNext()) {
ItemIF item = (ItemIF) it.next();
Element itemElem = new Element("li", rdfNs);
if (item.getLink() != null) {
itemElem.setAttribute("resource", item.getLink().toString());
}
seqElem.addContent(itemElem);
}
itemsElem.addContent(seqElem);
channelElem.addContent(itemsElem);
rootElem.addContent(channelElem);
// item-by-item en detail
items = channel.getItems();
it = items.iterator();
while (it.hasNext()) {
ItemIF item = (ItemIF) it.next();
Element itemElem = new Element("item", defNs);
if (item.getLink() != null) {
itemElem.setAttribute("about",
item.getLink().toString(), rdfNs);
}
itemElem.addContent(new Element("title", defNs).
setText(item.getTitle()));
if (item.getLink() != null) {
itemElem.addContent(new Element("link", defNs).
setText(item.getLink().toString()));
}
if (item.getDescription() != null) {
itemElem.addContent(new Element("description", dcNs).
setText(item.getDescription()));
}
if (item.getDate() != null) {
itemElem.addContent(new Element("date", dcNs).
setText(ParserUtils.formatDate(item.getDate())));
}
rootElem.addContent(itemElem);
}
和0.9.1和2.0协议不同,1.0的RSS对于item的描述有2次,第一次是summary,第二次是detail。
<items>
<rdf:Seq>
<rdf:li resource="http://xml.com/pub/2000/08/09/xslt/xslt.html" />
<rdf:li resource="http://xml.com/pub/2000/08/09/rdfdb/index.html" />
</rdf:Seq>
</items>
<item rdf:about="http://xml.com/pub/2000/08/09/xslt/xslt.html">
<title>Processing Inclusions with XSLT</title>
<link>http://xml.com/pub/2000/08/09/xslt/xslt.html</link>
<description>
Processing document inclusions with general XML tools can be
problematic. This article proposes a way of preserving inclusion
information through SAX-based processing.
</description>
</item>
<item rdf:about="http://xml.com/pub/2000/08/09/rdfdb/index.html">
<title>Putting RDF to Work</title>
<link>http://xml.com/pub/2000/08/09/rdfdb/index.html</link>
<description>
Tool and API support for the Resource Description Framework
is slowly coming of age. Edd Dumbill takes a look at RDFDB,
one of the most exciting new RDF toolkits.
</description>
</item>
可以看到上面的<items>是大概地告知了RSS阅读器这个channel下面有多少个item,顺序如何。下面每一个<item>则是对上面提到的item的详细描述。根据规范,<item>节点的rdf:about属性值必须和rdf:li的resource属性值一样。
上面的代码就是先找出item的列表,构建<items>节点及其子节点<rdf:seq>,后面是构建<item>节点。所以有2次的节点迭代操作。
-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要尽力打好一手烂牌。
posted on 2010-01-04 10:15
Paul Lin 阅读(398)
评论(0) 编辑 收藏 所属分类:
J2SE