https://kotlinlang.org logo
#announcements
Title
# announcements
e

Emil Orvik Kollstrøm

10/16/2019, 8:26 PM
What is the simplest to use XML deserialization library for Kotlin? Love Klaxon for JSON, but it does not support XML
a

alex

10/16/2019, 9:13 PM
if you're on JVM you can use Jackson or any other popular deserializer library, including JVM (SAX/StAX/DOM parsers) itself.
s

Stephan Schroeder

10/17/2019, 9:50 AM
So our team is using Jackson but also Spring so this is where we configure the jackson.XmlMapper:
Copy code
@Configuration
class ImporterConfig {
    @Bean
    fun getXmlMapper(): XmlMapper = XmlMapper(JacksonXmlModule().apply {
        setDefaultUseWrapper(false)
        setXMLTextElementName(XMLTextName)
        // blank string to null
        addDeserializerForType<String> { parsed: String? ->
            if (parsed != null && parsed.isNotBlank()) {
                parsed
            } else {
                null
            }
        }
        // Boolean should also be converted from values "0"(false) and "1"(true)
        addDeserializerForType<Boolean> { parsed: String? ->
            parsed?.let{
                when(it.toLowerCase()) {
                    "0", "false" -> false
                    "1", "true" -> true
                    else -> null
                }
            }
        }
    }).apply {
        registerModule(KotlinModule())
        configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    }

    companion object {
        const val XMLTextName = "xmlTextName"
    }
}

private inline fun <reified T : Any> JacksonXmlModule.addDeserializerForType(crossinline convert: (String?) -> T?) {
    this.addDeserializer(T::class.java, object : StdDeserializer<T>(T::class.java) {
        override fun deserialize(parser: JsonParser, context: DeserializationContext): T? {
            val result: String? = StringDeserializer.instance.deserialize(parser, context)
            return convert(result)
        }
    })
}
I’m pretty proud of my inline extension function with reified type parameter
addDeserializerForType
🤓
If your wondering what
XMLTextName
is for, it’s for when you need to deserialise a tag that has a body, but also attributes. Assume you have a tag
<Price currency="EUR" >23.99</Price>
than the data class for that would look like this:
Copy code
data class Price(
        val currency: String,
        @JacksonXmlText @JsonProperty(XMLTextName) val amount: Double
)
e

Emil Orvik Kollstrøm

10/17/2019, 6:59 PM
Thanks! Yes you can be proud @Stephan Schroeder, that thing is a beauty!
101 Views