Java中SimpleXML反序列化Retrofit2的SOAP XML响应遇xsi/xmlns问题
嘿,我来帮你搞定这个Retrofit2处理SOAP XML响应的头疼问题!核心就是xsi实例和xmlns命名空间的处理,咱们一步步拆解解决它。
解决Retrofit2 SOAP XML反序列化问题
1. 先揪出问题根源
Retrofit默认用的是Gson这类JSON解析器,完全不兼容XML,更别说处理SOAP里的xmlns命名空间和xsi实例属性了。所以第一步必须换个XML专用的转换器,SimpleXmlConverter是Android/Java项目里最靠谱的选择。
2. 第一步:添加XML解析依赖
先在你的build.gradle(Java项目用pom.xml)里加上依赖:
// Retrofit2的SimpleXml转换器,版本和你的Retrofit版本保持一致 implementation 'com.squareup.retrofit2:converter-simplexml:2.9.0'
如果是Android项目,可能需要在AndroidManifest.xml里加一行tools:replace="android:appComponentFactory"来避免依赖冲突,先加依赖再说。
3. 给模型类加上命名空间和xsi处理注解
你的三个模型类(UsStatesResponseBody、UsStatesCPResponse、UsStatesResponseReturn)必须用SimpleXml的注解明确标注命名空间,还要处理xsi:开头的属性。我给你写个示例:
UsStatesResponseBody.class
import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Root; @Root(name = "Envelope", strict = false) // strict=false可以忽略XML里没定义的额外元素 @Namespace(prefix = "soapenv", reference = "http://schemas.xmlsoap.org/soap/envelope/") public class UsStatesResponseBody { @Element(name = "Body") @Namespace(prefix = "soapenv", reference = "http://schemas.xmlsoap.org/soap/envelope/") private UsStatesCPResponse body; // 别忘了加Getters和Setters }
UsStatesCPResponse.class
import org.simpleframework.xml.Element; import org.simpleframework.xml.Namespace; // 把这里的reference换成你SOAP响应里实际的命名空间URL @Namespace(prefix = "web", reference = "http://your-target-namespace.com/") public class UsStatesCPResponse { @Element(name = "getUsStatesResponse") private UsStatesResponseReturn responseReturn; // Getters和Setters }
UsStatesResponseReturn.class
import org.simpleframework.xml.Element; import org.simpleframework.xml.Attribute; public class UsStatesResponseReturn { // 处理xsi:type属性,required=false表示这个属性可能不存在 @Attribute(name = "xsi:type", required = false) private String xsiType; @Element(name = "stateCode") private String stateCode; @Element(name = "stateName") private String stateName; // 其他字段和对应的Getters/Setters }
💡 关键提醒:
- 命名空间的URL必须和响应里的完全一致,包括大小写和结尾的斜杠
@Root(strict = false)能避免因为XML里有额外元素导致解析失败- 对于
xsi:开头的属性,直接用@Attribute(name = "xsi:type")标注即可,SimpleXml会自动处理
4. 重新配置Retrofit实例,换成XML转换器
原来的Retrofit可能用的是GsonConverterFactory,现在必须换成SimpleXmlConverterFactory:
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://your-soap-service-base-url.com/") .addConverterFactory(SimpleXmlConverterFactory.create()) // 替换成XML转换器 .build();
如果你的XML里有CDATA内容,还需要额外配置:
// 配置支持CDATA的序列化器 Serializer serializer = new Persister(new AnnotationStrategy()); SimpleXmlConverterFactory factory = SimpleXmlConverterFactory.create(serializer); // 用这个factory创建Retrofit Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://your-soap-service-base-url.com/") .addConverterFactory(factory) .build();
5. 检查你的Retrofit接口定义
确保接口正确配置了SOAP请求的头部和请求体:
public interface SoapService { @POST("/your-soap-endpoint-path") @Headers({ "Content-Type: text/xml; charset=utf-8", // 替换成你服务实际要求的SOAPAction,有些需要加引号,有些不需要 "SOAPAction: \"http://your-target-namespace.com/getUsStates\"" }) Call<UsStatesResponseBody> getUsStates(@Body RequestBody soapRequest); }
6. 常见坑点排查
- 命名空间的URL一定要和响应里的完全匹配,别漏了斜杠或者大小写错误
- 如果响应里有默认命名空间(没有前缀),直接用
@Namespace(reference = "http://...")不要指定prefix - 如果
xsi:type是复杂类型,可能需要自定义转换器或者用@ElementUnion处理不同类型的返回 - 模型类的字段名要和XML标签名完全一致,包括大小写
内容的提问来源于stack exchange,提问作者Mahdi Azadbar
相关产品推荐
相关产品推荐

