Informa不僅提供了對不同版本的RSS Feed source的讀入和解析,同樣也提供了將channel object導(dǎo)出為不同協(xié)議版本的XML文件的功能。這個功能是通過exporters包下的各個導(dǎo)出類來完成的。目前僅支持對RSS協(xié)議的導(dǎo)出,不支持Atom協(xié)議、OPML協(xié)議的導(dǎo)出。
所有的導(dǎo)出類都實(shí)現(xiàn)了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中提供了幾種構(gòu)造方法

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文件的過程其實(shí)很簡單,就是按照RSS 0.9.1規(guī)范的格式將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)方法的其中一個片段,是用于導(dǎo)出channel中的item節(jié)點(diǎn)的。
★RSS_2_0_Exporter
和RSS 0.9.1的導(dǎo)出類似,2.0版本的導(dǎo)出同樣需要實(shí)現(xiàn)ChannelExporterIF接口,同樣提供了和上面一樣參數(shù)類型的構(gòu)造方法。不同的是在2.0的版本,由于新增了幾個定義,所以增加了對應(yīng)的構(gòu)建方法。例如下面的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對象中,關(guān)系是以級聯(lián)的方式存在的,要把這種對象的級聯(lián)關(guān)系展開為平行的字符串,只能通過遞歸的方式訪問到最底層的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導(dǎo)出和0.9.1和2.0協(xié)議的過程有些不同,區(qū)別在于item方面和部分屬性,這里重點(diǎn)介紹一下item方面的導(dǎo)出過程
// ===========================================
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協(xié)議不同,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的詳細(xì)描述。根據(jù)規(guī)范,<item>節(jié)點(diǎn)的rdf:about屬性值必須和rdf:li的resource屬性值一樣。
上面的代碼就是先找出item的列表,構(gòu)建<items>節(jié)點(diǎn)及其子節(jié)點(diǎn)<rdf:seq>,后面是構(gòu)建<item>節(jié)點(diǎn)。所以有2次的節(jié)點(diǎn)迭代操作。
-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
posted on 2010-01-04 10:15
Paul Lin 閱讀(406)
評論(0) 編輯 收藏 所屬分類:
J2SE