首页 > 解决方案 > XML Jackson 与 Kotlin 中非真正嵌套的 XML 绑定

问题描述

我有一个“不好看”的 XML。(是的,它是有效的,但与我通常得到的以及我知道如何处理的不同)

通常我想看到类似的东西:

<Parent....>
  <Books>
    <Book ...>
    <Book ...>
    <Book ...>
  </Books>
</Parent> 

我的 abvoe XML 数据类如下所示:

data class Parent(
    @JacksonXmlProperty(localName = "Books")
    @JacksonXmlElementWrapper
    var books: List<Book> 
)

data class Book(
    .....
    )

但不幸的是,我们传入的 XML 看起来像这样:

<Parent....>
    <Book ...>
    <Something>
    <Book ....>
    <Something>
    <Book ...>
</parent> 

因此,我正在努力将其与普通的 Jackson Mapper 匹配,而不使用自定义的。(如果我需要一个定制的,它应该是什么样子?)

我的映射器看起来像这样:

val kotlinModule: KotlinModule = KotlinModule.Builder()
                .strictNullChecks(false)
                .nullIsSameAsDefault(true) // needed, else it will break for null https://github.com/FasterXML/jackson-module-kotlin/issues/130#issuecomment-546625625
                .build()

val xmlMapper =
                XmlMapper(JacksonXmlModule())
                        .registerModule(kotlinModule)
                        .registerModule(JavaTimeModule())
                        .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) // to parse the dates as LocalDate, else parsing error
                        .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
                        .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)
                        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)

标签: javaxmlkotlinjacksonjackson-dataformat-xml

解决方案


为了反序列化这样的 XML,您可以使用两个技巧:

  • 显式关闭您的包装List<Book>,因为它们直接坐在Parent
  • 使用自定义设置器解决引擎限制,GitHub 问题#275中提出的解决方案

更具体地说,您可以这样注释您的类以允许您的示例反序列化:

@JacksonXmlRootElement
class Parent {
    @JacksonXmlProperty(localName = "Book")
    @JacksonXmlElementWrapper(useWrapping = false)
    var books: List<Book> = ArrayList()
        set(value) {
            field = books + value
        }
}

data class Book(
    @JacksonXmlProperty
    val title: String
)

我上传了一个完整的示例,它使用您的 Jackson 配置和示例 XML,作为 Kotlin 脚本到GitHub Gist。它还在底部显示了反序列化 XML 的输出。


推荐阅读