본문 바로가기

안드로이드

[Android] Retrofit2을 활용시 반환 타입이 XML일 경우 변환 방법

개요

Retrofit2를 활용할 시 보통 대부분 응답 결과가 JSON으로 오기 때문에 GsonConverter를 사용한다. 하지만 국내 일부 공공데이터나 오래된 데이터는 XML 결과만 제공한다. 아래 '국문 관광정보 서비스'가 대표적이다.

 

과거에는 SimpleXML 라이브리를 활용하여 Converting이 가능했다고 하는데 현재는 deprecated되어 사용 불가능한 상태이다. 구글링한 결과 Tikxml이 가장 괜찮은 라이브러리로 보여 사용법을 소개한다.

 

 

Tickaroo/tikxml

Modern XML Parser for Android. Contribute to Tickaroo/tikxml development by creating an account on GitHub.

github.com

 

종속성 추가

   //retrofit
    implementation "com.squareup.retrofit2:retrofit:2.7.2"

   //xml parser
    implementation 'com.tickaroo.tikxml:annotation:0.8.13'
    implementation 'com.tickaroo.tikxml:core:0.8.13'
    implementation 'com.tickaroo.tikxml:retrofit-converter:0.8.13'

    kapt 'com.tickaroo.tikxml:processor:0.8.13'

만약 kotlin-kapt 플러그인을 사용하고 있지 않다면 기존 annotationProcessor 활용할 것

 

RetrofitClient 작성

object RetrofitClient {
    private var instance: Retrofit? = null
    fun getInstance(): Retrofit {

        if (instance == null)
            instance = Retrofit.Builder()
                .baseUrl("http://api.visitkorea.or.kr/openapi/service/rest/KorService/")
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(TikXmlConverterFactory.create(TikXml.Builder().exceptionOnUnreadXml(false).build()))
                .build()
        return instance!!
    }
}

눈 여겨 볼 곳은addConverterFactory(TikXmlConverterFactory.create(TikXml.Builder().exceptionOnUnreadXml(false).build())) 이다.

기존 GsonConverterFactory.create() 대신 추가된 모습이다. 하나 또 주목할 점은 TikXml.Builder().exceptionOnUnreadXml(false).build() 이 코드 부분인데, xml을 읽는 과정에서 POJO 클래스에서 굳이 읽고 싶지 않은 데이터가 있을 경우 추가해주는 것이 좋다. 없다면 에러가 발생함.

 

다음으로 POJO를 작성하기 전에 아래와 같은 반환결과가 온다고 가정하자.

 

위를 기반으로 POJO 클래스를 작성해본다면, 아래와 같다.

@Xml(name="response")
data class Tour(
        @Element
        val header: Header,
        @Element
        val body: Body,
){

}

@Xml(name = "header")
data class Header(
        @PropertyElement
        val resultCode: Int,
        @PropertyElement
        val resultMsg: String,
)

@Xml(name = "body")
data class Body(
        @Element
        val items: Items,
        @PropertyElement
        val numOfRows: Int,
        @PropertyElement
        val pageNo: Int,
        @PropertyElement
        val totalCount: Int,
)

@Xml
data class Items(
        @Element(name = "item")
        val item: List<Item>
)

@Xml
data class Item(
    @PropertyElement(name="addr1") var address: String?,
    @PropertyElement(name="contenttypeid") var contentTypeId : Int?,
    @PropertyElement(name="mapx") var latitude : Double?,
    @PropertyElement(name="mapy") var longitude : Double?,
    @PropertyElement(name="tel") var tel: String?,
    @PropertyElement(name="title") var title: String?,
    @PropertyElement(name="firstimage") var mainImageUrl: String?,
    @PropertyElement(name="firstimage2") var subImageUrl: String?
){
    constructor() : this(null,null,null,null,null,null,null,null)
}

 

@Xml은 하위 Element를 감싸는 annotation이고, Element는 그 다음 하위, PropertyElement는 Element 내부 property들을 의미한다. 이에 대한 아주 자세한 설명은 아래 wiki에 설명되어있다.

 

위에서 주목할 점은 필드가 모두 Nullable처리가 되어있다는 점이다. 만약 XML에서 받으려고 했던 일부 프로퍼티가 존재하지 않을 경우 null로 받을 수 있도록 처리해야되기 때문이다.

 

 

Tickaroo/tikxml

Modern XML Parser for Android. Contribute to Tickaroo/tikxml development by creating an account on GitHub.

github.com