gpt4 book ai didi

android - 未知根元素的改造和 SimpleXML?

转载 作者:太空宇宙 更新时间:2023-11-03 11:05:47 25 4
gpt4 key购买 nike

我们目前正在为 XML API 设置 Retrofit - 遗憾的是,每个请求都可能返回包含两个不同根元素之一的响应

通常,每个响应看起来像这样(当然,<response> 标签中包含的实际元素因每个请求而异):

<?xml version="1.0" encoding="UTF-8"?>
<response>
<SomeInfo>Some Info</SomeInfo>
<MoreInfo>More Info</MoreInfo>
</response>

每个错误看起来像这样(这里的结构对于每个响应都是相同的):

<?xml version="1.0" encoding="UTF-8"?>
<error>
<code>125002</code>
<message></message>
</error>

现在,到目前为止,我们发现以某种通用的方式完成这项工作的唯一方法如下:

public interface Api {

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

@GET("/api/pinStatus")
Observable<ResponseBody> requestPinStatus();
}

public class RestClient {

public RestClient() {
// ...
mApiService = retrofit.create(Api.class);
}

public Observable<PinStatusResponse> requestPinStatus() {
return mApiService.requestPinStatus()
.flatMap(foo(PinStatusResponse.class, PinStatusResponseData.class));
}

public Observable<SessionTokenResponse> requestSessionToken() {
return mApiService.requestSessionToken()
.flatMap(foo(SessionTokenResponse.class, SessionTokenResponseData.class));
}

private final <O extends MyResponse, I> Func1<ResponseBody, Observable<T>> foo(final Class<O> outerCls, final Class<I> innerCls) {
return new Func1<ResponseBody, Observable<O>>() {
@Override
public Observable<O> 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((O) outerCls.getConstructor(MyError.class, innerCls).newInstance(myError, null));
} else if (TextUtils.equals(rootTag, "response")) {
final I data = serializer.read(innerCls, xmlString);
return Observable.just((T) outerCls.getConstructor(MyError.class, innerCls).newInstance(null, data));
}
} catch (XmlPullParserException e) {
return Observable.error(e);
} catch (IOException e) {
return Observable.error(e);
} catch (Exception e) {
return Observable.error(e);
}
return Observable.error(new Exception("Should not be reached..."));
}
};
}
​}

Response 类看起来像这样:

public abstract class MyResponse<T> {
public final MyError error;
public final T data;

protected MyResponse(MyError error, T data) {
this.error = error;
this.data = data;
}
}

和:

public final class PinStatusResponse extends MyResponse<PinStatusResponseData> {
public PinStatusResponse(MyError error, PinStatusResponseData data) {
super(error, data);
}
}

所有*Data类直接对应于(非错误)XML 响应。

现在,我的问题是:真的没有更简单的方法来解决这个问题吗?(如果是这样,这是否表明 API 设计不当?)。

最佳答案

这就是 @ElementUnion 注释的用途。您可能可以使用纯 Retrofit+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;
}

* 'ValidResponse' 和 'ErrorReponse' 的具体结构必须根据您拥有的真实 XML 结构进行更改。您可能还希望考虑在他们的 @Root 中添加 'strict=false'

至于你的“Api”接口(interface),它必须看起来像这样(注意我在 Retrofit 的 Call 类的用法中漏掉了):

public interface Api {

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

@GET("/api/pinStatus")
Call<ResponseBody> 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) {
// ...
}
});

有关 ElementUnion 和 Simple-XML 注释的更多信息,请参阅 this guide .

关于android - 未知根元素的改造和 SimpleXML?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34046908/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com