现在的位置: 首页 > 移动开发> 正文
XML-RPC 之 Android实现(上)
2011年07月05日 移动开发 暂无评论 ⁄ 被围观 7,386+

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

给我留言

留言无头像?


×
腾讯微博