Cosmic Dev
Cosmic Dev

Reputation: 542

How to parse xml response using retrofit in kotlin?

I have the following response:

<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
    <photos page="1" pages="3704" perpage="100" total="370320">
        <photo id="49658592343" owner="138998919@N06" secret="0db4e03977" server="65535" farm="66" title="mmm " ispublic="1" isfriend="0" isfamily="0" />
        <photo id="49658586758" owner="156045424@N06" secret="2444dda679" server="65535" farm="66" title="Boeing 787-9 (G-CKOG) Norwegian Airlines" ispublic="1" isfriend="0" isfamily="0" />
        <photo id="49659129251" owner="156045424@N06" secret="97d1bd202e" server="65535" farm="66" title="Boeing 787-9 (G-CKOG) Norwegian Airlines" ispublic="1" isfriend="0" isfamily="0" />
         </photos>
</rsp>

and I am using SimpleXmlConverterFactory as a retrofit converter .I have converted the above response to json through an online converter and created a data class from it, parent class is as follows:

data class ResponseImages(
    val photos: Photos,
    val stat: String
)

but I am getting this error everytime i run the app:

org.simpleframework.xml.core.AttributeException: Attribute 'stat' does not have a match in class com.abx.cbz.Response.ResponseImages at line -1

so what I am doing wrong here?

Upvotes: 2

Views: 1983

Answers (2)

Dmitry Nitapol
Dmitry Nitapol

Reputation: 1

The following solution has worked for me: serialize + annotation + converter

code in gradle:

kotlin("plugin.serialization") version "1.9.21"
...

implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
implementation("io.github.pdvrieze.xmlutil:core:0.86.3")
implementation("io.github.pdvrieze.xmlutil:serialization:0.86.3")

retrofit factory:

val contentType = "text/xml".toMediaType()
val retro = Retrofit.Builder()
.addConverterFactory(XML.asConverterFactory(contentType))

annotation:

@Serializable
@XmlSerialName("myclass")
data class MyClass (
    @XmlElement(false)
    @XmlSerialName("id")
    var id: String = "",

    @XmlSerialName("item")
    @XmlElement(true)
    var items: List<Item> = listOf(Item())
}
  • I tried to use fastxml in my case, it worked well in okhttp3, but without retrofit.

Unsuccessful attempts:

  • SimpleXmlConverterFactory I couldn't serialize my classes properly. Deprecated!!!
  • JaxbConverterFactory that JAXB does not work on Android.
  • TikXML Work in Progress. Needed kotlin-kapt plugin. There were error whith implementation com.tickaroo.tikxml:processor (no type adaper exception)

Upvotes: 0

Cosmic Dev
Cosmic Dev

Reputation: 542

By reading various SO threads i have managed to make it work by using the following code block:

@Root(name = "photos")
data class Photos @JvmOverloads constructor(

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

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

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

    @field:ElementList(name = "photo", inline = true)
    @param:ElementList(name = "photo", inline = true)
    var photo: List<Photo>,

    @field:Attribute(name = "total")
    @param:Attribute(name = "total")
    var total: String
)

The same format should be used for other data classes too, I am only displaying one. There needs to be an empty constructor that's why I have used @JvmOverloads but the use of @param annotation is not that clear yet, a brief idea is we have to force Kotlin to generate constructor overloads.

Upvotes: 3

Related Questions