SimpleXML 和 Retrofit:仅包含根元素的响应模型

SimpleXML and Retrofit: model for response with only root element

我们正在使用 XML API 开发一个 Android 项目,使用 RxJavaRetrofitSimpleXML 来处理请求和回应。响应的根可以在两种类型之间变化:

<?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,它结合了可能的 errorsvalid 回复:

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 方法中修改我们的手动解析,它工作正常。