xml-rpc的文档规范请参照博文《XML-RPC 规范》, 本文是其android版本的一个实现,代码摘自wordpress的官方android发布版。
主要XML的封装和解封代码实现如下, 实现了将Java的数据类型封装成xml-rpc请求格式的xml数据和解析xml格式的返回数据来转换成java的数据类型:
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;
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格式.
*
* 请求示例:
*
* <methodCall>
* <methodName>examples.getStateName</methodName>
* <params>
* <param>
* <value><i4>41</i4></value>
* </param>
* </params>
* </methodCall>
*
* 结构体:
* <struct>
* <member>
* <name>lowerBound</name>
* <value><i4>18</i4></value>
* </member>
* <member>
* <name>upperBound</name>
* <value><i4>139</i4></value>
* </member>
* </struct>
*
* 数组:
* <array>
* <data>
* <value><i4>12</i4></value>
* <value><string>Egypt</string></value>
* <value><boolean>0</boolean></value>
* <value><i4>-31</i4></value>
* </data>
* </array>
*
* */
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)) > 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<?>) {
// 复合类型: 数组型
serializer.startTag(null, TYPE_ARRAY).startTag(null, TAG_DATA);
List<Object> list = (List<Object>) object;
Iterator<Object> 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 < 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<String, Object> map = (Map<String, Object>) object;
Iterator<Entry<String, Object>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Entry<String, Object> 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的数据类型.
*
* 回复示例:
*
* <methodResponse>
* <params>
* <param>
* <value><string>South Dakota</string></value>
* </param>
* </params>
* </methodResponse>
* */
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 (<data>)
parser.require(XmlPullParser.START_TAG, null, TAG_DATA);
parser.nextTag();
List<Object> list = new ArrayList<Object>();
while (parser.getName().equals(TAG_VALUE)) {
list.add(deserialize(parser));
parser.nextTag();
}
parser.require(XmlPullParser.END_TAG, null, TAG_DATA);
parser.nextTag(); // TAG_ARRAY (</array>)
parser.require(XmlPullParser.END_TAG, null, TYPE_ARRAY);
obj = list.toArray();
} else if (typeNodeName.equals(TYPE_STRUCT)) {
parser.nextTag();
Map<String, Object> map = new HashMap<String, Object>();
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 && 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 (</value>)
parser.require(XmlPullParser.END_TAG, null, TAG_VALUE);
return obj;
}
}
其他工具类的实现,比如错误,异常的实现类和Base64的编码和解码请参照:android_rpc




