最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - How to parse this rare XML structure with Retrofit? - Stack Overflow

programmeradmin1浏览0评论

I'm using Retrofit and Jackson with XML parser to transform this XML into data classes. As you can see it's a very rare array inside child_group... there is one item and one info, one item and one info, etc... not a normal array.

<?xml version="1.0" encoding="utf-8"?>
<parent id="2261">
    <child_group>
        <item>
            <line>1</line>
        </item>
        <info></info>
        <item>
            <line>2</line>
        </item>
        <info></info>
        <item>
            <line>3</line>
        </item>
        <info></info>
    </child_group>
</parent>

I can't find any info about how to create the data class structure to parse this. What can I try next?

This data class structure passed to retrofit only parses the first item and the first info, but not the rest of them:

@JacksonXmlRootElement(localName = "parent")
data class Parent(
    val id: String,
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "child_group")
    val child_group: ChildGroup
)

data class ChildGroup(
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "item")
    val item: List<Item>,
    val info: String? = null
)

data class Item(
    val line: String
)

This is my Retrofit builder:

Retrofit.Builder().baseUrl("/")
.addConverterFactory(
    JacksonConverterFactory.create(XmlMapper()
    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    .registerKotlinModule()))
.build().create(ApiService::class.java)

I tried also doing this, with same result:

@JacksonXmlRootElement(localName = "parent")
data class Parent(
    val id: String,
    @JacksonXmlProperty(localName = "child_group")
    @JacksonXmlElementWrapper(useWrapping = false)
    val childGroup: List<ChildGroupItem> 
)

data class ChildGroupItem(
    val item: Item,
    val info: String? = null 
)

data class Item(
    val line: String
)

I'm using Retrofit and Jackson with XML parser to transform this XML into data classes. As you can see it's a very rare array inside child_group... there is one item and one info, one item and one info, etc... not a normal array.

<?xml version="1.0" encoding="utf-8"?>
<parent id="2261">
    <child_group>
        <item>
            <line>1</line>
        </item>
        <info></info>
        <item>
            <line>2</line>
        </item>
        <info></info>
        <item>
            <line>3</line>
        </item>
        <info></info>
    </child_group>
</parent>

I can't find any info about how to create the data class structure to parse this. What can I try next?

This data class structure passed to retrofit only parses the first item and the first info, but not the rest of them:

@JacksonXmlRootElement(localName = "parent")
data class Parent(
    val id: String,
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "child_group")
    val child_group: ChildGroup
)

data class ChildGroup(
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "item")
    val item: List<Item>,
    val info: String? = null
)

data class Item(
    val line: String
)

This is my Retrofit builder:

Retrofit.Builder().baseUrl("https://www.website.es/")
.addConverterFactory(
    JacksonConverterFactory.create(XmlMapper()
    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    .registerKotlinModule()))
.build().create(ApiService::class.java)

I tried also doing this, with same result:

@JacksonXmlRootElement(localName = "parent")
data class Parent(
    val id: String,
    @JacksonXmlProperty(localName = "child_group")
    @JacksonXmlElementWrapper(useWrapping = false)
    val childGroup: List<ChildGroupItem> 
)

data class ChildGroupItem(
    val item: Item,
    val info: String? = null 
)

data class Item(
    val line: String
)
Share Improve this question edited yesterday halfer 20.4k19 gold badges108 silver badges201 bronze badges asked 2 days ago NullPointerExceptionNullPointerException 37.6k80 gold badges230 silver badges402 bronze badges 1
  • Hello in your last mentioned data class ChildGroupItem, item and info should be list as you are not getting a single object but a group of objects. Also, in class Parent childGroup is a single object and not list. Try that way, it should work. – Rajen Raiyarela Commented yesterday
Add a comment  | 

1 Answer 1

Reset to default 3

This problem is similar to https://stackoverflow.com/a/79388160/860227. If you manage to sort all items in child_group (all item tags come first, followed by info), your solution will work.

You need to create a custom deserializer for ChildGroup class like:

class CustomDeserializer : JsonDeserializer<ChildGroup>() {
    override fun deserialize(parser: JsonParser, context: DeserializationContext): ChildGroup {
        val items = mutableListOf<Item>()
        val infos = mutableListOf<String>()

        val node = parser.codec.readTree<JsonNode>(parser)
        node.fields().forEach { (key, value) ->
            when (key) {
                "item" -> {
                    if (value.isArray) {
                        value.forEach { itemNode ->
                            val item = parser.codec.treeToValue(itemNode, Item::class.java)
                            items.add(item)
                        }
                    } else {
                        val item = parser.codec.treeToValue(value, Item::class.java)
                        items.add(item)
                    }
                }
                "info" -> {
                    if (value.isArray) {
                        value.forEach { itemNode ->
                            infos.add(itemNode.asText())
                        }
                    } else {
                        infos.add(value.asText())
                    }
                }
            }
        }
        return ChildGroup(items, infos)
    }
}

and register it in the data class:

@JacksonXmlRootElement(localName = "parent")
data class Parent(
    val id: String,
    @JsonDeserialize(using = CustomDeserializer::class) // <-- this
    val child_group: ChildGroup
)

data class ChildGroup(
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "item")
    val item: List<Item>,
    val info: List<String>,
)

data class Item(
    val line: String
)
发布评论

评论列表(0)

  1. 暂无评论