首页 > 解决方案 > 使用 Retrofit2 和 SimpleXmlConverterFactory 序列化为 XML 时,如何包含 DOCTYPE 声明?

问题描述

我正在尝试将 SimpleXmlConverterFactory 与 Retrofit 一起使用来创建对 REST 服务的 XML 请求。但是,该服务需要请求中的 DTD 声明,就像这样。

<!DOCTYPE paymentService PUBLIC "-//WorldPay//DTD WorldPay PaymentService v1//EN" "http://dtd.worldpay.com/paymentService_v1.dtd">

但是当 SimpleXmlConverterFactory 序列化数据对象时,它会省略 DOCTYPE 声明:

<paymentService merchantCode="..." version="1.4">
  <inquiry>
    <shopperTokenRetrieval>
      <authenticatedShopperID>...</authenticatedShopperID>
    </shopperTokenRetrieval>
  </inquiry>
</paymentService>

创建 SimpleXmlConverterFactory 并没有什么特别之处:

val builder = Retrofit
                .Builder()
                .addConverterFactory(
                        SimpleXmlConverterFactory.create()
                )
                .baseUrl(BuildConfig.WORLDPAY_BASE_URL)
                .build()
                .create(WorldPayApiService::class.java)

这是带注释的数据对象

@Root(name = "paymentService")
data class WorldPayXmlPaymentService(
        @field:Attribute(name = "version")
        var version: String = "",

        @field:Attribute(name = "merchantCode")
        var merchantCode: String = "",

        @field:Element(name = "reply", required = false)
        var reply: WorldPayXmlReply? = null,

        @field:Element(name = "inquiry", required = false)
        var inquiry: WorldPayXmlInquiry? = null
)

标签: androidretrofit2simple-xml-converter

解决方案


我将 Persister 作为参数添加到 SimpleXmlConverterFactory.create 方法中,如下所示。它查找根元素,然后在序列化其余部分之前输出 DOCTYPE。

val persister = object : Persister() {
  @Throws(Exception::class)
  override fun write(source: Any, out: Writer) {
    (source as? WorldPayXmlPaymentService)?.let {
      val docType = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
        "<!DOCTYPE paymentService PUBLIC \"-//WorldPay//DTD WorldPay PaymentService v1//EN\" \"http://dtd.worldpay.com/paymentService_v1.dtd\">"
      out.write(docType)
      super.write(source, out)
    }
  }
}

val builder = Retrofit
                .Builder()
                .addConverterFactory(
                        SimpleXmlConverterFactory.create(persister)
                )
                .baseUrl(BuildConfig.WORLDPAY_BASE_URL)
                .build()
                .create(WorldPayApiService::class.java)

WorldPayXmlPaymentService 是我的根数据对象。

感谢@CommonsWare 的指导。


推荐阅读