在博客添加与朋友更好交流的通道:del.icio.us 和在线阅读器订阅

受文章不用SEO取得成功的10个步骤的启发:

6、添加社会媒体应用服务
你可以增加一些类似del.icio.us或Stumple Upon的书签收藏服务。。。

在博客上添加了del.icio.us网摘的 link rolls (链接列表)、tagrolls(标签列表)和 daily blog posting(网摘每日博客提交) 和 在线阅读器订阅。

下面简单的说一下我使用这两个功能的步骤。

一、 del.icio.us

1、在del.icio.us上申请一个帐号,在您的浏览器中安装相应的插件,如:firefox的插件:del.icio.us/help/firefox/extension ,IE的插件:del.icio.us/help/ie/extension

2、link rolls和tagrolls的使用。

link rolls用来把您的网摘在网页上分享给大家。

登录您的帐户,在右上角的 settings中的link rolls进行相应的设置,拷贝相应的代码到您要显示网摘列表的网页。

这里有一个技巧,因为del.icio.us的服务可能拖慢您的网页,可以把这个代码写在一个单独的页面上,再在要显示的地方用<iframe>标签嵌入代码。我的代码如下:

<html>
<head>
<title>my del.icio.us</title>
<base target="_parent">
</head>

<body bgcolor="#FFFFFF">
<div style="font-size: 13px">
<script type="text/javascript" src="http://del.icio.us/feeds/js/learndiary?tags;count=15;title=my%20del.icio.us;icon;name;showadd" mce_src="http://del.icio.us/feeds/js/learndiary?tags;count=15;title=my%20del.icio.us;icon;name;showadd"></script>
<noscript><a href="http://del.icio.us/learndiary" mce_href="http://del.icio.us/learndiary">my del.icio.us</a></noscript>
</div>
</body>

</html>

其中的<base target="_parent">一定要加上,不然窗口就在<iframe>框架内打开,原因参见:CodeAve.com/HTML - Base Target。改成target="_blank"新开一个窗口。

然后在需要显示link rolls的地方用<iframe>调用上面的页面:

<IFRAME border="0" marginWidth="0" marginHeight="0" src="/my-includes/delicious.htm" frameBorder="0" width="630" height="400" scrolling="no" ></IFRAME>  

tagrolls是把您在delicious中网摘的标签列在网页,用法类似link rolls。我把这个标签列表放在页面标签云中,跟我的博客上的标签云放在一起。

3、daily blog posting的使用。

daily blog posting是把您的网摘每日自动提交到您的博客上成为一篇日记。支持的博客程序: Movable Type, Typepad, WordPress等等。我的是wordpress。

在settings的daily blog posting中add a new thingy,参数含义如下:(摘改自:在blogbus中如何使用delicious的“daily blog posting”功能?

job_name填写你blog名字就可以了,实际上随便填;
out_name;out_pass是你blog的用户名和密码;
out_url填写你在bus的blog的xmlrpc地址,类似于http://www.learndiary.com/xmlrpc.php;
out_time是GMT时间,GMT时间在中国大陆因为是8时区,所以我们的本地时间减去8就是了,如我填的是20,意思是本地时间早上4点提交;
out_blog_id如果你在delicious只输出一个blog的话填1,空着也可以;
out_cat_id可以不填,是你输出的分类编号;然后就等着del.icio.us每天设定的时间朝您的博客自动发送您的网摘列表吧。不过,从已经发过的几篇自动提交的日记来看,基本上是4:20左右发过来的,从del.icio.us中daily blog posting的log记录来看,应该是del.icio.us系统延迟的原因。使用的示例:links for 2007-09-01

二、在线阅读器订阅:
可以供对我的博客感兴趣的朋友用各种RSS在线阅读器订阅。
我试验了一下Feedburner,发现服务不太稳定,原因可以参考一下月光博客的这篇发布RSS Feeds的方法再思考,但大多数朋友好像都使用的这个,就保留了Feedburner的feed服务。哦,如果您的feedburner出现乱码,参看一下这篇文章:FeedBurner乱码解决方法

不知怎么一回事,用wordpress自带的feed地址在有的在线阅读器也有些工作不正常。

最后,我试用了Feedsky,感觉不错,它在一个feed地址的页面集成了常用在线阅读器的订阅,并且可以用这个地址作为本地RSS阅读器的订阅地址。见下截图:

Feedsky服务截图

于是,我的订阅服务是几种都摆在侧边栏底部,如下:

订阅

其中后面两条是订阅我的del.icio.us的网摘和网摘标签的。在您的del.icio.us页面有相应的链接。前者就在您的bookmarks的底部,后者忘了地方。

实现这个目标的困难所在

  1、前段时间把xml-rpc和相应的一些规范看了一下,发现现在网站的web service服务很不规范和统一,例如:roller及一些blog用的是Blogger API、MetaWeblog API、MovableType API,现在的atom项目为了统一规范,在相应的项目中也涉及了web service(具体还没有看),而一些网站提供的web service是自己的方言API,如:www.43things.com的43 Things Web Service API。因为,所有这些API都不统一,为了以后的扩展,所以需要用面向对象的方法抽象其中的共同点,进行充分的设计,使学习日记的这套web service服务能够具有好的可扩展和可重用性。虽然,目标是绑定roller,但是要考虑绑定其它系统,例如:www.43things.com,wordpress等;

  2、因为访问其它系统需要提供其它系统的密码,怎么样来进行别的网站的密码验证是个问题,如果,把密码存在我们的数据库中,明文是不恰当的,加密可以解密,也不很合适,要求用户在向其它网站同时提交帖子的时候输入密码,也不方便。是个问题。但是,既然,www.43things.com已经实现了“post to my blog from 43 Things”,我们可以参考一下别人的作法;

  3、我的目标是绑定到blog.matrix.org.cn上,但是,我初步发现matrix好像禁止了web service,见今天在matrix的blog中试用blog客户端软件:w.bloggar不成功 (1篇) ,这可以通过在自己系统上运行一个roller来进行实验,实际运行时可以把中国实现了web service的BLOG系统绑定,www.43things.com的绑定也要实现,不过要取得网站的web service,好象要取得他们的API KEY,像www.43things.com的setup page中。

  最大的困难是第一个困难,规范不统一。

  为了更快的克服困难,完成这个模块,取得大家的帮助,并同时实现共同学习,共同进步的目标,我把这个模块的完成提交到了行动练功场的程序员练功场中的实战项目一:学习日记的web service模块专栏。要是没有人感兴趣的话,只有我一个人在这里玩,还是觉得有点不舒服的。

基于XML-RPC的BloggerAPI学习(转贴)

基于XML-RPC的BloggerAPI学习(转自:http://blog.donews.com/softbunny/articles/11032.aspx)

blogger_logo.gif   Luliang的mail2blog脚本,通过基于XML-RPC的BloggerAPI来实现的发布blog的功能。

  BloggerAPI是一套程序接口,用以支持远程操作blog.这个规范现在的版本是1.0,是个试验版本和α版本。但是,规范的研发人员不再对BloggerAPI进一步地开发,他们正在制定一套新的、更稳定的API,新项目的名称为echomoinmoin.gif

.

  虽然如此,了解一下这个bloggerAPI还是非常有意义的。一方面有很多语言提供了实现包,另一方面很blog工具也提供了相应的包,如MT。需要说明的是,BloggerAPI提供的功能太有限了,只定义了6个方法或函数,所以出了一个RFC叫 MetaWeblog API,对其进行了扩展。我看了一下,MT2.6.4就支持MetaWeblogAPI.

  下面对二者进行简单地介绍,以后有机会,再跟echo比较一下。:)

BloggerAPI based on XML-RPC

1、方法列表

方法 说明

blogger.newPost 向批定的blog增加新的文章(post),通常会在增加后即发布。

blogger.editPost 编辑一篇文章(post),通常会在修改后发布。

blogger.getUsersBlogs 返回一个成员的所有文章的信息。

blogger.getUserInfo 鉴证一个用户并反回其信息(如userid,email等)

blogger.getTemplate 返回指定的blog的主要或文档索引模板

blogger.setTemplate 编辑指定的blog的主要或文档索引模板

2、blogger.newPost

参数说明

参数 说明

appkey (string) 发送这个post的程序的唯一标志

blogid (string) 这个post即将发送到的blog的标志

username (string) 有权post文章的用户名

password (string) 用户密码

content (string) Post的内容

publish (boolean) 是否发布

示例:

请求XML-RPC调用的数据

POST /api/RPC2 HTTP/1.0

User-Agent: Java.Net Wa-Wa 2.0

Host: plant.blogger.com

Content-Type: text/xml

Content-length: 515

<?xml version="1.0"?>

<methodCall>

<methodName>blogger.newPost</methodName>

<params>

<param><value><string>C6CE3FFB3174106584CBB250C0B0519BF4E294</string></value></param>

<param><value><string>744145</string></value></param>

<param><value><string>ewilliams</string></value></param>

<param><value><string>secret</string></value></param>

<param><value><string>Today I had a peanut butter and pickle sandwich

for lunch. Do you like peanut-butter and pickle sandwiches? I do.

They're yummy. Please comment!</string></value></param>

<param><value><boolean>false</boolean></value></param>

</params>

</methodCall>

成功时的应答

HTTP/1.1 200 OK

Connection: close

Content-Length: 125

Content-Type: text/xml

Date: Mon, 6 Aug 20001 19:55:08 GMT

Server: Java.Net Wa-Wa/Linux

<?xml version="1.0"?>

<methodResponse>

<params>

<param>

<value><string>4515151</string></value>

</param>

</params>

</methodResponse>

失败时的应答

错误信息通过XML-RPC <methodResponse>及<fault> 项返回,包含着的 <struct> 有错误码和描述,这是由xml-rpc规范定义.

HTTP/1.1 200 OK

Connection: close

Content-Length: 225

Content-Type: text/xml

Date: Mon, 6 Aug 20001 19:55:08 GMT

Server: Java.Net Wa-Wa/Linux

<?xml version="1.0"?>

<methodResponse>

<fault>

<value>

<struct>

<member>

<name>faultCode</name>

<value><int>4</int></value>

</member>

<member>

<name>faultString</name>

<value><string>java.lang.Exception: java.lang.Exception: Error: AppKey is

invalid or inactive.</string></value>

</member>

</struct>

</value>

</fault>

</methodResponse>

3、blogger.editPost

参数说明

参数 说明

appkey (string) 发送这个post的程序的唯一标志

postid (string) 某篇post的唯一标志

username (string) 有权修改文章的用户名(作者或管理员)

password (string) 用户密码

content (string) Post的内容

publish (boolean) 是否发布

4、blogger.getUserBlogs

参数说明

参数 说明

appkey (string) 发送这个post的程序的唯一标志

username (string) 用户名

password (string) 用户密码

成功应答示例

HTTP/1.1 200 OK

Connection: close

Content-Length: 125

Content-Type: text/xml

Date: Mon, 6 Aug 20001 19:55:08 GMT

Server: Java.Net Wa-Wa/Linux

<?xml version="1.0" encoding="ISO-8859-1"?>

<methodResponse>

<params>

<param>

<value>

<array>

<data>

<value>

<struct>

<member>

<name>url</name>

<value>http://stuff.foo.com/biz</value>

</member>

<member>

<name>blogid</name>

<value>2997323</value>

</member>

<member>

<name>blogName</name>

<value>Blogger Biz Dev</value>

</member>

</struct>

</value>

<value>

<struct>

<member>

<name>url</name>

<value>http://www.blogger.com/</value>

</member>

<member>

<name>blogid</name>

<value>2723</value>

</member>

<member>

<name>blogName</name>

<value>Blogger News</value>

</member>

</struct>

<value>

<struct>

<member>

<name>url</name>

<value>http://www.geocities.com/rafting/</value>

</member>

<member>

<name>blogid</name>

<value>223723</value>

</member>

<member>

<name>blogName</name>

<value>RaftingBlog</value>

</member>

</struct>

</value>

</value>

</data>

</array>

</value>

</param>

</params>

</methodResponse>

5、blogger.getUserInfo

参数说明

参数 说明

appkey (string) 发送这个post的程序的唯一标志

username (string) 用户名

password (string) 用户密码

成功应答示例

HTTP/1.1 200 OK

Connection: close

Content-Length: 125

Content-Type: text/xml

Date: Mon, 6 Aug 20001 19:55:08 GMT

Server: Java.Net Wa-Wa/Linux

<?xml version="1.0" encoding="ISO-8859-1"?>

<methodResponse>

<params>

<param>

<value>

<struct>

<member>

<name>nickname</name>

<value>Ev.</value>

</member>

<member>

<name>userid</name>

<value>1</value>

</member>

<member>

<name>url</name>

<value>http://www.evhead.com</value>

</member>

<member>

<name>email</name>

<value>ev@pyra.com</value>

</member>

<member>

<name>lastname</name>

<value>Williams</value>

</member>

<member>

<name>firstname</name>

<value>Evan</value>

</member>

</struct>

</value>

</param>

</params>

</methodResponse>

6、blogger.getTemplate

参数说明

参数 说明

appkey (string) 发送这个post的程序的唯一标志

blogid (string) 这个post即将发送到的blog的标志

username (string) 有权post文章的用户名

password (string) 用户密码

templateType (string) 指定返回哪个模板,目前只能是 "main" 或 "archiveIndex".

成功时的应答,....表示此处内容被我省略。

<?xml version="1.0" encoding="ISO-8859-1"?<<methodResponse<<params<<param<<value<<HTML<

<HEAD<

<TITLE<<$BlogTitle$<: <$BlogDescription$<</TITLE<

</BODY<

</HTML<

</value<</param<</params<</methodResponse<

7、blogger.setTemplate

参数说明

参数 说明

appkey (string) 发送这个post的程序的唯一标志

blogid (string) 这个post即将发送到的blog的标志

username (string) 有权post文章的用户名

password (string) 用户密码

template (string) 模板文本(通常是HTML).必须包含 和标签,因它们需要发布。 (?我的mainindex里没有啊)

templateType (string) 指定返回哪个模板,目前只能是 "main" 或 "archiveIndex".

请求格式示例

POST /api/RPC2 HTTP/1.0

User-Agent: Java.Net Wa-Wa 2.0

Host: plant.blogger.com

Content-Type: text/xml

Content-length: 515

<?xml version="1.0"?>

<methodCall>

<methodName>blogger.setTemplate</methodName>

<params>

<param><value><string>C6CE3FFB3174106584CBB250C0B0519BF4E294</string></value></param>

<param><value><string>744154</string></value></param>

<param><value><string>ewilliams</string></value></param>

<param><value><string>secret</string></value></param>

<param><value><string><html><head><title><$BlogTitle$></title></head><body><Blogger><BlogDateHeader><h1><$BlogDateHeaderDate$></h1></BlogDateHeader><$BlogItemBody$><br></Blogger></body></html></string></value></param>

<param><value><string>main</string></value></param>

</params>

</methodCall>

MetaWeblog API

这个rfc的最新发布是在08/26/2003.

1、什么是MetaWeblog API

  MetaWeblog API (MWA)是一套编程接口,允许外面的程序能取得和设置blog文章的文本或属性。它基于流行的XML-RPC通信协议,后者在很多的流行的开发环境中都有了实现的包。

2、MetaWeblog API与Blogger API 的关系

  MetaWeblog API是对Blogger API增强, Blogger API只能取得或设置blog文章的文本内容(hedong问,能取得吗?).在2002年春天MWA面世,在此以前许多blog工具能存储许多扩展数据,但不能访问或编辑这些数据,因为没有一个通过的API。

  到2003年夏天,在本文的写作期间,大部分流行的blog工具和编辑器,能同时支持Blogger API 和MetaWeblog API.

3、MetaWeblog API和 RSS 2.0 的关系

MetaWeblog API利用XML-RPC来描述一篇blog文章. 我们使用了RSS2.0中对一个项的术语来描述一篇blog文章的元数据,而不是重新发明一套。请参照RSS2.0中对文章的title, link 、description,author, comments, enclosure, guid等的定义或命名。更进一步,由于RSS2.0是可扩展的,因而MetaWeblog API也是可扩展的. 我们在MWA中设计了一些用以表述属性和命名空间的约定。

4、基本函数(entry-points)

1)metaWeblog.newPost (blogid, username, password, struct, publish) returns string

2)metaWeblog.editPost (postid, username, password, struct, publish) returns true

3)metaWeblog.getPost (postid, username, password) returns struct

blogid, username, password 和publish参数的含义同 Blogger API. newPost返回的字符串表示post_id,同Blogger API定义的一样. 而那个struct就是MWA的精华所在。

5、数据结构

  在newPost和editPost中,内容信息不再跟BloggerAPI中那是一个字符串,而是一个数据结构。这个数据结构的成员,就是rss2.0中定义的ITEM的元素。参见后面附表。

  当一个元素有属性时,用一个数据结构(属性做成员)传递属性及其相应的值。如enclosure元素,用一个包含url, length 和type的结构传递属性。

对source元素,数据结构的成员为url 和name,前者为source的属性后者为source值。

对categories元素,传递一个字符串数组。在服务器端,如果传来的category不存在,则忽略不报错,且只保存有效的那些category.(hedong,好象没说domain属性的事啊)

  服务器必须忽略所有不能理解的元素。

在调用 metaWeblog.newPost 或 metaWeblog.editPost时,如果数据结构中含有一个名叫flNotOnHomePage的 boolean 值,则主页不显示此文章而只在分类中显示。

6、其它函数

1)metaWeblog.newMediaObject (blogid, username, password, struct) returns struct

  参数的struct,至少包含name, type and bits三个元素。

name是个字符串,可以用来作存储对象的文件名或用于对象列表的显示。它决定weblog如何引用这个对象。如果name和weblog已有一个对象重名,则替换掉已有的对象。

type是个字符串,表示对象的类型,必须是个标准的MIME类型,如 audio/mpeg or image/jpeg or video/quicktime.

bits是个base64-编码的二进制值,包含着对象的内容。

这个结构可以含有其它的元素,这些元素可以或不能被内容管理系统保存.

当调用失败时,抛出error.当成功时,返回的strcut中,至少要有一个元素url,用以指明这个对象如何被访问。其值只能是一个HTTP url或FTP url.

2)metaWeblog.getCategories (blogid, username, password) returns struct

返回的struct中,为每个分类提供一个子结构,子结构中至少包含三个元素:description, httpurl 和 rssurl.

3)metaWeblog.getRecentPosts (blogid, username, password, numberOfPosts) returns array of structs

  返回是一个结构数组,盛放着最新发布的文章信息。每个结构的内容同metaWeblog.getPost返回内容相同.

  numberOfPosts指明要取回的按发布时间倒序计数的文章数量,当值超过总文章数时,返回全部文章信息。

7、传送带属性的元素

  除了enclosure和source元素有专门规定外,其它元素按下列规则处理:

1)如果一个元素有属性,则用一个struct来表示,各属性为struct的子元素。

2)如果一个元素同时有属性和值,则用一个一个struct来表示,各属性为struct的子元素,再增加一个叫_value的子元素,表示元素的值。这也就要求,元素的属性名不能为_value.

8、传送某命名空间的元素

  RSS 2.0允许使用命名空间. 如果你要传送的元素是一个命名空间的一部分,那就在传递给 newPost 或 editPost 的struct中增加一个子struct,以指明命名空间的URL为名,以要传送的元素值为子元素。

9、说明

  在MWA中不要明确要求传送appkey值,如果应用程序要传送appkey,则在struct中增加一个名为appkey的元素,并赋之以相关的值。

附表:RSS2.0中ITEM的元素列表  

元素(Element) 描述(Description) 例子(Example) 重要性 属性

title 项(item)的标题 Venice Film Festival Tries to Quit Sinking 必备

link 项的URL http://www.nytimes.com/2002/09/07/movies/07FEST.html 必备

description 项的大纲 Some of the most heated chatter at the Venice Film Festival this week was about the way that the arrival of the stars at the Palazzo del Cinema was being staged. 必备

author 该项作者的email oprah@oxygen.net 可选

category 包含该项的一个或几个分类(catogory) Simpsons Characters 可选 domain可选,指分类法的URL

comments 该项的评论(comments)页的URL http://www.myblog.org/cgi-local/mt/mt-comments.cgi?entry_id=290 可选

enclosure 描述该附带的媒体对象 可选 url/length/type皆必备,type须是标准MIME类型

guid 项的唯一标志符串 http://inessential.com/2002/09/01.php#a2 可选 isPermaLink可选,默认为真,指明guid是否为一永久URL。

pubDate 项的发布时间 Sun, 19 May 2002 15:21:36 GMT 可选

source 该项来自的RSS道 Quotes of the Day 可选 Url必备

附:MWAAPI清单

   1. metaWeblog.newPost (blogid, username, password, struct, publish) returns string

   2. metaWeblog.editPost (postid, username, password, struct, publish) returns true

   3. metaWeblog.getPost (postid, username, password) returns struct

   4. metaWeblog.newMediaObject (blogid, username, password, struct) returns struct

   5. metaWeblog.getCategories (blogid, username, password) returns struct

   6. metaWeblog.getRecentPosts (blogid, username, password, numberOfPosts) returns array of structs

Trackback: http://tb.donews.net/TrackBack.aspx?PostId=11032

[点击此处收藏本文]   发表于 2004年04月07日 10:24 PM

有关 Blogger API、MetaWeblog API、MovableType API的转帖3篇

1、Blogger API(http://www.blogger.com/developers/api/1_docs/)

Blogger API

By Evan Williams, 8/7/01

Update: 8/13/01 -Ev.

Update: 6/27/03 -Jason Shellen

Welcome to the Blogger API. This site is for independent developers and partners who are interested in hooking into Blogger with other programs, interfaces, or environments.

Please Note: While we will continue to support the Blogger API we will not be developing it further. We are working along with others in the blogging industry to produce a new, more robust API. You can view the current state of the Echo Project here. For further updates, stay tuned to the bloggerDev mail list and www.blogger.com/developers/.

DISCLAIMER: The current state of this interface is experimental and alpha. I'm sure something's broken and other things will change. Your help in figuring these things out are appreciated, but no guarantees are made about reliability, robustness, or longevity. Use at your own risk.

Protocols

The Blogger API is currently implemented for XML-RPC. There may be others some day.

Methods

These are the available methods:

blogger.newPost: Makes a new post to a designated blog. Optionally, will publish the blog after making the post.

blogger.editPost: Edits a given post. Optionally, will publish the blog after making the edit.

blogger.getUsersBlogs: Returns information on all the blogs a given user is a member of.

blogger.getUserInfo: Authenticates a user and returns basic user info (name, email, userid, etc.).

blogger.getTemplate: Returns the main or archive index template of a given blog.

blogger.setTemplate: Edits the main or archive index template of a given blog.

More Info

There is a mailing list.

There is also a node in the XML-RPC directory pointing to implementations and such.

AppKeys

Good news, friends! We no longer require appkey registration to use the Blogger API. If you send us an appkey of 0123456789ABCDEF, then everything will work fine.

Each API request requires an application key ("appkey"), which is a unique identifier for each application using the interface. You can register an application and get a key with this form. You can distribute appkeys with source code that uses the API. Please use different keys for different apps. Appkeys will be used for tracking, stats, and, potentially, other stuff.

Acknowledgements

The Blogger API implementation uses the Helma XML-RPC library for Java. Also?: Tomcat. And lots of help from some of the people over here.

Copyright © 2001 Pyra Labs

2、有没有与网志交互的 Web Services APIs?(http://hanhan.blog.ccidnet.com/blog/ccid/do_showone/tid_18919.html)

有没有与网志交互的 Web Services APIs?

作者: hanhan11 发表日期: 2006-01-20 17:19 文章属性: 原创 复制链接 

许多网志引 擎都提供属于自己的 Web service 接口,通过编程与网志交互,但目前还没有出现一种标准化的东西。

.Text 和 dasBlog 两者都提供某些 .asmx 端点,可以通过 SOAP 来实现编辑功能,但其接口是不同的。Blogger.com 提供基于 XML-RPC 的交互式 API (Blogger API)。Userland Software 对Blogger API 的功能进行了增强,并把它叫做 MetaWeblog API。这些可能是当今公认的网志 APIs,但仍然不是所有网志引擎都支持的。还有一个用于添加评论的独力的 API 叫做 Comment API,同样,它也不是被普遍支持。

  Atom 组正在努力解决这些问题,Atom API 定义了一个标准的网志 API 用于发布和编辑网志内容。有关信息请参考 The Atom Project 网站。 

阅读全文(192) | 回复(0) | 推送 | 举报 

3、wordpress的XML-RPC开发(http://wuhongsheng.com/blog/archives/2006/268/)

February 5, 2006

wordpress的XML-RPC开发

Filed under: 技术 — 吴洪声 @ 11:17 pm

wordpress支持使用xml-rpc进行开发。但网络上很少有相关的资料。这两天在做一个离线写blog的东东,研究到了这个东西,顺便做一下记录。

wordpress的xml-rpc支持多种API,根据从xmlrpc.php里面提取的数据,支持的API有:

// Blogger API

‘blogger.getUsersBlogs’ => ‘this:blogger_getUsersBlogs’,

‘blogger.getUserInfo’ => ‘this:blogger_getUserInfo’,

‘blogger.getPost’ => ‘this:blogger_getPost’,

‘blogger.getRecentPosts’ => ‘this:blogger_getRecentPosts’,

‘blogger.getTemplate’ => ‘this:blogger_getTemplate’,

‘blogger.setTemplate’ => ‘this:blogger_setTemplate’,

‘blogger.newPost’ => ‘this:blogger_newPost’,

‘blogger.editPost’ => ‘this:blogger_editPost’,

‘blogger.deletePost’ => ‘this:blogger_deletePost’,

// MetaWeblog API (with MT extensions to structs)

‘metaWeblog.newPost’ => ‘this:mw_newPost’,

‘metaWeblog.editPost’ => ‘this:mw_editPost’,

‘metaWeblog.getPost’ => ‘this:mw_getPost’,

‘metaWeblog.getRecentPosts’ => ‘this:mw_getRecentPosts’,

‘metaWeblog.getCategories’ => ‘this:mw_getCategories’,

‘metaWeblog.newMediaObject’ => ‘this:mw_newMediaObject’,

// MetaWeblog API aliases for Blogger API

// see http://www.xmlrpc.com/stories/storyReader$2460

‘metaWeblog.deletePost’ => ‘this:blogger_deletePost’,

‘metaWeblog.getTemplate’ => ‘this:blogger_getTemplate’,

‘metaWeblog.setTemplate’ => ‘this:blogger_setTemplate’,

‘metaWeblog.getUsersBlogs’ => ‘this:blogger_getUsersBlogs’,

// MovableType API

‘mt.getCategoryList’ => ‘this:mt_getCategoryList’,

‘mt.getRecentPostTitles’ => ‘this:mt_getRecentPostTitles’,

‘mt.getPostCategories’ => ‘this:mt_getPostCategories’,

‘mt.setPostCategories’ => ‘this:mt_setPostCategories’,

‘mt.supportedMethods’ => ‘this:mt_supportedMethods’,

‘mt.supportedTextFilters’ => ‘this:mt_supportedTextFilters’,

‘mt.getTrackbackPings’ => ‘this:mt_getTrackbackPings’,

‘mt.publishPost’ => ‘this:mt_publishPost’,

// PingBack

‘pingback.ping’ => ‘this:pingback_ping’,

‘pingback.extensions.getPingbacks’ => ‘this:pingback_extensions_getPingbacks’,

‘demo.sayHello’ => ‘this:sayHello’,

‘demo.addTwoNumbers’ => ‘this:addTwoNumbers’

其中最后两个API为用于测试的DEMO。

根据XML-RPC的约定,客户端必须向服务器作以下post:

POST /RPC2 HTTP/1.0

User-Agent: Frontier/5.1.2 (WinNT)

Host: betty.userland.com

Content-Type: text/xml

Content-length: 181

<?xml version="1.0"?>

<methodCall>

<methodName>examples.getStateName</methodName>

<params>

<param>

<value><i4>41</i4></value>

</param>

</params>

</methodCall>

User-Agent和Host项是必须的。

Content-Type的值必须是text/xml.

Content-Length必须指定,而且必须是正确的值。

下面是一个例子:

POST /api/RPC2 HTTP/1.0

User-Agent: Java.Net Wa-Wa 2.0

Host: plant.blogger.com

Content-Type: text/xml

Content-length: 515

<?xml version="1.0"?>

<methodCall>

<methodName>blogger.newPost</methodName>

<params>

<param><value><string>C6CE3FFB3174106584CBB250C0B0519BF4E294</string></value></param>

<param><value><string>744145</string></value></param>

<param><value><string>ewilliams</string></value></param>

<param><value><string>secret</string></value></param>

<param><value><string>Today I had a peanut butter and pickle

sandwich

for lunch. Do you like peanut-butter and pickle sandwiches? I do.

They’re yummy. Please comment!</string></value></param>

<param><value><boolean>false</boolean></value></param>

</params>

</methodCall>

服务器返回的数据:

HTTP/1.1 200 OK

Connection: close

Content-Length: 125

Content-Type: text/xml

Date: Mon, 6 Aug 20001 19:55:08 GMT

Server: Java.Net Wa-Wa/Linux

<?xml version="1.0"?>

<methodResponse>

<params>

<param>

<value><string>4515151</string></value>

</param>

</params>

</methodResponse>

如果出现错误,服务器会返回以下内容:

HTTP/1.1 200 OK

Connection: close

Content-Length: 225

Content-Type: text/xml

Date: Mon, 6 Aug 20001 19:55:08 GMT

Server: Java.Net Wa-Wa/Linux

<?xml version="1.0"?>

<methodResponse>

<fault>

<value>

<struct>

<member>

<name>faultCode</name>

<value><int>4</int></value>

</member>

<member>

<name>faultString</name>

<value><string>java.lang.Exception: java.lang.Exception: Error:

AppKey is

invalid or inactive.</string></value>

</member>

</struct>

</value>

</fault>

</methodResponse>

wordpress, xml rpc

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

这段时间把这个目标停下来,现在重新启动

  想做的太多了:把“123行动!”的总体规划好好做一下,学建模(AndroMDA与ArgoUML),设计模式,学习日记重构,太多的事想做了,还要......

  想做太多是做不成的,现在把这个目标的第2和3步实现。

  1、先把要用到的技术要点初步掌握;

  2、学习一下相关网站的同步操作流程(如:www.43things.com)(实现学习日记和我的blog的双向绑定:http://www.123go.org.cn/disGoalContentAction.do?goalID=1547&naviStr=a10);

  3、系统设计,用ArgoUML认真设计一下,我发现这样很对我的口味,像设置RSS Feed这样的小功能我也用它设计了一下;

  4、实现。

  

  技术要点:

  1)、关于item的内容,请看基于XML-RPC的BloggerAPI学习(http://www.123go.org.cn/disDiaryContentAction.do?searchDiaryID=1771&goalID=1554&naviStr=a10a21547ah1726)

  2)Currently, w.bloggar is compatible with all tools that implements Blogger API, metaWeblog API, MovableType API and b2 API; all based on the XML-RPC definition. (http://www.123go.org.cn/disDiaryContentAction.do?searchDiaryID=1771&goalID=1622&naviStr=a10a21547ah1625)

  可见基础是xml-rpc,可以用“XML-RPC 之 Apache XML-RPC 实例 及规范(转帖2篇)”(http://www.123go.org.cn/disDiaryContentAction.do?searchDiaryID=1771&goalID=1771&naviStr=a10a21547)这篇文章并结合“一个使用了xml_rpc和 Rome 0.6 for RSS / Atom feed generation开源blog ”(http://www.123go.org.cn/disDiaryContentAction.do?searchDiaryID=1716&goalID=1716&naviStr=a10a21547)这个开源Blog系统来学习XML-RPC的使用。

  现在,我基本上可以在Linux下进行写程序了。就用这个功能来进行在linux开发的实践之一吧。

XML-RPC 之 Apache XML-RPC 实例 及规范(转帖2篇)

XML-RPC 之 Apache XML-RPC 实例 (转自:http://spaces.msn.com/lzhuacuo/blog/cns!18730E989D068035!507.entry?_c11_blogpart_blogpart=blogview&_c=blogpart#permalink)

 

XML-RPC 之 Apache XML-RPC 实例

作者:王恩建 来源:http://www.sentom.net

XML-RPC 是工作在 Internet 上的远程过程调用协议。通俗点讲,就是使用 HTTP 协议交互,交互的载体是 XML 文件。XML-RPC 具体的规范说 明请参考这里。

图片来自XML-RPC官方网站

XML-RPC 规范定义了六种数据类型,下表是这六种数据类型与 Java 的数据类型对应表。

XML-RPC Java

<i4> 或 <int> int

<boolean> boolean

<string> java.lang.String

<double> double

<dateTime.iso8601> java.util.Date

<struct> java.util.Hashtable

<array> java.util.Vector

<base64> byte[ ]

XML-RPC 规范的各种平台都有具体实现,XML-RPC 规范的 Java 实现都有好几种,这里我们选择了 Apache XML-RPC。

XML-RPC 服务端实现

先定义一个简单业务对象 MyHandler,远程客户端将调用该对象的方法,具体代码如下:

package net.sentom.xmlrpc;

public class MyHandler {

public String sayHello(String str){

return "Hello," + str;

}

}

然后定义一个 Servlet 名叫 MyXmlRpcServer,远程客户端通过 HTTP-POST 访问该 Servlet。

package net.sentom.xmlrpc;

import java.io.IOException;

import java.io.OutputStream;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.xmlrpc.XmlRpcServer;

public class MyXmlRpcServer extends HttpServlet {

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

XmlRpcServer xmlrpc = new XmlRpcServer();

xmlrpc.addHandler("myHandler", new MyHandler());

byte[] result = xmlrpc.execute(request.getInputStream());

response.setContentType("text/xml");

response.setContentLength(result.length);

OutputStream out = response.getOutputStream();

out.write(result);

out.flush();

}

}

需要特别说明是:

xmlrpc.addHandler("myHandler", new MyHandler());

为了便于理解,这里可以看成普通的:

MyHandler myHandler = new MyHandler();

最后在web.xml文件中加入以下几行:

<servlet>

    <servlet-name>MyXmlRpcServer</servlet-name>

    <servlet-class>net.sentom.xmlrpc.MyXmlRpcServer</servlet-class>

</servlet>

<servlet-mapping>

    <servlet-name>MyXmlRpcServer</servlet-name>

    <url-pattern>/MyXmlRpcServer</url-pattern>

</servlet-mapping>

XML-RPC 客户端实现

客户端相对简单一些,先来一个 Java 客户端实现 MyXmlRpcClient:

package net.sentom.xmlrpc;

import java.io.IOException;

import java.net.MalformedURLException;

import java.util.Vector;

import org.apache.xmlrpc.XmlRpcClient;

import org.apache.xmlrpc.XmlRpcException;

public class MyXmlRpcClient {

public static void main(String[] args) {

try {

XmlRpcClient xmlrpc = new XmlRpcClient("http://localhost:8080/XMLRPC/MyXmlRpcServer");

Vector params = new Vector();

params.addElement("Tom");

String result = (String) xmlrpc.execute("myHandler.sayHello",params);

System.out.println(result);

} catch (MalformedURLException e) {

System.out.println(e.toString());

} catch (XmlRpcException e) {

System.out.println(e.toString());

} catch (IOException e) {

e.printStackTrace();

}

}

http://localhost:8080/XMLRPC/MyXmlRpcServer 为 MyXmlRpcServer 的访问URL。

String result = (String) xmlrpc.execute("myHandler.sayHello",params);

再来一个 Python 客户端实现

import xmlrpclib

url = 'http://localhost:8080/XMLRPC/MyXmlRpcServer';

server = xmlrpclib.Server(url);

print server.myHandler.sayHello('Tom');

 

 

 

添加评论

9:12  |  固定链接 | 引用通告 (0) | 记录它 | Open Source

 

 

固定链接  关闭

 

http://spaces.msn.com/lzhuacuo/blog/cns!18730E989D068035!507.entry

 

 

 

 

 

 

 

XML-RPC规范(中文版) (转自:http://spaces.msn.com/lzhuacuo/blog/cns!18730E989D068035!504.entry?_c11_blogpart_blogpart=blogview&_c=blogpart#permalink)

 

XML-RPC规范(中文版)

把这篇文章转到blog里,希望rainbowsoft能看见有朝一日给blog写支持客户端post的功能时能用上

 

Tue, Jun 15, 1999; by Dave Winer. (翻译:滴水 最后修改时间:2005-3-15 后续完善)

更新 6/30/03 DW

更新 10/16/99 DW

更新 1/21/99 DW

本规范说明的XML-RPC协议实现UserLand Frontier 5.1。

关于非技术性说明,请访问XML-RPC for Newbies。

文档提供了实现XML-RPC所需要的所有信息。

前言

XML-RPC是一种基于Internet的远程函数调用协议。

XML-RPC消息都是HTTP-POST请求。请求的主要部分的XML。服务器端执行后的返回结果同样也是XML格式。

函数调用的参数可以是scalars, numbers, strings, dates等等;也可以是混合型的记录和结构体。

Request请求样式

下面是一个XML-RPC请求的例子:

POST /RPC2 HTTP/1.0

User-Agent: Frontier/5.1.2 (WinNT)

Host: betty.userland.com

Content-Type: text/xml

Content-length: 181

<?xml version="1.0"?>

<methodCall>

   <methodName>examples.getStateName</methodName>

   <params>

      <param>

         <value><i4>41</i4></value>

         </param>

      </params>

   </methodCall>

关于请求头

第一行的URI格式不是特定的。可以为空,如果服务器只处理XML-RPC请求甚至可以只是简单的一个斜线。可是,如果服务器除了XML-RPC外还提供其他的HTTP请求,URI可以帮助我们把请求指向特定的XML-RPC服务。

User-Agent和Host项是必须的。

Content-Type的值必须是text/xml.

Content-Length必须指定,而且必须是正确的值。

有效的格式

XML-RPC具有和XML一样的有效格式,并且是一个<methodCall>结构。

<methodCall>必须包含一个值为字符型的<methodName>子元素,用来表明被调用的方法。这个字符必须符合以下规定:大小写字母、数字0-9、下划线、点、冒号和斜线。至于怎么解释这个字符串将有服务器端来决定。

例如,methodName可以是一个包含执行request请求的文件的名字,可以是数据表中列的名字,还可以是表示目录和文件结构的路径。

如果远程调用接受参数,<methodCall>就必须包含<params>子元素。<params>可以包含任意个<param>元素,每个<param>包含一个<value>子元素。

Scalar <value>s <value>

<value>值被嵌入类型标签中,支持的类型如下表:

Tag Type Example

<i4> or <int> four-byte signed integer -12

<boolean> 0 (false) or 1 (true) 1

<string> string hello world

<double> double-precision signed floating point number -12.214

<dateTime.iso8601> date/time 19980717T14:08:55

<base64> base64-encoded binary eW91IGNhbid0IHJlYWQgdGhpcyE=

如果没有指定类型,默认为字符串。

<struct>s

参数值可以是<struct>。

每个<struct>包含若干<member>,每个<member>包含一个<name>和一个<value>.

如果所示为包含两个值的<struct>

<struct>

   <member>

      <name>lowerBound</name>

      <value><i4>18</i4></value>

      </member>

   <member>

      <name>upperBound</name>

      <value><i4>139</i4></value>

      </member>

   </struct>

<struct>是可以递归使用的,任何<value>都里还可以<struct>或其他任何类型,包括后面将要说明的<array>。

<array>s

值可以个<array>

一个<array>简单的有一个<data>元素。<data>可以是任何合法类型。

下面是一个有4个值的array:

<array>

   <data>

      <value><i4>12</i4></value>

      <value><string>Egypt</string></value>

      <value><boolean>0</boolean></value>

      <value><i4>-31</i4></value>

      </data>

   </array>

<array> elements do not have names.

<array> 元素没有名字。

你可以混合使用上面列出的几种类型。

<arrays>可以递归使用,其值可以是<array>或其他类型,包括上面说明的<strut>。

Response应答样式

下面是一个 XML-RPC请求:

HTTP/1.1 200 OK

Connection: close

Content-Length: 158

Content-Type: text/xml

Date: Fri, 17 Jul 1998 19:55:08 GMT

Server: UserLand Frontier/5.1.2-WinNT

<?xml version="1.0"?>

<methodResponse>

   <params>

      <param>

         <value><string>South Dakota</string></value>

         </param>

      </params>

   </methodResponse>

Respnse应答格式

除非底层操作出现错,否则总是返回200 OK.

Content-Type是text/xml。必须设置Content-Length,并且必须是正确的值。

应到内容是一个简单的XML,可是是<methodResponse>包含一个<params>,<params>包含一个<param>,<param>包含一个<value>。

<methodResponse>可能含有一个<fault>标签。<fault>的值为<struct>类型,<struct>有两个元素,值为<int>的<faultCode>和值为<string>的<faultString>。

<methodResponse>不能既有<fault>又有<params>。

Fault example

HTTP/1.1 200 OK

Connection: close

Content-Length: 426

Content-Type: text/xml

Date: Fri, 17 Jul 1998 19:55:02 GMT

Server: UserLand Frontier/5.1.2-WinNT

<?xml version="1.0"?>

<methodResponse>

   <fault>

      <value>

         <struct>

            <member>

               <name>faultCode</name>

               <value><int>4</int></value>

               </member>

            <member>

               <name>faultString</name>

               <value><string>Too many parameters.</string></value>

               </member>

            </struct>

         </value>

      </fault>

   </methodResponse>

Strategies/Goals

Firewalls. The goal of this protocol is to lay a compatible foundation across different environments, no new power is provided beyond the capabilities of the CGI interface. Firewall software can watch for POSTs whose Content-Type is text/xml.

Discoverability. We wanted a clean, extensible format that's very simple. It should be possible for an HTML coder to be able to look at a file containing an XML-RPC procedure call, understand what it's doing, and be able to modify it and have it work on the first or second try.

Easy to implement. We also wanted it to be an easy to implement protocol that could quickly be adapted to run in other environments or on other operating systems.

Updated 1/21/99 DW

The following questions came up on the UserLand discussion group as XML-RPC was being implemented in Python.

The Response Format section says "The body of the response is a single XML structure, a <methodResponse>, which can contain a single <params>..." This is confusing. Can we leave out the <params>?

No you cannot leave it out if the procedure executed successfully. There are only two options, either a response contains a <params> structure or it contains a <fault> structure. That's why we used the word "can" in that sentence.

Is "boolean" a distinct data type, or can boolean values be interchanged with integers (e.g. zero=false, non-zero=true)?

Yes, boolean is a distinct data type. Some languages/environments allow for an easy coercion from zero to false and one to true, but if you mean true, send a boolean type with the value true, so your intent can't possibly be misunderstood.

What is the legal syntax (and range) for integers? How to deal with leading zeros? Is a leading plus sign allowed? How to deal with whitespace?

An integer is a 32-bit signed number. You can include a plus or minus at the beginning of a string of numeric characters. Leading zeros are collapsed. Whitespace is not permitted. Just numeric characters preceeded by a plus or minus.

What is the legal syntax (and range) for floating point values (doubles)? How is the exponent represented? How to deal with whitespace? Can infinity and "not a number" be represented?

There is no representation for infinity or negative infinity or "not a number". At this time, only decimal point notation is allowed, a plus or a minus, followed by any number of numeric characters, followed by a period and any number of numeric characters. Whitespace is not allowed. The range of allowable values is implementation-dependent, is not specified.

What characters are allowed in strings? Non-printable characters? Null characters? Can a "string" be used to hold an arbitrary chunk of binary data?

Any characters are allowed in a string except < and &, which are encoded as < and &. A string can be used to encode binary data.

Does the "struct" element keep the order of keys. Or in other words, is the struct "foo=1, bar=2" equivalent to "bar=2, foo=1" or not?

The struct element does not preserve the order of the keys. The two structs are equivalent.

Can the <fault> struct contain other members than <faultCode> and <faultString>? Is there a global list of faultCodes? (so they can be mapped to distinct exceptions for languages like Python and Java)?

A <fault> struct may not contain members other than those specified. This is true for all other structures. We believe the specification is flexible enough so that all reasonable data-transfer needs can be accomodated within the specified structures. If you believe strongly that this is not true, please post a message on the discussion group.

There is no global list of fault codes. It is up to the server implementer, or higher-level standards to specify fault codes.

What timezone should be assumed for the dateTime.iso8601 type? UTC? localtime?

Don't assume a timezone. It should be specified by the server in its documentation what assumptions it makes about timezones.

Additions

<base64> type. 1/21/99 DW.

Updated 6/30/03 DW

Removed "ASCII" from definition of string.

Changed copyright dates, below, to 1999-2003 from 1998-99.

Copyright and disclaimer

? Copyright 1998-2003 UserLand Software. All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and these paragraphs are included on all such copies and derivative works.

This document may not be modified in any way, such as by removing the copyright notice or references to UserLand or other organizations. Further, while these copyright restrictions apply to the written XML-RPC specification, no claim of ownership is made by UserLand to the protocol it describes. Any party may, for commercial or non-commercial purposes, implement this protocol without royalty or license fee to UserLand. The limited permissions granted herein are perpetual and will not be revoked by UserLand or its successors or assigns.

This document and the information contained herein is provided on an "AS IS" basis and USERLAND DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

 

 

 

添加评论

9:09  |  固定链接 | 引用通告 (0) | 记录它 | Open Source

 

 

固定链接  关闭

 

http://spaces.msn.com/lzhuacuo/blog/cns!18730E989D068035!506.entry

 

 

 

 

 

 

 

XML-RPC

 

XML-RPC

 

 

 

\

http://www.xmlrpc.com/

Java Technology and Web Services

http://java.sun.com/webservices/index.jsp

Web services are Web-based enterprise applications that use open, XML-based standards and transport protocols to exchange data with calling clients. Java 2 Platform, Enterprise Edition (J2EE) provides the APIs and tools you need to create and deploy interoperable Web services and clients.

Java Technology and Web Services is organized into these subcategories:

Java Web Services Developer Pack (Java WSDP)

Java API for XML-Based RPC (JAX-RPC)

Java API for XML Registries (JAXR)

Java API for XML Processing (JAXP)

Java Architecture for XML Binding (JAXB)

SOAP with Attachments API for Java (SAAJ)

XML and Web Services Security

Java API for XML-Based RPC >

http://java.sun.com/xml/downloads/jaxrpc.html#jaxrpcspec10

Java API for XML-Based RPC (JAX-RPC) Specification 2.0

 

 

 

添加评论

8:35  |  固定链接 | 引用通告 (0) | 记录它 | Open Source

 

完成"issue 12"的学习日记rrs支持

  作了一点完善。rss的全部代码已经提交完毕,并且用在了现在的系统中。

  但是,我发现,至今为止,基本没有什么人用rss来订阅学习日记的的内容。我也不知道为什么?可能最主要的原因是学习日记的内容太少了,太浅了,订阅的价值不大;其次是rss订阅还不为一些朋友了解和习惯使用吧。

为什么学习日记没有实现rss0.91的支持

  在使用rome生成的程序中,我发现了rss0.91的一些限制:例如:language是channel的必需元素,copyRight的长度不能超过100个字符(?),description的长度不能超过?个字符

  我生成的内容不符合这些限制,所以就不支持rss0.91了(包括RSS 0.91 Netscape 和 RSS 0.91 Userland)。

  我只是从程序的出错信息中得知这些限制的,还没有具体去学习这些规范。

rss支持第一次代码提交

  程序类基本完成,页面还没有做。使用rome可以较好的实现所有rss版本和atom的feed。个人认为还是应用得比较成功的。今天早上已经把全部代码和argoUML0.18.1的粗略设计提交到了cvs库。

  主要类的实现概略:(希望得到你的意见或建议,也供想使用rome的朋友参考。)

  1、

//$ Id: RSSAction.java,v 1.0 2006/02/26 20:49:06 dashing_meng Exp $

//Copyright (c) 2004-2005 Http://www.learndiary.com. All Rights Reserved.

//Permission to use, copy, modify, and distribute this software and its

//documentation without fee, and without a written agreement is hereby

//granted, provided that the above copyright notice and this paragraph

//appear in all copies.  This software program and documentation are

//copyrighted by http://www.learndiary.com. The software program and

//documentation are supplied "AS IS", without any accompanying services

//from The LearnDiary. The LearnDiary does not warrant that the operation

//of the program will be uninterrupted or error-free. The end-user

//understands that the program was developed for research purposes and is

//advised not to rely exclusively on the program for any reason.

//IN NO EVENT SHALL HTTP://WWW.LEARNDIARY.COM BE LIABLE TO ANY PARTY FOR

//DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,

//INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS

//DOCUMENTATION, EVEN IF HTTP://WWW.LEARNDIARY.COM HAS BEEN ADVISED OF THE

//POSSIBILITY OF SUCH DAMAGE. HTTP://WWW.LEARNDIARY.COM SPECIFICALLY

//DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE

//SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND

//HTTP://WWW.LEARNDIARY.COM HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,

//SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

package com.learndiary.website.action.rss;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionForward;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.apache.struts.action.ActionMapping;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionForm;

import com.learndiary.website.util.rss.*;

import com.sun.syndication.io.FeedException;

/**

 * action for generating rss feed.

 * @author http://www.learndiary.com,LearnDiary Develop Group

 */

public class RSSAction extends Action {

  /* {src_lang=Java}*/

  private Log __log = LogFactory.getFactory().getInstance(this.getClass());

  ;

  /* {transient=false, volatile=false}*/

  /**

   *  pseudo code:

   *  {

   *    //the rss feed type,includes:

   *    //latestDiariesOfMyProcessGoal, latestAdvicesOfMyDiaries,

   *    //latestGoals, mostJoinedGoals, latestDiaries, latestAdvices,

   *    //latestDiariesOfGoal, latestAdvicesOfGoal,etc..

   *    String type=request.getParameter("type");

   *   

   *    //feed type,includes:

   *    //RSS 0.90, RSS 0.91 Netscape, RSS 0.91 Userland,

   *    //RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0,

   *    // RSS 2.0, Atom 0.3, Atom 1.0

   *    String rssVersion = request.getParameter("feedType");

   * 

   *    //entries number:

   *    //user can specify how many entries he would like to see,

   *    //the default entries number is 39.

   *    int entriesNum=Integer.parseInt(request.getParemeter("entriesNum"));

   * 

   *    //user's name:

   *    //for getting specified user's entries.

   *    String userName=request.getParameter("userName");

   * 

   *    //channel article's ID:

   *    //it is only for subscribing a goal's sub-entries,goalID.

   *    int  channelID=Integer.parseInt(request.getParemeter("channelID"));

   *   

   *    if (type.equal("latestDiaries")){

   *      RSSGenerator generator = new  LatestDiariesRSS(feedType, entriesNum);

   *      generator.outputFeed();

   *    }else if(type.equal("latestAdvices")){

   *      RSSGenerator generator = new  LatestAdvicesRSS(feedType, entriesNum);

   *      generator.outputFeed();

   *    }else if(type.equal("latestDiariesOfMyProcessGoal")){

   *      RSSGenerator generator = new  LatestDiariesOfMyProcessGoalRSS(feedType, entriesNum, userName);

   *      generator.outputFeed();

   *    }else if(type.equal("latestMyDiariesOfMyProcessGoal")){

   *      RSSGenerator generator = new  LatestMyDiariesOfMyProcessGoalRSS(feedType, entriesNum, userName);

   *      generator.outputFeed();

   *    }else if(type.equal("latestAdvicesOfMyDiaries")){

   *      RSSGenerator generator = new  LatestAdvicesOfMyDiariesRSS(feedType, entriesNum, userName);

   *      generator.outputFeed();

   *    }else if(type.equal("latestDiariesOfGoal")){

   *      RSSGenerator generator = new  LatestDiariesOfGoalRSS(feedType, entriesNum, channelID);

   *      generator.outputFeed();

   *    }else if(type.equal("latestAdvicesOfGoal")){

   *      RSSGenerator generator = new  LatestAdvicesOfGoalRSS(feedType, entriesNum, channelID);

   *      generator.outputFeed();

   *    }else if(type.equal("latestGoals")){

   *      RSSGenerator generator = new  LatestGoalsRSS(feedType, entriesNum);

   *      generator.outputFeed();

   *    }else if(type.equal("mostJoinedGoals")){

   *      RSSGenerator generator = new  MostJoinedGoalsRSS(feedType, entriesNum);

   *      generator.outputFeed();

   *    }else {

   *      show "error type" message;

   *    }

   *  }//end of excute() method

   *  

   */

  public ActionForward execute(

    ActionMapping mapping,

    ActionForm form,

    HttpServletRequest request,

    HttpServletResponse response) {

    //the rss feed type,includes:

    //latestDiariesOfMyProcessGoal, latestAdvicesOfMyDiaries,

    //latestGoals, mostJoinedGoals, latestDiaries, latestAdvices,

    //latestDiariesOfGoal, latestAdvicesOfGoal,etc..

    String type = request.getParameter("type");

    //feed type,includes:

    //RSS 0.90, RSS 0.91 Netscape, RSS 0.91 Userland,

    //RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0,

    // RSS 2.0, Atom 0.3, Atom 1.0

    String feedType = request.getParameter("feedType");

    //entries number:

    //user can specify how many entries he would like to see,

    //the default entries number is 39.

    int entriesNum = Integer.parseInt(request.getParameter("entriesNum"));

    //user's name:

    //for getting specified user's entries.

    String userName = request.getParameter("userName");

    //channel article's ID:

    //it is only for subscribing a goal's sub-entries,goalID.

    int channelID = 0;

    String channelIDStr = request.getParameter("channelID");

    if (channelIDStr != null && !channelIDStr.equals(""))

      channelID = Integer.parseInt(channelIDStr);

    try {

      if (type.equals("latestDiaries")) {

        RSSGenerator generator = new LatestDiariesRSS(feedType, entriesNum);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestDiaries:feedType="

            + feedType

            + " entriesNum="

            + entriesNum);

      } else if (type.equals("latestAdvices")) {

        RSSGenerator generator = new LatestAdvicesRSS(feedType, entriesNum);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestAdvices:feedType="

            + feedType

            + " entriesNum="

            + entriesNum);

      } else if (type.equals("latestDiariesOfMyProcessGoal")) {

        RSSGenerator generator =

          new LatestDiariesOfMyProcessGoalRSS(feedType, entriesNum, userName);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestDiariesOfMyProcessGoal:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " userName="

            + userName);

      } else if (type.equals("latestMyDiariesOfMyProcessGoal")) {

        RSSGenerator generator =

          new LatestMyDiariesOfMyProcessGoalRSS(feedType, entriesNum, userName);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestMyDiariesOfMyProcessGoal:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " userName="

            + userName);

      } else if (type.equals("latestAdvicesOfMyDiaries")) {

        RSSGenerator generator =

          new LatestAdvicesOfMyDiariesRSS(feedType, entriesNum, userName);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestAdvicesOfMyDiaries:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " userName="

            + userName);

      } else if (type.equals("latestDiariesOfGoal")) {

        RSSGenerator generator =

          new LatestDiariesOfGoalRSS(feedType, entriesNum, channelID);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestDiariesOfGoal:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " channelID="

            + channelID);

      } else if (type.equals("latestAdvicesOfGoal")) {

        RSSGenerator generator =

          new LatestAdvicesOfGoalRSS(feedType, entriesNum, channelID);

        generator.outputFeed(response);

        __log.info(

          "get feed of latestAdvicesOfGoal:feedType="

            + feedType

            + " entriesNum="

            + entriesNum

            + " channelID="

            + channelID);

      } else if (type.equals("latestGoals")) {

        RSSGenerator generator = new LatestGoalsRSS(feedType, entriesNum);

        generator.outputFeed(response);

        __log.info(

          "get feed of LatestGoalsRSS:feedType="

            + feedType

            + " entriesNum="

            + entriesNum);

      } else if (type.equals("mostJoinedGoals")) {

        RSSGenerator generator = new MostJoinedGoalsRSS(feedType, entriesNum);

        generator.outputFeed(response);

        __log.info(

          "get feed of mostJoinedGoals:feedType="

            + feedType

            + " entriesNum="

            + entriesNum);

      } else {

        return mapping.findForward("commonFailure");

      }

    } catch (IOException e1) {

      e1.printStackTrace();

    } catch (FeedException e2) {

      e2.printStackTrace();

    } catch (Exception e3) {

      e3.printStackTrace();

    }

    return null;

  }

}

  2、

//$ Id: RSSGenerator.java,v1.4  2006/02/26 20:49:06 dashing_meng Exp $

//Copyright (c) 2004-2005 Http://www.learndiary.com. All Rights Reserved.

//Permission to use, copy, modify, and distribute this software and its

//documentation without fee, and without a written agreement is hereby

//granted, provided that the above copyright notice and this paragraph

//appear in all copies.  This software program and documentation are

//copyrighted by http://www.learndiary.com. The software program and

//documentation are supplied "AS IS", without any accompanying services

//from The LearnDiary. The LearnDiary does not warrant that the operation

//of the program will be uninterrupted or error-free. The end-user

//understands that the program was developed for research purposes and is

//advised not to rely exclusively on the program for any reason.

//IN NO EVENT SHALL HTTP://WWW.LEARNDIARY.COM BE LIABLE TO ANY PARTY FOR

//DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,

//INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS

//DOCUMENTATION, EVEN IF HTTP://WWW.LEARNDIARY.COM HAS BEEN ADVISED OF THE

//POSSIBILITY OF SUCH DAMAGE. HTTP://WWW.LEARNDIARY.COM SPECIFICALLY

//DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE

//SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND

//HTTP://WWW.LEARNDIARY.COM HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,

//SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

package com.learndiary.website.util.rss;

import com.sun.syndication.feed.synd.SyndCategory;

import com.sun.syndication.feed.synd.SyndCategoryImpl;

import com.sun.syndication.feed.synd.SyndContent;

import com.sun.syndication.feed.synd.SyndContentImpl;

import com.sun.syndication.feed.synd.SyndEntry;

import com.sun.syndication.feed.synd.SyndEntryImpl;

import com.sun.syndication.feed.synd.SyndFeed;

import com.sun.syndication.io.FeedException;

import com.sun.syndication.io.SyndFeedOutput;

import com.learndiary.website.Constants;

import com.learndiary.website.Consts;

import com.learndiary.website.model.ArticleInfo;

import java.io.IOException;

import java.io.PrintWriter;

import java.text.DateFormat;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import org.apache.commons.logging.Log;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import com.learndiary.website.db.ArticleDB;

import com.learndiary.website.dao.TransContext;

import javax.servlet.http.HttpServletResponse;

/**

 * the base abstract class for generating rss feed.

 * @author http://www.learndiary.com,LearnDiary Develop Group

 */

public abstract class RSSGenerator {

  protected static final DateFormat DATE_PARSER =

    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  /* {transient=false, volatile=false}*/

  protected Log __log = null; //should it be added "static" modifier?

  /* {transient=false, volatile=false}*/

  protected static TransContext trans = null;

  /* {transient=false, volatile=false}*/

  protected static ArticleDB myDB = null;

  /* {transient=false, volatile=false}*/

  protected String feedType = "rss_2.0";

  /* {transient=false, volatile=false}*/

  protected int entriesNum = 39;

  /* {transient=false, volatile=false}*/

  protected final List entries = new ArrayList();

  /* {transient=false, volatile=false}*/

  protected SyndFeed feed = null;

  /* {transient=false, volatile=false}*/

  protected String catName = null;

  /* {transient=false, volatile=false}*/

  /**

   *  output the rss feed xml page

   *  pseudo code:

   *  {

   *    res.setContentType("application/xml; charset=UTF-8");

   *    SyndFeedOutput output = new SyndFeedOutput();

   *    output.output(feed,res.getWriter());

   *  }

   * @param res the HttpServletResponse come from the excute() method of struts Action 

   */

  public void outputFeed(HttpServletResponse res)

    throws IOException, FeedException, Exception {

    try {

      this.setFeed();

    } catch (Exception e1) {

      e1.printStackTrace();

    }

    res.setContentType("application/xml; charset=UTF-8");

    SyndFeedOutput output = new SyndFeedOutput();

    PrintWriter out = res.getWriter();

    try {

      output.output(feed, out);

    } catch (IOException e) {

      e.printStackTrace();

    } catch (FeedException e) {

      e.printStackTrace();

    }

  }

  /**

   *  set rss feed

   */

  abstract protected void setFeed() throws Exception;

  /**

   *  set articles into the entries list of the rss feed

   *  {

   *    List artList=(ArrayList)myDB.getCPageList(0, entriesNum, "article", condition, Consts.ART_WRITE, Consts.DIR_DESC, Consts.HTML_FLAG);

   *    Iterator it=artList.listIterator();

   *     while (it.hasNext()) {

   *        ArticleInfo anArt = (ArticleInfo)it.next();

   *        entries.addEntry(anArt);

   *    }

   *  }

   * @param condition "WHERE" clause in the sql statement,for example:"WHERE parentID=1 AND typeID=2" 

   */

  protected void setEntries(String condition,int orderType,int direction,int htmlFlag) throws Exception {

    List artList = new ArrayList();

    __log.debug("setEntries() in RSSGenerator:entriesNum="+entriesNum+" condition is:"+condition);

    try {

      artList =

        (ArrayList) myDB.getCPageList(

          0,

          entriesNum,

          "article",

          condition,

          orderType,

          direction,

          htmlFlag);

    } catch (Exception e) {

      e.printStackTrace();

    }

    __log.debug("artList is:"+artList);

    if (artList == null)

      return;

    Iterator it = artList.listIterator();

    while (it.hasNext()) {

      ArticleInfo anArt = (ArticleInfo) it.next();

      this.addEntry(anArt);

    }

  }

  /**

   *  add an articleInfo into rss entries list

   *  pseudo code:

   *  {

   *    SyndEntry entry = new SyndEntryImpl();

   *    entry.setAuthor(anArt.getUserName());

   *    entry.setTitle(title);

   *    entry.setLink(link);

   *    entry.setPublishedDate(DATE_PARSER.parse(date));

   *    SyndContent description = new SyndContentImpl();

   *    description.setType("text/plain");

   *    description.setValue(blogContent);

   *    entry.setDescription(description);

   *    List categories = new ArrayList();

   *    SyndCategory category = new SyndCategoryImpl();

   *    category.setName(catName);

   *    categories.add(category);

   *    entry.setCategories(categories);

   *    entries.add(entry);

   *  }

   * @param anArt an article's information

   */

  private void addEntry(ArticleInfo anArt) throws Exception, ParseException {

    int artType = anArt.getTypeID();

    int artID = anArt.getArticleID();

    int parentID = anArt.getParentID();

    String parentName = anArt.getParentArticleName();

    String parentParentName = null;

    int parentType = 0;

    try {

      parentType = myDB.getArtTypeByID(parentID);

      if (parentType == Consts.DIARY_TYPE)

        parentParentName = myDB.getArtNameByID(myDB.getParentIDByID(parentID));

    } catch (Exception e1) {

      e1.printStackTrace();

    }

    String artName = anArt.getArticleName();

    String artAuthor = anArt.getUserName();

    String artContent = anArt.getArticleText();

    String artResource = anArt.getArticleResource();

    String writeDate = anArt.getWriteDate();

    SyndEntry entry = new SyndEntryImpl();

    entry.setAuthor(artAuthor);

    __log.debug("set entry's author is:" + artAuthor);

    entry.setTitle(artName);

    __log.debug("set entry's title is:" + artName);

    //get article's link and rss description head information;

    String link = null, headInfo = null;

    if (artType == Consts.GOAL_TYPE) {

      link =

        Constants.APPLICATION_PATH.concat(

          "/disGoalContentAction.do?goalID=" + artID);

      headInfo =

        "\""

          + artAuthor

          + "\" 在:"

          + writeDate

          + " 首先创建了目标:\""

          + artName

          + "\"<p>";

    } else if (artType == Consts.DIARY_TYPE) {

      link =

        Constants.APPLICATION_PATH.concat(

          "/disDiaryContentAction.do?goalID" + artID);

      headInfo =

        "\""

          + artAuthor

          + "\" 于:"

          + writeDate

          + " 在目标:\""

          + parentName

          + "\"下添加了日记:\""

          + artName

          + "\"<p>";

    } else if (

      artType == Consts.ADVICE_TYPE && parentType == Consts.GOAL_TYPE) {

      link =

        Constants.APPLICATION_PATH.concat(

          "/disGoalContentAction.do?goalID" + parentID);

      headInfo =

        "\""

          + artAuthor

          + "\" 于:"

          + writeDate

          + " 在目标:\""

          + parentName

          + "\"下添加了评论:\""

          + artName

          + "\"<p>";

    } else {

      link =

        Constants.APPLICATION_PATH.concat(

          "/disDiaryContentAction.do?goalID" + parentID);

      headInfo =

        "\""

          + artAuthor

          + "\" 于:"

          + writeDate

          + " 在目标:\""

          + parentParentName

          + "\"的日记:\""

          + parentName

          + "\"下添加了评论:\""

          + artName

          + "\"<p>";

    }

    entry.setLink(link);

    __log.debug("set entry's link is:" + link);

    try {

      entry.setPublishedDate(DATE_PARSER.parse(writeDate));

      __log.debug("set entry's publishedDate is:" + writeDate);

    } catch (ParseException e) {

      e.printStackTrace();

    }

    SyndContent description = new SyndContentImpl();

    description.setType("text/plain");

    String value =

      headInfo.concat("文章内容:<br>").concat(artContent).concat(

        "<p>相关资源:<br>" + artResource);

    description.setValue(value);

    __log.debug("set description's value is:" + value);

    entry.setDescription(description);

    List categories = new ArrayList();

    SyndCategory category = new SyndCategoryImpl();

    category.setName(catName);

    __log.debug("set category's name is:" + catName);

    categories.add(category);

    entry.setCategories(categories);

    entries.add(entry);

    __log.debug(

      "add an entry into entriesList.\n*********************************");

  }

}

  3、

//$ Id: LatestGoalsRSS.java,v 1.0 2006/02/26 20:49:06 dashing_meng Exp $

//Copyright (c) 2004-2005 Http://www.learndiary.com. All Rights Reserved.

//Permission to use, copy, modify, and distribute this software and its

//documentation without fee, and without a written agreement is hereby

//granted, provided that the above copyright notice and this paragraph

//appear in all copies.  This software program and documentation are

//copyrighted by http://www.learndiary.com. The software program and

//documentation are supplied "AS IS", without any accompanying services

//from The LearnDiary. The LearnDiary does not warrant that the operation

//of the program will be uninterrupted or error-free. The end-user

//understands that the program was developed for research purposes and is

//advised not to rely exclusively on the program for any reason.

//IN NO EVENT SHALL HTTP://WWW.LEARNDIARY.COM BE LIABLE TO ANY PARTY FOR

//DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,

//INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS

//DOCUMENTATION, EVEN IF HTTP://WWW.LEARNDIARY.COM HAS BEEN ADVISED OF THE

//POSSIBILITY OF SUCH DAMAGE. HTTP://WWW.LEARNDIARY.COM SPECIFICALLY

//DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE

//SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND

//HTTP://WWW.LEARNDIARY.COM HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,

//SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

package com.learndiary.website.util.rss;

import org.apache.commons.logging.LogFactory;

import com.learndiary.website.Constants;

import com.learndiary.website.Consts;

import com.learndiary.website.dao.TransContext;

import com.learndiary.website.db.ArticleDB;

import com.sun.syndication.feed.synd.SyndFeedImpl;

/**

 * for generating latest goals' rss feed.

 * @author http://www.learndiary.com,LearnDiary Develop Group

 */

public class LatestGoalsRSS extends RSSGenerator {

  public LatestGoalsRSS(String feedType, int entriesNum) {

    this.__log = LogFactory.getFactory().getInstance(this.getClass());

    try {

      RSSGenerator.trans = new TransContext();

      RSSGenerator.myDB = new ArticleDB(trans);

    } catch (Exception e) {

      e.printStackTrace();

    }

    this.feedType = feedType;

    this.entriesNum = entriesNum;

    this.catName = "最新创建的" + entriesNum + "个目标";

  }

  protected void setFeed() throws Exception {

    try {

      this.setEntries("WHERE typeID=1",Consts.ART_WRITE,Consts.DIR_DESC,Consts.HTML_FLAG);

    } catch (Exception e) {

      e.printStackTrace();

    }

    feed = new SyndFeedImpl();

    feed.setFeedType(feedType);

    feed.setTitle("最新创建的" + entriesNum + "个目标");

    feed.setLink(Constants.APPLICATION_PATH.concat("/indexAction.do"));

    feed.setDescription("学习日记里按时间排序的最新创建的" + entriesNum + "个目标。");

    feed.setCopyright(

      "除原作者特别声明外,本站所有帖子以<a rel=\"license\" href=\"http://creativecommons.org/licenses/by/2.0/\" target=\"creativecommons\">Creative Commons License</a>方式授权.");

    feed.setEntries(entries);

  }

}