【原】RSS工具开发手记(14)---Informa的exporters包

【原】RSS工具开发手记(14)---Informa的exporters包
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 ([email protected]
 
*/

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次的节点迭代操作。


-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要尽力打好一手烂牌。

你可能感兴趣的:(【原】RSS工具开发手记(14)---Informa的exporters包)