Sitemap

Parsing XML data via Retrofit 2.x using Kotlin

3 min readJun 5, 2020
Photo by Chris Lawton on Unsplash

For most part of fetching data through network calls, we are used to getting data in JSON. However, there can be instances when we need to or have to get data in XML format, for example when you need to parse an RSS feed. Through this tutorial, I’ll show you how that can be achieved via Retrofit using Kotlin.

Enter SimpleXmlConverterFactory, a data converter provided by Retrofit only. Though this converter factory is deprecated, but that doesn’t mean it’s non-functional. For most things, it gets tasks done simply. However, you can also check out Tickaroo library for XML parsing. It pretty much works similarly to SimpleXmlConverterFactory.

I’ll be taking example of Google Trends API which returns the data in format something like this -

<rss version=”2.0">
<channel>
<title>Daily Search Trends</title>
<description>Recent searches</description>
<link>
https://trends.google.com/trends/trendingsearches/daily?geo=US
</link>
<atom:link href=”https://trends.google.com/trends/trendingsearches/daily/rss?geo=US" rel=”self” type=”application/rss+xml”/>
<item>
<title>Pride month</title>
<ht:approx_traffic>50,000+</ht:approx_traffic>
<description/>
<link>
https://trends.google.com/trends/trendingsearches/daily?geo=US#Pride%20month
</link>
<pubDate>Mon, 01 Jun 2020 01:00:00 -0700</pubDate>
<ht:picture>
https://t1.gstatic.com/images?q=tbn:ANd9GcRl-PZIiwOHNaIdSSUTUjHTp32TLNzz4nv2xouis0RlugNrD-PFoFl1Tl0me2sgUZNSFy6TgpA_
</ht:picture>
</item>
</channel>
</rss>

I’ve deliberately skipped some of the fields to keep it simple. You can check out the complete response here. Alright, let’s get on with the implementation.

STEP 1:
Add the following dependencies in gradle script:

api ‘com.squareup.retrofit:retrofit:2.4.0’ 
api ‘com.squareup.retrofit:converter-simplexml:2.4.0’

STEP 2:
Time for model classes -

import org.simpleframework.xml.Element
import org.simpleframework.xml.ElementList
import org.simpleframework.xml.Root

@Root(name = "rss", strict = false)
class TrendingSearchResponseWrapper @JvmOverloads constructor(
@field: Element(name = "channel")
var channel: TrendingSearchResponse? = null
)

@Root(name = "channel", strict = false)
class TrendingSearchResponse @JvmOverloads constructor(
@field: ElementList(inline = true)
var itemList: List<TrendingSearchItem>? = null
)

@Root(name = "item", strict = false)
class TrendingSearchItem @JvmOverloads constructor(
@field: Element(name = "title")
var title: String = "",
@field: Element(name = "description", required = false)
var description: String = "",
@field: Element(name = "link")
var link: String = ""
)

This was the tricky section for me since XmlConverter expects model class to satisfy some rules which in some cases are not easily caught. There are some important things to note here -
1. Notice how we used Root, Element and ElementList annotations as we go about parsing the nested XML.
2. Setting strict=false only works when you are using XmlConverter factory in non-strict mode.
3. Use required=false for fields that might not be present in some the cases. Otherwise, the converter throws an error.
4. Very importantly, use JvmOverload annotation and make sure you have given a default value to every field. XmlConverterFactory requires that you provide every possible constructor for your model class. JvmOverload annotation takes care of that for us.

STEP 3:
Next up, create service interface that will be used by Retrofit to execute our request.

import io.reactivex.Single
import retrofit2.http.GET
import retrofit2.http.Query

interface TrendingSearchesApi {

@GET("rss")
fun getTrendingSearches(@Query("geo") countryCode: String): Single<TrendingSearchResponseWrapper>
}

STEP 4:
Completing the connection by adding XmlConverterFactory while creating Retrofit builder —

val retrofit : Retrofit = Retrofit.Builder()  
.baseUrl("https://trends.google.com/trends/trendingsearches /daily/")
.client(OkHttpClient())
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
val trendingApi = retrofit.create(TrendingSearchesApi.class);

In case you add multiple converters for Retrofit Builder, it will try to parse the response with first added converter. If that fails, then next and so on…

And that’s it, simple and sweet. Comment or reach out in case you have any queries.

If you found this informative, hit the CLAP button. Thanks!

--

--

Mayank Khandelwal
Mayank Khandelwal

Written by Mayank Khandelwal

Trying to go big because playing small never serves the world. Know more about me - https://mayankkhandelwal.me/

Responses (3)