<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>润物无声 &#187; XML</title>
	<atom:link href="http://blog.zhourunsheng.com/tag/xml/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.zhourunsheng.com</link>
	<description>天空一朵雨做的云</description>
	<lastBuildDate>Sat, 08 May 2021 05:17:21 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.41</generator>
	<item>
		<title>XML-RPC 之 Android实现（下）</title>
		<link>http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88%e4%b8%8b%ef%bc%89/</link>
		<comments>http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88%e4%b8%8b%ef%bc%89/#comments</comments>
		<pubDate>Tue, 05 Jul 2011 09:55:01 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[移动开发]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[RPC]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=371</guid>
		<description><![CDATA[<p>代码对RPC的请求进行了封装，至于XML格式的生成请参照上一篇博文《XML-RPC 之 Android实现（上 [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88%e4%b8%8b%ef%bc%89/">XML-RPC 之 Android实现（下）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>代码对RPC的请求进行了封装，至于XML格式的生成请参照上一篇博文《<a title="XML-RPC 之 Android实现（上）" rel="bookmark" href="../?p=346">XML-RPC 之 Android实现（上）</a>》<br />
<code>package org.xmlrpc.android;</code></p>
<p><code>import java.io.File;<br />
import java.io.FileWriter;<br />
import java.io.PushbackInputStream;<br />
import java.io.StringWriter;<br />
import java.net.URI;<br />
import java.net.URL;<br />
import java.security.KeyManagementException;<br />
import java.security.KeyStoreException;<br />
import java.security.NoSuchAlgorithmException;<br />
import java.security.UnrecoverableKeyException;<br />
import java.util.Map;</code></p>
<p><span id="more-371"></span></p>
<p><code>import org.apache.http.HttpEntity;<br />
import org.apache.http.HttpResponse;<br />
import org.apache.http.HttpStatus;<br />
import org.apache.http.auth.UsernamePasswordCredentials;<br />
import org.apache.http.client.methods.HttpPost;<br />
import org.apache.http.entity.FileEntity;<br />
import org.apache.http.entity.StringEntity;<br />
import org.apache.http.params.CoreConnectionPNames;<br />
import org.apache.http.params.HttpParams;<br />
import org.apache.http.params.HttpProtocolParams;<br />
import org.wordpress.android.util.ConnectionClient;<br />
import org.xmlpull.v1.XmlPullParser;<br />
import org.xmlpull.v1.XmlPullParserFactory;<br />
import org.xmlpull.v1.XmlSerializer;</p>
<p>import android.os.Environment;<br />
import android.util.Log;<br />
import android.util.Xml;</p>
<p>public class XMLRPCClient {<br />
private static final String TAG_METHOD_CALL = "methodCall";<br />
private static final String TAG_METHOD_NAME = "methodName";<br />
private static final String TAG_METHOD_RESPONSE = "methodResponse";<br />
private static final String TAG_PARAMS = "params";<br />
private static final String TAG_PARAM = "param";<br />
private static final String TAG_FAULT = "fault";<br />
private static final String TAG_FAULT_CODE = "faultCode";<br />
private static final String TAG_FAULT_STRING = "faultString";</p>
<p>private ConnectionClient client;<br />
private HttpPost postMethod;<br />
private XmlSerializer serializer;<br />
private HttpParams httpParams;</p>
<p>/**<br />
* XMLRPCClient constructor. Creates new instance based on server URI<br />
*<br />
* @param XMLRPC<br />
*            server URI<br />
*/<br />
public XMLRPCClient(URI uri, String httpuser, String httppasswd) {<br />
postMethod = new HttpPost(uri);<br />
postMethod.addHeader("Content-Type", "text/xml");<br />
postMethod.addHeader("charset", "UTF-8");<br />
// UPDATE THE VERSION NUMBER BEFORE RELEASE! &lt;3 Dan<br />
postMethod.addHeader("User-Agent", "wp-android/1.4.1");</p>
<p>httpParams = postMethod.getParams();<br />
HttpProtocolParams.setUseExpectContinue(httpParams, false);</p>
<p>// username &amp; password not needed<br />
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(<br />
httpuser, httppasswd);</p>
<p>// this gets connections working over https<br />
if (uri.getScheme() != null) {<br />
if (uri.getScheme().equals("https")) {<br />
if (uri.getPort() == -1)<br />
try {<br />
client = new ConnectionClient(creds, 443);<br />
} catch (KeyManagementException e) {<br />
client = new ConnectionClient(creds);<br />
} catch (NoSuchAlgorithmException e) {<br />
client = new ConnectionClient(creds);<br />
} catch (KeyStoreException e) {<br />
client = new ConnectionClient(creds);<br />
} catch (UnrecoverableKeyException e) {<br />
client = new ConnectionClient(creds);<br />
}<br />
else<br />
try {<br />
client = new ConnectionClient(creds, uri.getPort());<br />
} catch (KeyManagementException e) {<br />
client = new ConnectionClient(creds);<br />
} catch (NoSuchAlgorithmException e) {<br />
client = new ConnectionClient(creds);<br />
} catch (KeyStoreException e) {<br />
client = new ConnectionClient(creds);<br />
} catch (UnrecoverableKeyException e) {<br />
client = new ConnectionClient(creds);<br />
}<br />
} else {<br />
client = new ConnectionClient(creds);<br />
}<br />
} else {<br />
client = new ConnectionClient(creds);<br />
}</p>
<p>serializer = Xml.newSerializer();<br />
}</p>
<p>/**<br />
* Convenience constructor. Creates new instance based on server String<br />
* address<br />
*<br />
* @param XMLRPC<br />
*            server address<br />
*/<br />
public XMLRPCClient(String url, String httpuser, String httppasswd) {<br />
this(URI.create(url), httpuser, httppasswd);<br />
}</p>
<p>/**<br />
* Convenience XMLRPCClient constructor. Creates new instance based on<br />
* server URL<br />
*<br />
* @param XMLRPC<br />
*            server URL<br />
*/<br />
public XMLRPCClient(URL url, String httpuser, String httppasswd) {<br />
this(URI.create(url.toExternalForm()), httpuser, httppasswd);<br />
}</p>
<p>/**<br />
* Call method with optional parameters. This is general method. If you want<br />
* to call your method with 0-8 parameters, you can use more convenience<br />
* call methods<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param params<br />
*            parameters to pass to method (may be null if method has no<br />
*            parameters)<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method, Object[] params) throws XMLRPCException {<br />
return callXMLRPC(method, params);<br />
}</p>
<p>/**<br />
* Convenience method call with no parameters<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method) throws XMLRPCException {<br />
return callXMLRPC(method, null);<br />
}</p>
<p>/**<br />
* Convenience method call with one parameter<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param p0<br />
*            method's parameter<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method, Object p0) throws XMLRPCException {<br />
Object[] params = { p0, };<br />
return callXMLRPC(method, params);<br />
}</p>
<p>/**<br />
* Convenience method call with two parameters<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param p0<br />
*            method's 1st parameter<br />
* @param p1<br />
*            method's 2nd parameter<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method, Object p0, Object p1)<br />
throws XMLRPCException {<br />
Object[] params = { p0, p1, };<br />
return callXMLRPC(method, params);<br />
}</p>
<p>/**<br />
* Convenience method call with three parameters<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param p0<br />
*            method's 1st parameter<br />
* @param p1<br />
*            method's 2nd parameter<br />
* @param p2<br />
*            method's 3rd parameter<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method, Object p0, Object p1, Object p2)<br />
throws XMLRPCException {<br />
Object[] params = { p0, p1, p2, };<br />
return callXMLRPC(method, params);<br />
}</p>
<p>/**<br />
* Convenience method call with four parameters<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param p0<br />
*            method's 1st parameter<br />
* @param p1<br />
*            method's 2nd parameter<br />
* @param p2<br />
*            method's 3rd parameter<br />
* @param p3<br />
*            method's 4th parameter<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method, Object p0, Object p1, Object p2, Object p3)<br />
throws XMLRPCException {<br />
Object[] params = { p0, p1, p2, p3, };<br />
return callXMLRPC(method, params);<br />
}</p>
<p>/**<br />
* Convenience method call with five parameters<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param p0<br />
*            method's 1st parameter<br />
* @param p1<br />
*            method's 2nd parameter<br />
* @param p2<br />
*            method's 3rd parameter<br />
* @param p3<br />
*            method's 4th parameter<br />
* @param p4<br />
*            method's 5th parameter<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method, Object p0, Object p1, Object p2,<br />
Object p3, Object p4) throws XMLRPCException {<br />
Object[] params = { p0, p1, p2, p3, p4, };<br />
return callXMLRPC(method, params);<br />
}</p>
<p>/**<br />
* Convenience method call with six parameters<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param p0<br />
*            method's 1st parameter<br />
* @param p1<br />
*            method's 2nd parameter<br />
* @param p2<br />
*            method's 3rd parameter<br />
* @param p3<br />
*            method's 4th parameter<br />
* @param p4<br />
*            method's 5th parameter<br />
* @param p5<br />
*            method's 6th parameter<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method, Object p0, Object p1, Object p2,<br />
Object p3, Object p4, Object p5) throws XMLRPCException {<br />
Object[] params = { p0, p1, p2, p3, p4, p5, };<br />
return callXMLRPC(method, params);<br />
}</p>
<p>/**<br />
* Convenience method call with seven parameters<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param p0<br />
*            method's 1st parameter<br />
* @param p1<br />
*            method's 2nd parameter<br />
* @param p2<br />
*            method's 3rd parameter<br />
* @param p3<br />
*            method's 4th parameter<br />
* @param p4<br />
*            method's 5th parameter<br />
* @param p5<br />
*            method's 6th parameter<br />
* @param p6<br />
*            method's 7th parameter<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method, Object p0, Object p1, Object p2,<br />
Object p3, Object p4, Object p5, Object p6) throws XMLRPCException {<br />
Object[] params = { p0, p1, p2, p3, p4, p5, p6, };<br />
return callXMLRPC(method, params);<br />
}</p>
<p>/**<br />
* Convenience method call with eight parameters<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param p0<br />
*            method's 1st parameter<br />
* @param p1<br />
*            method's 2nd parameter<br />
* @param p2<br />
*            method's 3rd parameter<br />
* @param p3<br />
*            method's 4th parameter<br />
* @param p4<br />
*            method's 5th parameter<br />
* @param p5<br />
*            method's 6th parameter<br />
* @param p6<br />
*            method's 7th parameter<br />
* @param p7<br />
*            method's 8th parameter<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
public Object call(String method, Object p0, Object p1, Object p2,<br />
Object p3, Object p4, Object p5, Object p6, Object p7)<br />
throws XMLRPCException {<br />
Object[] params = { p0, p1, p2, p3, p4, p5, p6, p7, };<br />
return callXMLRPC(method, params);<br />
}</p>
<p>/**<br />
* Call method with optional parameters<br />
*<br />
* @param method<br />
*            name of method to call<br />
* @param params<br />
*            parameters to pass to method (may be null if method has no<br />
*            parameters)<br />
* @return deserialized method return value<br />
* @throws XMLRPCException<br />
*/<br />
@SuppressWarnings("unchecked")<br />
private Object callXMLRPC(String method, Object[] params)<br />
throws XMLRPCException {<br />
try {<br />
// prepare POST body<br />
File tempFile = null;<br />
if (method.equals("wp.uploadFile")) {<br />
String tempFilePath = Environment.getExternalStorageDirectory()<br />
+ File.separator + "wordpress" + File.separator + "wp-"<br />
+ System.currentTimeMillis() + ".xml";</p>
<p>File directory = new File(tempFilePath).getParentFile();<br />
if (!directory.exists() &amp;&amp; !directory.mkdirs()) {<br />
throw new XMLRPCException(<br />
"Path to file could not be created.");<br />
}</p>
<p>tempFile = new File(tempFilePath);<br />
FileWriter fileWriter = new FileWriter(tempFile);<br />
serializer.setOutput(fileWriter);</p>
<p>serializer.startDocument(null, null);<br />
serializer.startTag(null, TAG_METHOD_CALL);<br />
// set method name<br />
serializer.startTag(null, TAG_METHOD_NAME).text(method)<br />
.endTag(null, TAG_METHOD_NAME);<br />
if (params != null &amp;&amp; params.length != 0) {<br />
// set method params<br />
serializer.startTag(null, TAG_PARAMS);<br />
for (int i = 0; i &lt; params.length; i++) {<br />
serializer.startTag(null, TAG_PARAM).startTag(null,<br />
XMLRPCSerializer.TAG_VALUE);<br />
XMLRPCSerializer<br />
.serialize(serializer, params[i], false);<br />
serializer.endTag(null, XMLRPCSerializer.TAG_VALUE)<br />
.endTag(null, TAG_PARAM);<br />
}<br />
serializer.endTag(null, TAG_PARAMS);<br />
}<br />
serializer.endTag(null, TAG_METHOD_CALL);<br />
serializer.endDocument();</p>
<p>fileWriter.flush();<br />
fileWriter.close();<br />
FileEntity fEntity = new FileEntity(tempFile,<br />
"text/xml; charset="UTF-8"");<br />
fEntity.setContentType("text/xml");<br />
// fEntity.setChunked(true);<br />
postMethod.setEntity(fEntity);<br />
} else {<br />
StringWriter bodyWriter = new StringWriter();<br />
serializer.setOutput(bodyWriter);</p>
<p>serializer.startDocument(null, null);<br />
serializer.startTag(null, TAG_METHOD_CALL);<br />
// set method name<br />
serializer.startTag(null, TAG_METHOD_NAME).text(method)<br />
.endTag(null, TAG_METHOD_NAME);<br />
if (params != null &amp;&amp; params.length != 0) {<br />
// set method params<br />
serializer.startTag(null, TAG_PARAMS);<br />
for (int i = 0; i &lt; params.length; i++) {<br />
serializer.startTag(null, TAG_PARAM).startTag(null,<br />
XMLRPCSerializer.TAG_VALUE);<br />
if (method.equals("metaWeblog.editPost")<br />
|| method.equals("metaWeblog.newPost")) {<br />
XMLRPCSerializer.serialize(serializer, params[i],<br />
true);<br />
} else {<br />
XMLRPCSerializer.serialize(serializer, params[i],<br />
false);</p>
<p>}<br />
serializer.endTag(null, XMLRPCSerializer.TAG_VALUE)<br />
.endTag(null, TAG_PARAM);<br />
}<br />
serializer.endTag(null, TAG_PARAMS);<br />
}<br />
serializer.endTag(null, TAG_METHOD_CALL);<br />
serializer.endDocument();</p>
<p>HttpEntity entity = new StringEntity(bodyWriter.toString());<br />
// Log.i("WordPress", bodyWriter.toString());<br />
postMethod.setEntity(entity);<br />
}</p>
<p>// set timeout to 40 seconds, does it need to be set for both client<br />
// and method?<br />
client.getParams().setParameter(<br />
CoreConnectionPNames.CONNECTION_TIMEOUT, 40000);<br />
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,<br />
40000);<br />
postMethod.getParams().setParameter(<br />
CoreConnectionPNames.CONNECTION_TIMEOUT, 40000);<br />
postMethod.getParams().setParameter(<br />
CoreConnectionPNames.SO_TIMEOUT, 40000);</p>
<p>// execute HTTP POST request<br />
HttpResponse response = client.execute(postMethod);</p>
<p>Log.i("WordPress", "response = " + response.getStatusLine());<br />
// check status code<br />
int statusCode = response.getStatusLine().getStatusCode();</p>
<p>if ((method.equals("wp.uploadFile"))) { // get rid of the temp file<br />
tempFile.delete();<br />
}</p>
<p>if (statusCode != HttpStatus.SC_OK) {<br />
throw new XMLRPCException("HTTP status code: " + statusCode<br />
+ " was returned. "<br />
+ response.getStatusLine().getReasonPhrase());<br />
}</p>
<p>// setup pull parser<br />
XmlPullParser pullParser = XmlPullParserFactory.newInstance()<br />
.newPullParser();<br />
HttpEntity entity = response.getEntity();<br />
// change to pushbackinput stream 1/18/2010 to handle self installed<br />
// wp sites that insert the BOM<br />
PushbackInputStream is = new PushbackInputStream(<br />
entity.getContent());</p>
<p>// get rid of junk characters before xml response. 60 = '&lt;'. Added<br />
// stopper to prevent infinite loop<br />
int bomCheck = is.read();<br />
int stopper = 0;<br />
while (bomCheck != 60 &amp;&amp; stopper &lt; 20) {<br />
bomCheck = is.read();<br />
stopper++;<br />
}<br />
is.unread(bomCheck);</p>
<p>pullParser.setInput(is, "UTF-8");</p>
<p>// lets start pulling...<br />
pullParser.nextTag();<br />
pullParser.require(XmlPullParser.START_TAG, null,<br />
TAG_METHOD_RESPONSE);</p>
<p>pullParser.nextTag(); // either TAG_PARAMS (&lt;params&gt;) or TAG_FAULT<br />
// (&lt;fault&gt;)<br />
String tag = pullParser.getName();<br />
if (tag.equals(TAG_PARAMS)) {<br />
// normal response<br />
pullParser.nextTag(); // TAG_PARAM (&lt;param&gt;)<br />
pullParser.require(XmlPullParser.START_TAG, null, TAG_PARAM);<br />
pullParser.nextTag(); // TAG_VALUE (&lt;value&gt;)<br />
// no parser.require() here since its called in<br />
// XMLRPCSerializer.deserialize() below</p>
<p>// deserialize result<br />
Object obj = XMLRPCSerializer.deserialize(pullParser);<br />
entity.consumeContent();<br />
return obj;<br />
} else if (tag.equals(TAG_FAULT)) {<br />
// fault response<br />
pullParser.nextTag(); // TAG_VALUE (&lt;value&gt;)<br />
// no parser.require() here since its called in<br />
// XMLRPCSerializer.deserialize() below</p>
<p>// deserialize fault result<br />
Map&lt;String, Object&gt; map = (Map&lt;String, Object&gt;) XMLRPCSerializer<br />
.deserialize(pullParser);<br />
String faultString = (String) map.get(TAG_FAULT_STRING);<br />
int faultCode = (Integer) map.get(TAG_FAULT_CODE);<br />
entity.consumeContent();<br />
throw new XMLRPCFault(faultString, faultCode);<br />
} else {<br />
entity.consumeContent();<br />
throw new XMLRPCException("Bad tag &lt;" + tag<br />
+ "&gt; in XMLRPC response - neither &lt;params&gt; nor &lt;fault&gt;");<br />
}<br />
} catch (XMLRPCException e) {<br />
// catch &amp; propagate XMLRPCException/XMLRPCFault<br />
throw e;<br />
} catch (Exception e) {<br />
// wrap any other Exception(s) around XMLRPCException<br />
throw new XMLRPCException(e);<br />
}<br />
}<br />
}<br />
</code><br />
其他工具类的实现，比如错误，异常的实现类和Base64的编码和解码请参照：<a href="http://blog.zhourunsheng.com/wp-content/uploads/2011/07/android_rpc.zip">android_rpc</a></p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88%e4%b8%8b%ef%bc%89/">XML-RPC 之 Android实现（下）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88%e4%b8%8b%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XML-RPC 之 Android实现（上）</title>
		<link>http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88wordpress%e5%ae%98%e6%96%b9%e7%89%88%ef%bc%89/</link>
		<comments>http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88wordpress%e5%ae%98%e6%96%b9%e7%89%88%ef%bc%89/#comments</comments>
		<pubDate>Tue, 05 Jul 2011 09:44:03 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[移动开发]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[RPC]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=346</guid>
		<description><![CDATA[<p>xml-rpc的文档规范请参照博文《XML-RPC 规范》， 本文是其android版本的一个实现，代码摘自w [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88wordpress%e5%ae%98%e6%96%b9%e7%89%88%ef%bc%89/">XML-RPC 之 Android实现（上）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>xml-rpc的文档规范请参照博文《<a title="XML-RPC 规范" rel="bookmark" href="../?p=331">XML-RPC 规范</a>》， 本文是其android版本的一个实现，代码摘自wordpress的官方android发布版。</p>
<p>主要XML的封装和解封代码实现如下， 实现了将Java的数据类型封装成xml-rpc请求格式的xml数据和解析xml格式的返回数据来转换成java的数据类型：</p>
<pre>package org.xmlrpc.android;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.Map.Entry;</pre>
<p><span id="more-346"></span></p>
<pre> 
import org.wordpress.android.models.MediaFile;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

class XMLRPCSerializer {
 static final String TAG_NAME = "name";
 static final String TAG_MEMBER = "member";
 static final String TAG_VALUE = "value";
 static final String TAG_DATA = "data";

 static final String TYPE_INT = "int";
 static final String TYPE_I4 = "i4";
 static final String TYPE_I8 = "i8";
 static final String TYPE_DOUBLE = "double";
 static final String TYPE_BOOLEAN = "boolean";
 static final String TYPE_STRING = "string";
 static final String TYPE_DATE_TIME_ISO8601 = "dateTime.iso8601";
 static final String TYPE_BASE64 = "base64";
 static final String TYPE_ARRAY = "array";
 static final String TYPE_STRUCT = "struct";

 static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");

 /**
 * 序列化请求数据，封装成对应的XML格式.
 *
 * 请求示例：
 *
 * &lt;methodCall&gt;
 *     &lt;methodName&gt;examples.getStateName&lt;/methodName&gt;
 *       &lt;params&gt;
 *          &lt;param&gt;
 *             &lt;value&gt;&lt;i4&gt;41&lt;/i4&gt;&lt;/value&gt;
 *          &lt;/param&gt;
 *        &lt;/params&gt;
 *  &lt;/methodCall&gt;
 *
 * 结构体：
 *  &lt;struct&gt;
 *     &lt;member&gt;
 *         &lt;name&gt;lowerBound&lt;/name&gt;
 *         &lt;value&gt;&lt;i4&gt;18&lt;/i4&gt;&lt;/value&gt;
 *     &lt;/member&gt;
 *     &lt;member&gt;
 *         &lt;name&gt;upperBound&lt;/name&gt;
 *         &lt;value&gt;&lt;i4&gt;139&lt;/i4&gt;&lt;/value&gt;
 *     &lt;/member&gt;
 *  &lt;/struct&gt;
 *
 * 数组：
 *  &lt;array&gt;
 *     &lt;data&gt;
 *        &lt;value&gt;&lt;i4&gt;12&lt;/i4&gt;&lt;/value&gt;
 *        &lt;value&gt;&lt;string&gt;Egypt&lt;/string&gt;&lt;/value&gt;
 *        &lt;value&gt;&lt;boolean&gt;0&lt;/boolean&gt;&lt;/value&gt;
 *        &lt;value&gt;&lt;i4&gt;-31&lt;/i4&gt;&lt;/value&gt;
 *     &lt;/data&gt;
 *  &lt;/array&gt;
 * 
 * */
 static void serialize(XmlSerializer serializer, Object object,
 boolean convertToGMT) throws IOException {
 // check for scalar types:
 if (object instanceof Integer || object instanceof Short
 || object instanceof Byte) {
 // 基本类型： 整型
 serializer.startTag(null, TYPE_I4).text(object.toString()).endTag(null, TYPE_I4);
 } else if (object instanceof Long) {
 // 基本类型： 长整型
 serializer.startTag(null, TYPE_I8).text(object.toString()).endTag(null, TYPE_I8);
 } else if (object instanceof Double || object instanceof Float) {
 // 基本类型： 浮点型
 serializer.startTag(null, TYPE_DOUBLE).text(object.toString()).endTag(null, TYPE_DOUBLE);
 } else if (object instanceof Boolean) {
 // 基本类型： 布尔型
 Boolean bool = (Boolean) object;
 String boolStr = bool.booleanValue() ? "1" : "0";
 serializer.startTag(null, TYPE_BOOLEAN).text(boolStr).endTag(null, TYPE_BOOLEAN);
 } else if (object instanceof String) {
 // 基本类型： 字符串型
 serializer.startTag(null, TYPE_STRING).text(object.toString()).endTag(null, TYPE_STRING);
 } else if (object instanceof Date || object instanceof Calendar) {
 // 基本类型： 日期型
 Date date = (Date) object;
 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss");
 if (convertToGMT) {
 long pubDate = date.getTime();
 TimeZone tz = TimeZone.getDefault();
 long offset = tz.getOffset(pubDate);
 pubDate += offset * -1;
 date = new Date(pubDate);
 }
 String sDate = dateFormat.format(date);
 serializer.startTag(null, TYPE_DATE_TIME_ISO8601).text(sDate).endTag(null, TYPE_DATE_TIME_ISO8601);
 } else if (object instanceof byte[]) {
 // 基本类型： Base64编码型
 String value = new String(Base64Coder.encode((byte[]) object));
 serializer.startTag(null, TYPE_BASE64).text(value).endTag(null, TYPE_BASE64);
 } else if (object instanceof MediaFile) {
 // 基本类型： Base64编码型
 // convert media file binary to base64
 serializer.startTag(null, "base64");
 MediaFile videoFile = (MediaFile) object;
 InputStream inStream = new DataInputStream(new FileInputStream(videoFile.getFilePath()));
 byte[] buffer = new byte[3600];// you must use a 24bit multiple
 int length = -1;
 String chunk = null;
 // int ctr = 0;
 // Log.i("WordPress", "converting media file to base64");
 while ((length = inStream.read(buffer)) &gt; 0) {
 chunk = Base64.encodeBytes(buffer, 0, length);
 serializer.text(chunk);
 // ctr+=3600;
 // Log.i("WordPress", "chunk " + ctr);
 }
 // Log.i("WordPress", "conversion done!");
 inStream.close();
 serializer.endTag(null, "base64");
 } else if (object instanceof List&lt;?&gt;) {
 // 复合类型： 数组型
 serializer.startTag(null, TYPE_ARRAY).startTag(null, TAG_DATA);
 List&lt;Object&gt; list = (List&lt;Object&gt;) object;
 Iterator&lt;Object&gt; iter = list.iterator();
 while (iter.hasNext()) {
 Object o = iter.next();
 serializer.startTag(null, TAG_VALUE);
 serialize(serializer, o, convertToGMT);
 serializer.endTag(null, TAG_VALUE);
 }
 serializer.endTag(null, TAG_DATA).endTag(null, TYPE_ARRAY);
 } else if (object instanceof Object[]) {
 // 复合类型： 数组型
 serializer.startTag(null, TYPE_ARRAY).startTag(null, TAG_DATA);
 Object[] objects = (Object[]) object;
 for (int i = 0; i &lt; objects.length; i++) {
 Object o = objects[i];
 serializer.startTag(null, TAG_VALUE);
 serialize(serializer, o, convertToGMT);
 serializer.endTag(null, TAG_VALUE);
 }
 serializer.endTag(null, TAG_DATA).endTag(null, TYPE_ARRAY);
 } else if (object instanceof Map) {
 // 复合类型： 结构型
 serializer.startTag(null, TYPE_STRUCT);
 Map&lt;String, Object&gt; map = (Map&lt;String, Object&gt;) object;
 Iterator&lt;Entry&lt;String, Object&gt;&gt; iter = map.entrySet().iterator();
 while (iter.hasNext()) {
 Entry&lt;String, Object&gt; entry = iter.next();
 String key = entry.getKey();
 Object value = entry.getValue();

 serializer.startTag(null, TAG_MEMBER);
 serializer.startTag(null, TAG_NAME).text(key).endTag(null, TAG_NAME);
 serializer.startTag(null, TAG_VALUE);
 serialize(serializer, value, convertToGMT);
 serializer.endTag(null, TAG_VALUE);
 serializer.endTag(null, TAG_MEMBER);
 }
 serializer.endTag(null, TYPE_STRUCT);
 } else {
 throw new IOException("Cannot serialize " + object);
 }
 }

 /**
 * 反序列化服务器的返回数据，解封成Java的数据类型.
 *
 * 回复示例：
 *
 * &lt;methodResponse&gt;
 *    &lt;params&gt;
 *       &lt;param&gt;
 *         &lt;value&gt;&lt;string&gt;South Dakota&lt;/string&gt;&lt;/value&gt;
 *       &lt;/param&gt;
 *    &lt;/params&gt;
 * &lt;/methodResponse&gt;
 * */
 static Object deserialize(XmlPullParser parser)
 throws XmlPullParserException, IOException {
 parser.require(XmlPullParser.START_TAG, null, TAG_VALUE);

 parser.nextTag();
 String typeNodeName = parser.getName();

 Object obj;
 if (typeNodeName.equals(TYPE_INT) || typeNodeName.equals(TYPE_I4)) {
 String value = parser.nextText();
 obj = Integer.parseInt(value);
 } else if (typeNodeName.equals(TYPE_I8)) {
 String value = parser.nextText();
 obj = Long.parseLong(value);
 } else if (typeNodeName.equals(TYPE_DOUBLE)) {
 String value = parser.nextText();
 obj = Double.parseDouble(value);
 } else if (typeNodeName.equals(TYPE_BOOLEAN)) {
 String value = parser.nextText();
 obj = value.equals("1") ? Boolean.TRUE : Boolean.FALSE;
 } else if (typeNodeName.equals(TYPE_STRING)) {
 obj = parser.nextText();
 } else if (typeNodeName.equals(TYPE_DATE_TIME_ISO8601)) {
 String value = parser.nextText();
 try {
 obj = dateFormat.parseObject(value);
 } catch (ParseException e) {
 e.printStackTrace();
 obj = value;
 // throw new IOException("Cannot deserialize dateTime " + value);
 }
 } else if (typeNodeName.equals(TYPE_BASE64)) {
 String value = parser.nextText();
 BufferedReader reader = new BufferedReader(new StringReader(value));
 String line;
 StringBuffer sb = new StringBuffer();
 while ((line = reader.readLine()) != null) {
 sb.append(line);
 }
 obj = Base64Coder.decode(sb.toString());
 } else if (typeNodeName.equals(TYPE_ARRAY)) {
 parser.nextTag(); // TAG_DATA (&lt;data&gt;)
 parser.require(XmlPullParser.START_TAG, null, TAG_DATA);

 parser.nextTag();
 List&lt;Object&gt; list = new ArrayList&lt;Object&gt;();
 while (parser.getName().equals(TAG_VALUE)) {
 list.add(deserialize(parser));
 parser.nextTag();
 }
 parser.require(XmlPullParser.END_TAG, null, TAG_DATA);
 parser.nextTag(); // TAG_ARRAY (&lt;/array&gt;)
 parser.require(XmlPullParser.END_TAG, null, TYPE_ARRAY);
 obj = list.toArray();
 } else if (typeNodeName.equals(TYPE_STRUCT)) {
 parser.nextTag();
 Map&lt;String, Object&gt; map = new HashMap&lt;String, Object&gt;();
 while (parser.getName().equals(TAG_MEMBER)) {
 String memberName = null;
 Object memberValue = null;
 while (true) {
 parser.nextTag();
 String name = parser.getName();
 if (name.equals(TAG_NAME)) {
 memberName = parser.nextText();
 } else if (name.equals(TAG_VALUE)) {
 memberValue = deserialize(parser);
 } else {
 break;
 }
 }
 if (memberName != null &amp;&amp; memberValue != null) {
 map.put(memberName, memberValue);
 }
 parser.require(XmlPullParser.END_TAG, null, TAG_MEMBER);
 parser.nextTag();
 }
 parser.require(XmlPullParser.END_TAG, null, TYPE_STRUCT);
 obj = map;
 } else {
 throw new IOException("Cannot deserialize " + parser.getName());
 }
 parser.nextTag(); // TAG_VALUE (&lt;/value&gt;)
 parser.require(XmlPullParser.END_TAG, null, TAG_VALUE);
 return obj;
 }
}</pre>
<p>其他工具类的实现，比如错误，异常的实现类和Base64的编码和解码请参照：<a href="http://blog.zhourunsheng.com/wp-content/uploads/2011/07/android_rpc.zip">android_rpc</a></p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88wordpress%e5%ae%98%e6%96%b9%e7%89%88%ef%bc%89/">XML-RPC 之 Android实现（上）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2011/07/xml-rpc-%e4%b9%8b-android%e5%ae%9e%e7%8e%b0%ef%bc%88wordpress%e5%ae%98%e6%96%b9%e7%89%88%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XML-RPC 规范</title>
		<link>http://blog.zhourunsheng.com/2011/07/xml-rpc-%e8%a7%84%e8%8c%83/</link>
		<comments>http://blog.zhourunsheng.com/2011/07/xml-rpc-%e8%a7%84%e8%8c%83/#comments</comments>
		<pubDate>Tue, 05 Jul 2011 08:35:28 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[移动开发]]></category>
		<category><![CDATA[RPC]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=331</guid>
		<description><![CDATA[<p>Overview(简介) XML-RPC is a Remote Procedure Calling prot [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2011/07/xml-rpc-%e8%a7%84%e8%8c%83/">XML-RPC 规范</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p><strong>Overview(简介)</strong></p>
<p>XML-RPC is a Remote Procedure Calling protocol that works over the Internet.</p>
<p>An XML-RPC message is an HTTP-POST request. The body of the request is  in XML. A procedure executes on the server and the value it returns is  also formatted in XML.</p>
<p>Procedure parameters can be scalars, numbers, strings, dates, etc.; and can also be complex record and list structures.</p>
<p>工作机制：</p>
<p><a href="http://blog.zhourunsheng.com/wp-content/uploads/2011/07/xmlrpc.jpg"><img class="alignnone size-full wp-image-335" title="xmlrpc" src="http://blog.zhourunsheng.com/wp-content/uploads/2011/07/xmlrpc.jpg" alt="" width="527" height="270" /></a></p>
<p><strong>Request example（请求示例）</strong></p>
<pre>POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (WinNT)
Host: betty.userland.com
Content-Type: text/xml
Content-length: 181

&lt;?xml version="1.0"?&gt;
&lt;methodCall&gt;
   &lt;methodName&gt;examples.getStateName&lt;/methodName&gt;
   &lt;params&gt;
      &lt;param&gt;
         &lt;value&gt;&lt;i4&gt;41&lt;/i4&gt;&lt;/value&gt;
      &lt;/param&gt;
   &lt;/params&gt;
&lt;/methodCall&gt;</pre>
<p><strong>Header requirements（请求中需设置header的必要信息）</strong></p>
<p>The format of the URI in the first line of the header is not specified.  For example, it could be empty, a single slash, if the server is only  handling XML-RPC calls. However, if the server is handling a mix of  incoming HTTP requests, we allow the URI to help route the request to  the code that handles XML-RPC requests. (In the example, the URI is  /RPC2, telling the server to route the request to the "RPC2" responder.)</p>
<ol>
<li>A User-Agent and Host must be specified.</li>
<li>The Content-Type is text/xml.</li>
<li>The Content-Length must be specified and must be correct.</li>
</ol>
<p><strong>Payload format（请求的数据格式）</strong></p>
<p>The payload is in XML, a single &lt;methodCall&gt; structure.</p>
<p>The &lt;methodCall&gt; must contain a &lt;methodName&gt; sub-item, a  string, containing the name of the method to be called. The string may  only contain identifier characters, upper and lower-case A-Z, the  numeric characters, 0-9, underscore, dot, colon and slash. It's entirely  up to the server to decide how to interpret the characters in a  methodName.</p>
<p>For example, the methodName could be the name of a file containing a  script that executes on an incoming request. It could be the name of a  cell in a database table. Or it could be a path to a file contained  within a hierarchy of folders and files.</p>
<p>If the procedure call has parameters, the &lt;methodCall&gt; must  contain a &lt;params&gt; sub-item. The &lt;params&gt; sub-item can  contain any number of &lt;param&gt;s, each of which has a &lt;value&gt;.</p>
<p><strong>Scalar &lt;value&gt;s （基本数据类型）</strong></p>
<p>&lt;value&gt;s can be scalars, type is indicated by nesting the value inside one of the tags listed in this table:</p>
<table border="0" cellspacing="3">
<tbody>
<tr>
<td valign="top"><strong>Tag</strong></td>
<td width="35%" valign="top"><strong>Type</strong></td>
<td valign="top"><strong>Example</strong></td>
</tr>
<tr>
<td valign="top">&lt;i4&gt; or &lt;int&gt;</td>
<td width="35%" valign="top">four-byte signed integer</td>
<td valign="top">-12</td>
</tr>
<tr>
<td valign="top">&lt;boolean&gt;</td>
<td valign="top">0 (false) or 1 (true)</td>
<td valign="top">1</td>
</tr>
<tr>
<td valign="top">&lt;string&gt;</td>
<td valign="top">string</td>
<td valign="top">hello world</td>
</tr>
<tr>
<td valign="top">&lt;double&gt;</td>
<td valign="top">double-precision signed floating point number</td>
<td valign="top">-12.214</td>
</tr>
<tr>
<td valign="top">&lt;dateTime.iso8601&gt;</td>
<td valign="top">date/time</td>
<td valign="top">19980717T14:08:55</td>
</tr>
<tr>
<td valign="top">&lt;base64&gt;</td>
<td valign="top">base64-encoded binary</td>
<td valign="top">eW91IGNhbid0IHJlYWQgdGhpcyE=</td>
</tr>
</tbody>
</table>
<p>If no type is indicated, the type is string.</p>
<p><strong>&lt;struct&gt;s （结构体类型）</strong></p>
<p>A value can also be of type &lt;struct&gt;.</p>
<p>A &lt;struct&gt; contains &lt;member&gt;s and each &lt;member&gt; contains a &lt;name&gt; and a &lt;value&gt;.</p>
<p>Here's an example of a two-element &lt;struct&gt;:</p>
<pre>&lt;struct&gt;
   &lt;member&gt;
      &lt;name&gt;lowerBound&lt;/name&gt;
      &lt;value&gt;&lt;i4&gt;18&lt;/i4&gt;&lt;/value&gt;
   &lt;/member&gt;
   &lt;member&gt;
      &lt;name&gt;upperBound&lt;/name&gt;
      &lt;value&gt;&lt;i4&gt;139&lt;/i4&gt;&lt;/value&gt;
   &lt;/member&gt;
&lt;/struct&gt;</pre>
<p>&lt;struct&gt;s can be recursive, any &lt;value&gt; may contain a  &lt;struct&gt; or any other type, including an &lt;array&gt;, described  below.</p>
<p><strong>&lt;array&gt;s （数组类型）</strong></p>
<p>A value can also be of type &lt;array&gt;.</p>
<p>An &lt;array&gt; contains a single &lt;data&gt; element, which can contain any number of &lt;value&gt;s.</p>
<p>Here's an example of a four-element array:</p>
<pre>&lt;array&gt;
   &lt;data&gt;
      &lt;value&gt;&lt;i4&gt;12&lt;/i4&gt;&lt;/value&gt;
      &lt;value&gt;&lt;string&gt;Egypt&lt;/string&gt;&lt;/value&gt;
      &lt;value&gt;&lt;boolean&gt;0&lt;/boolean&gt;&lt;/value&gt;
      &lt;value&gt;&lt;i4&gt;-31&lt;/i4&gt;&lt;/value&gt;
   &lt;/data&gt;
 &lt;/array&gt;</pre>
<p>&lt;array&gt; elements do not have names.</p>
<p>You can mix types as the example above illustrates.</p>
<p>&lt;arrays&gt;s can be recursive, any value may contain an &lt;array&gt;  or any other type, including a &lt;struct&gt;, described above.</p>
<p><strong>Response example （回复示例）</strong></p>
<pre>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

&lt;?xml version="1.0"?&gt;
&lt;methodResponse&gt;
   &lt;params&gt;
      &lt;param&gt;
         &lt;value&gt;&lt;string&gt;South Dakota&lt;/string&gt;&lt;/value&gt;
      &lt;/param&gt;
   &lt;/params&gt;
 &lt;/methodResponse&gt;</pre>
<p><strong>Response format （回复的数据格式）</strong></p>
<p>Unless there's a lower-level error, always return 200 OK.</p>
<p>The Content-Type is text/xml. Content-Length must be present and correct.</p>
<p>The body of the response is a single XML structure, a  &lt;methodResponse&gt;, which can contain a single &lt;params&gt; which  contains a single &lt;param&gt; which contains a single &lt;value&gt;.</p>
<p>The &lt;methodResponse&gt; could also contain a  &lt;fault&gt; which contains a &lt;value&gt; which is a &lt;struct&gt;  containing two elements, one named &lt;faultCode&gt;, an &lt;int&gt; and  one named &lt;faultString&gt;, a &lt;string&gt;.</p>
<p>A &lt;methodResponse&gt; can not contain both a &lt;fault&gt; and a &lt;params&gt;.</p>
<p><strong>Fault example （请求出错时的回复示例）</strong></p>
<pre>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

&lt;?xml version="1.0"?&gt;
&lt;methodResponse&gt;
   &lt;fault&gt;
      &lt;value&gt;
         &lt;struct&gt;
            &lt;member&gt;
               &lt;name&gt;faultCode&lt;/name&gt;
               &lt;value&gt;&lt;int&gt;4&lt;/int&gt;&lt;/value&gt;
            &lt;/member&gt;
            &lt;member&gt;
               &lt;name&gt;faultString&lt;/name&gt;
               &lt;value&gt;&lt;string&gt;Too many parameters.&lt;/string&gt;&lt;/value&gt;
            &lt;/member&gt;
         &lt;/struct&gt;
       &lt;/value&gt;
   &lt;/fault&gt;
&lt;/methodResponse&gt;</pre>
<hr />
<p>官方spec: <a href="http://www.xmlrpc.com/spec">http://www.xmlrpc.com/spec</a></p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2011/07/xml-rpc-%e8%a7%84%e8%8c%83/">XML-RPC 规范</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2011/07/xml-rpc-%e8%a7%84%e8%8c%83/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
