Android 为未知根元素改型和SimpleXML?

Android 为未知根元素改型和SimpleXML?,android,xml,retrofit,simple-framework,Android,Xml,Retrofit,Simple Framework,我们目前正在为一个XML API进行改造,不幸的是,每个请求都会返回一个带有两个不同根元素之一的响应 通常,每个响应都是这样的(当然,标记中包含的实际元素随每个请求的不同而不同): 到目前为止,我们找到的以某种通用方式完成这项工作的唯一方法是: 公共接口Api{ @获取(“/api/sessionToken”) 可观察请求SessionToken(); @获取(“/api/pinStatus”) 可观察的状态(); } 公共类RestClient{ 公共RestClient(){ // ...

我们目前正在为一个XML API进行改造,不幸的是,每个请求都会返回一个带有两个不同根元素之一的响应

通常,每个响应都是这样的(当然,
标记中包含的实际元素随每个请求的不同而不同):

到目前为止,我们找到的以某种通用方式完成这项工作的唯一方法是:

公共接口Api{
@获取(“/api/sessionToken”)
可观察请求SessionToken();
@获取(“/api/pinStatus”)
可观察的状态();
}
公共类RestClient{
公共RestClient(){
// ...
mApiService=reformation.create(Api.class);
}
公共可观察请求状态(){
返回mApiService.requestPinStatus()
.flatMap(foo(PinStatusResponse.class,PinStatusResponseData.class));
}
公共可观察请求SessionToken(){
返回mApiService.requestSessionToken()
.flatMap(foo(SessionTokenResponse.class,SessionTokenResponseData.class));
}
专用最终功能1 foo(最终类外部循环,最终类内部循环){
返回新的Func1(){
@凌驾
公共可观察呼叫(应答器应答器应答器){
试一试{
最后一个字符串xmlString=responseBody.String();
final XmlPullParser parser=Xml.newPullParser();
setFeature(XmlPullParser.FEATURE_进程_名称空间,false);
setInput(新的ByteArrayInputStream(xmlString.getBytes(Charset.forName(“UTF-8”)),null);
parser.nextTag();
最后一个字符串rootTag=parser.getName();
final Serializer Serializer=new Persister();
if(TextUtils.equals(rootTag,“error”)){
final MyError MyError=serializer.read(MyError.class,xmlString);
返回Observable.just((O)outerCls.getConstructor(MyError.class,innerCls.newInstance(MyError,null));
}else if(TextUtils.equals(rootTag,“response”)){
final I data=serializer.read(innerCls,xmlString);
返回Observable.just((T)outerCls.getConstructor(MyError.class,innerCls.newInstance(null,data));
}
}catch(XMLPullParseRexE){
返回可观测误差(e);
}捕获(IOE异常){
返回可观测误差(e);
}捕获(例外e){
返回可观测误差(e);
}
返回可观察的错误(新异常(“不应到达…”);
}
};
}
​}
其中响应类如下所示:

公共抽象类MyResponse{
公共最终MyError错误;
公开最终数据;
受保护的MyResponse(MyError错误,T数据){
this.error=错误;
这个数据=数据;
}
}
以及:

公共最终类PinStatusResponse扩展了MyResponse{
公共PinStatusResponse(MyError错误,PinStatusResponseData数据){
超级(错误、数据);
}
}
所有的
*数据
类直接对应于(无错误)XML响应


现在,我的问题是:真的没有更简单的方法来解决这个问题吗?(如果是的话,这是一个糟糕的API设计的标志吗?

这就是
@ElementUnion
注释的目的。您可能可以使用纯改型+SimpleXML API,通过使用这样的注释对象来解决这个问题:

@Root
public class ResponseBody {

    public interface IApiResponse {
    }

    @Root
    public static class ValidResponse implements IApiResponse {
        @Element(name="SomeInfo") String someInfo;
        @Element(name="MoreInfo") String moreInfo;
    }

    @Root
    public static class ErrorResponse implements IApiResponse {
        @Element(name="code") int code;
        @Element(name="message") String message;
    }

    @ElementUnion({
        @Element(name="response", type=ValidResponse.class),
        @Element(name="error", type=ErrorResponse.class)
    })
    IApiResponse apiResponse;
}

>“有效响应”和“错误响应”的具体结构必须根据实际的XML结构进行更改。您可能还希望考虑在<代码> @根 < < /P>中添加<代码>“严格= false”/代码>。 至于您的“Api”接口,则必须如下所示(请注意,我已经介绍了改型的调用类的用法):

公共接口Api{
@获取(“/api/sessionToken”)
调用requestSessionToken();
@获取(“/api/pinStatus”)
调用requestPinStatus();
}
最后,调用本身(例如requestPinStatus())应根据以下框架实现进行计算:

Call<ResponseBody> result = mApiService.requestPinStatus();
result.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
        // ...

        if (response.body().apiResponse instanceof ValidResponse) {
            // ...
        } else if (response.body().apiResponse instanceof ErrorResponse) {
            // ...
        }
    }

    @Override
    public void onFailure(Throwable t) {
        // ...
    }
});
callresult=mApiService.requestPinStatus();
result.enqueue(新回调(){
@凌驾
公共响应(响应、改装){
// ...
if(response.body().apiResponse instanceof ValidResponse){
// ...
}else if(response.body().apirresponse instanceof ErrorResponse){
// ...
}
}
@凌驾
失效时的公共无效(可丢弃的t){
// ...
}
});

有关
ElementUnion
和简单XML注释的更多信息,请参阅。

好的,谢谢-我会尝试一下,然后在这里报告!
@Root
public class ResponseBody {

    public interface IApiResponse {
    }

    @Root
    public static class ValidResponse implements IApiResponse {
        @Element(name="SomeInfo") String someInfo;
        @Element(name="MoreInfo") String moreInfo;
    }

    @Root
    public static class ErrorResponse implements IApiResponse {
        @Element(name="code") int code;
        @Element(name="message") String message;
    }

    @ElementUnion({
        @Element(name="response", type=ValidResponse.class),
        @Element(name="error", type=ErrorResponse.class)
    })
    IApiResponse apiResponse;
}
public interface Api {

    @GET("/api/sessionToken")
    Call<ResponseBody> requestSessionToken();

    @GET("/api/pinStatus")
    Call<ResponseBody> requestPinStatus();
}
Call<ResponseBody> result = mApiService.requestPinStatus();
result.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
        // ...

        if (response.body().apiResponse instanceof ValidResponse) {
            // ...
        } else if (response.body().apiResponse instanceof ErrorResponse) {
            // ...
        }
    }

    @Override
    public void onFailure(Throwable t) {
        // ...
    }
});