SimpleXML 和 Retrofit:仅包含根元素的响应模型
SimpleXML and Retrofit: model for response with only root element
我们正在使用 XML API 开发一个 Android 项目,使用 RxJava
、Retrofit
和 SimpleXML
来处理请求和回应。响应的根可以在两种类型之间变化:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<Element1>Integer</Element1>
<Element2>Integer</Element2>
...
</response>
或
<?xml version="1.0" encoding="UTF-8"?>
<error>
<Element1>String</Element1>
<Element2>Integer</Element2>
</error>
因此我们使用 XMLPullParse 来解析对不同模型及其伴随元素的不同类型响应,效果很好。
MyResponse:超级 class,它结合了可能的 errors
和 valid
回复:
public abstract class MyResponse<T> {
public final MyError error;
public final T data;
protected MyResponse(MyError mError, T data) {
this.error = mError;
this.data = data;
}
public final boolean isError() {
return error != null;
}
@Override
public String toString() {
return "MyResponse{" +
"error=" + error +
", data=" + data +
'}';
}
public T getData() {
return data;
}
}
SessionTokenResponse:扩展 MyResponse
的 response
class 示例
public class SessionTokenResponse extends MyResponse<SessionTokenResponseData>{
public SessionTokenResponse(MyError mError, SessionTokenResponseData response) {
super(mError, response);
}
}
SessionTokenResponseData:一个例子class展示了我们如何构建模型
@Root(name = "data")
public class SessionTokenResponseData {
@Element(name = "Session")
private String sessionInfo;
@Element(name = "Token")
private String tokenInfo;
public String getSessionInfo() {
return sessionInfo;
}
....
}
RestClient - foo():我们 RestClient class 中的一种方法,用于解析不同类型的响应。如果成功,则响应将 <response>
作为根元素,否则根元素的类型为 <error>
private final <T extends MyResponse, I> Func1<ResponseBody, Observable<T>> foo(final Class<T> cls, final Class<I> innerCls) {
return new Func1<ResponseBody, Observable<T>>() {
@Override
public Observable<T> call(ResponseBody responseBody) {
try {
final String xmlString = responseBody.string();
final XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(new ByteArrayInputStream(xmlString.getBytes(Charset.forName("UTF-8"))), null);
parser.nextTag();
final String rootTag = parser.getName();
final Serializer serializer = new Persister();
if (TextUtils.equals(rootTag, "error")) {
final MyError myError = serializer.read(MyError.class, xmlString);
return Observable.just((T) cls.getConstructor(MyError.class, innerCls).newInstance(myError, null));
} else if (TextUtils.equals(rootTag, "response")) {
final I data = serializer.read(innerCls, xmlString);
return Observable.just((T) cls.getConstructor(HuiError.class, innerCls).newInstance(null, data));
}
但是我们遇到了一种响应类型的问题,它看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<response>
OK
</response>
我们的问题是:如果没有元素,我们如何为这种响应建立模型?我们仍然需要能够区分具有 <response>
根的其他响应。
灵机一动,我们自己找到了答案。
响应将扩展超级 class,并且不会像我的示例 class SessionTokenResponseData 那样包含任何其他模型 class,但仅包含一个字符串:
public class LoginResponse extends MyResponse<String>{
public LoginResponse(MyError mError, String response) {
super(mError, response);
}
}
因此我们不需要在 RestClient class 方法中修改我们的手动解析,它工作正常。
我们正在使用 XML API 开发一个 Android 项目,使用 RxJava
、Retrofit
和 SimpleXML
来处理请求和回应。响应的根可以在两种类型之间变化:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<Element1>Integer</Element1>
<Element2>Integer</Element2>
...
</response>
或
<?xml version="1.0" encoding="UTF-8"?>
<error>
<Element1>String</Element1>
<Element2>Integer</Element2>
</error>
因此我们使用 XMLPullParse 来解析对不同模型及其伴随元素的不同类型响应,效果很好。
MyResponse:超级 class,它结合了可能的 errors
和 valid
回复:
public abstract class MyResponse<T> {
public final MyError error;
public final T data;
protected MyResponse(MyError mError, T data) {
this.error = mError;
this.data = data;
}
public final boolean isError() {
return error != null;
}
@Override
public String toString() {
return "MyResponse{" +
"error=" + error +
", data=" + data +
'}';
}
public T getData() {
return data;
}
}
SessionTokenResponse:扩展 MyResponse
的response
class 示例
public class SessionTokenResponse extends MyResponse<SessionTokenResponseData>{
public SessionTokenResponse(MyError mError, SessionTokenResponseData response) {
super(mError, response);
}
}
SessionTokenResponseData:一个例子class展示了我们如何构建模型
@Root(name = "data")
public class SessionTokenResponseData {
@Element(name = "Session")
private String sessionInfo;
@Element(name = "Token")
private String tokenInfo;
public String getSessionInfo() {
return sessionInfo;
}
....
}
RestClient - foo():我们 RestClient class 中的一种方法,用于解析不同类型的响应。如果成功,则响应将 <response>
作为根元素,否则根元素的类型为 <error>
private final <T extends MyResponse, I> Func1<ResponseBody, Observable<T>> foo(final Class<T> cls, final Class<I> innerCls) {
return new Func1<ResponseBody, Observable<T>>() {
@Override
public Observable<T> call(ResponseBody responseBody) {
try {
final String xmlString = responseBody.string();
final XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(new ByteArrayInputStream(xmlString.getBytes(Charset.forName("UTF-8"))), null);
parser.nextTag();
final String rootTag = parser.getName();
final Serializer serializer = new Persister();
if (TextUtils.equals(rootTag, "error")) {
final MyError myError = serializer.read(MyError.class, xmlString);
return Observable.just((T) cls.getConstructor(MyError.class, innerCls).newInstance(myError, null));
} else if (TextUtils.equals(rootTag, "response")) {
final I data = serializer.read(innerCls, xmlString);
return Observable.just((T) cls.getConstructor(HuiError.class, innerCls).newInstance(null, data));
}
但是我们遇到了一种响应类型的问题,它看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<response>
OK
</response>
我们的问题是:如果没有元素,我们如何为这种响应建立模型?我们仍然需要能够区分具有 <response>
根的其他响应。
灵机一动,我们自己找到了答案。 响应将扩展超级 class,并且不会像我的示例 class SessionTokenResponseData 那样包含任何其他模型 class,但仅包含一个字符串:
public class LoginResponse extends MyResponse<String>{
public LoginResponse(MyError mError, String response) {
super(mError, response);
}
}
因此我们不需要在 RestClient class 方法中修改我们的手动解析,它工作正常。