如何在Retrofit+SimpleXmlConverter中解析不同结构的XML响应?
这个问题我之前也碰到过,API返回不同根节点的XML确实会让SimpleXmlConverter直接抛出结构不匹配的异常,给你两种实用的解决方案:
方案一:创建通用包装模型类,包含成功和错误响应
这种方式最直观,我们定义一个能同时容纳Success和Error节点的通用模型,关闭严格解析模式来兼容不同的根节点:
import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; @Root(name = "Response", strict = false) public class GeneralResponse { // 标记为非必填,因为只会返回其中一个节点 @Element(name = "Success", required = false) private SuccessModel success; @Element(name = "Error", required = false) private ErrorModel error; // 判断是否为成功响应 public boolean isSuccess() { return success != null; } // Getter方法 public SuccessModel getSuccess() { return success; } public ErrorModel getError() { return error; } // 内部类定义成功响应模型 @Root(name = "Success") public static class SuccessModel { @Element private String id; public String getId() { return id; } } // 内部类定义错误响应模型 @Root(name = "Error") public static class ErrorModel { @Element private String message; public String getMessage() { return message; } } }
使用时,Retrofit接口返回Call<GeneralResponse>,在回调里判断响应类型即可:
call.enqueue(new Callback<GeneralResponse>() { @Override public void onResponse(Call<GeneralResponse> call, Response<GeneralResponse> response) { if (response.isSuccessful()) { GeneralResponse resp = response.body(); if (resp.isSuccess()) { // 处理成功逻辑,获取id String id = resp.getSuccess().getId(); } else { // 处理错误逻辑,展示错误信息 String errorMsg = resp.getError().getMessage(); } } else { // 处理HTTP错误(如404、500等),可解析errorBody获取详细信息 try { String errorXml = response.errorBody().string(); // 用同样的GeneralResponse解析errorXml GeneralResponse errorResp = new Persister().read(GeneralResponse.class, errorXml); String errorMsg = errorResp.getError().getMessage(); } catch (IOException | Exception e) { e.printStackTrace(); } } } @Override public void onFailure(Call<GeneralResponse> call, Throwable t) { // 处理网络失败等异常 } });
方案二:利用
@Root的alternate属性实现多根节点解析 这种方式更偏向面向对象,通过抽象父类+子类的方式,让SimpleXml支持解析多个根节点:
首先定义抽象父类和两个响应子类:
import org.simpleframework.xml.Root; @Root(alternate = {SuccessResponse.class, ErrorResponse.class}) public abstract class BaseResponse { }
import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; @Root(name = "Success") public class SuccessResponse extends BaseResponse { @Element private String id; public String getId() { return id; } }
import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; @Root(name = "Error") public class ErrorResponse extends BaseResponse { @Element private String message; public String getMessage() { return message; } }
然后Retrofit接口返回Call<BaseResponse>,在回调里通过instanceof判断具体类型:
call.enqueue(new Callback<BaseResponse>() { @Override public void onResponse(Call<BaseResponse> call, Response<BaseResponse> response) { if (response.isSuccessful()) { BaseResponse resp = response.body(); if (resp instanceof SuccessResponse) { String id = ((SuccessResponse) resp).getId(); // 处理成功逻辑 } else if (resp instanceof ErrorResponse) { String errorMsg = ((ErrorResponse) resp).getMessage(); // 处理错误逻辑 } } else { // 同样处理HTTP错误,解析errorBody try { String errorXml = response.errorBody().string(); BaseResponse errorResp = new Persister().read(BaseResponse.class, errorXml); if (errorResp instanceof ErrorResponse) { String errorMsg = ((ErrorResponse) errorResp).getMessage(); } } catch (IOException | Exception e) { e.printStackTrace(); } } } @Override public void onFailure(Call<BaseResponse> call, Throwable t) { // 处理网络异常 } });
额外配置提醒
确保你的Retrofit已经正确配置了SimpleXmlConverterFactory,若需要宽松解析(比如忽略未知元素),可以用createNonStrict():
Retrofit retrofit = new Retrofit.Builder() .baseUrl("你的API基础地址") .addConverterFactory(SimpleXmlConverterFactory.createNonStrict()) .build();
内容的提问来源于stack exchange,提问作者andro-girl
相关产品推荐
相关产品推荐

