728x90

공공데이터 포털에서 Json이 아닌 xml 을 응답으로 받아야 하는 상황이라서 xml 을 파싱하는 방법을 찾다가 처음에는 TikXml 을 사용 했으며, TikXml 사용시 gradle 충돌 문제가 있어서 다른 방법을 찾아봤다.

 

//빌드에러

Caused by: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':app:debugCompileClasspath'.

 

jaxb 로 대체하려 했으나 몇 시간의 삽질 끝에 android 지원하지 않는 것 알게됨

 

시도 해본 것

  1. annotaion 버전 down grade
  2. 캐시 삭제
  3. 리빌드 프로젝트 -> Could not find com.tickaroo.tikxml:annotation:0.8.15.
    Required by:
    project :app
    project :app > com.tickaroo.tikxml:retrofit-converter:0.8.15 에러
  4. kapt 제거
  5. jaxb 라이브러리 사용 -> 안드로이드 지원x 삽질o

결국 버전을 내려서 다시 시도 

implementation("com.tickaroo.tikxml:annotation:0.8.13")
implementation("com.tickaroo.tikxml:core:0.8.13")
kapt("com.tickaroo.tikxml:processor:0.8.13")
implementation("com.tickaroo.tikxml:retrofit-converter:0.8.13")
kapt("com.tickaroo.tikxml:auto-value-tikxml:0.8.13")

 

버전을 0.8.15 에서 0.8.13으로 내려서 그래들 문제는 해결이 되었는데 데이터가 들어온 이후에 타임아웃 에러가 뜸

 

-> 데이터 클래스 구조와 어노테이션을 잘 못 사용한 것 때문에 파싱이 제대로 안된 것 데이터 클래스 구조와 어노테이션을 제대로 사용해서 파싱 성공

 

KopisApi

package com.nbc.curtaincall.data.model

import retrofit2.http.GET
import retrofit2.http.Query

interface KopisApi {
    @GET("pblprfr")
    suspend fun fetchShowList(
        @Query("stdate") stdate: String = "20240101",
        @Query("eddate") eddate: String = "20240630",
        @Query("cpage") cpage: String = "1",
        @Query("rows") rows: String = "10",
    ): ShowListResponse
}

 

RetrofitClient

package com.nbc.curtaincall.data.api

import com.nbc.curtaincall.BuildConfig
import com.nbc.curtaincall.data.model.KopisApi
import com.tickaroo.tikxml.TikXml
import com.tickaroo.tikxml.retrofit.TikXmlConverterFactory
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import java.util.concurrent.TimeUnit

private const val BASE_URL = "http://kopis.or.kr/openApi/restful/"
private const val KOPIS_API_KEY = BuildConfig.KOPIS_API_KEY

object RetrofitClient {
    private val loggingInterceptor = HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY // 로깅 레벨 설정 (BASIC, HEADERS, BODY)
    }

    // API Key 삽입을 위한 인터셉터
    private val apiKeyInterceptor = Interceptor { chain ->
        val original = chain.request()
        val originalHttpUrl = original.url
        val url = originalHttpUrl.newBuilder()
            .addQueryParameter("service", KOPIS_API_KEY)  // Kopis api key 기본 추가
            .build()
        val requestBuilder = original.newBuilder().url(url)
        val request = requestBuilder.build()
        chain.proceed(request)
    }

    // OkHttpClient 설정
    private val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(apiKeyInterceptor)
        .addInterceptor(loggingInterceptor)
        .readTimeout(15, TimeUnit.SECONDS)
        .writeTimeout(15, TimeUnit.SECONDS)
        .connectTimeout(15, TimeUnit.SECONDS)
        .build()


    // Retrofit 설정
    private val retrofit by lazy {
    	//exceptionOnUnreadXml(false).build() 는 원하지 않는 데이터는 제외하기 위해서입니다. 내려받은 데이터를 모두 사용하신다면 추가하지 않아도 됩니다.
        val parser = TikXml.Builder().exceptionOnUnreadXml(false).build()
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(TikXmlConverterFactory.create(parser))
            .build()
    }

    val kopisApi: KopisApi by lazy { retrofit.create(KopisApi::class.java) }
}

 

ShowListResponse 

package com.nbc.curtaincall.data.model

import com.tickaroo.tikxml.annotation.Element
import com.tickaroo.tikxml.annotation.PropertyElement
import com.tickaroo.tikxml.annotation.Xml

@Xml(name = "dbs")
data class ShowListResponse(
    @Element(name = "db")
    val showList: List<ShowList>
)

@Xml(name = "db")
data class ShowList(
    @PropertyElement(name = "area") val area: String?,
    @PropertyElement(name = "fcltynm") val fcltynm: String?,
    @PropertyElement(name = "genrenm") val genrenm: String?,
    @PropertyElement(name = "mt20id") val mt20id: String?,
    @PropertyElement(name = "openrun") val openrun: String?,
    @PropertyElement(name = "poster") val poster: String?,
    @PropertyElement(name = "prfnm") val prfnm: String?,
    @PropertyElement(name = "prfpdfrom") val prfpdfrom: String?,
    @PropertyElement(name = "prfpdto") val prfpdto: String?,
    @PropertyElement(name = "prfstate") val prfstate: String?
)

 

@PropertyElement는 nest child element가 없는 경우 @Element는 nest child element를 가진 경우

어노테이션 부분은 Json을 파싱할 때랑 비슷하다. 

 

공식문서 참고

https://github.com/Tickaroo/tikxml/blob/master/docs/AnnotatingModelClasses.md

 

 

받아오는 XML 형태 

<?xml version="1.0" encoding="UTF-8"?>
<dbs>
    <db>
        <mt20id>PF236104</mt20id>
        <prfnm>싱어게인3 TOP10 전국투어 [울산]</prfnm>
        <prfpdfrom>2024.06.08</prfpdfrom>
        <prfpdto>2024.06.08</prfpdto>
        <fcltynm>KBS홀 [울산]</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236104_240223_151315.gif</poster>
        <genrenm>대중음악</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
    <db>
        <mt20id>PF236099</mt20id>
        <prfnm>화통콘서트 [거창]</prfnm>
        <prfpdfrom>2024.03.09</prfpdfrom>
        <prfpdto>2024.03.09</prfpdto>
        <fcltynm>거창문화센터</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236099_240223_144636.jpg</poster>
        <genrenm>복합</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
    <db>
        <mt20id>PF236098</mt20id>
        <prfnm>한경arte필하모닉 더클래식 시리즈3, 지휘 이병욱 &amp; 바이올린 윤소영</prfnm>
        <prfpdfrom>2024.03.28</prfpdfrom>
        <prfpdto>2024.03.28</prfpdto>
        <fcltynm>롯데콘서트홀</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236098_240223_143315.jpg</poster>
        <genrenm>서양음악(클래식)</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
    <db>
        <mt20id>PF236097</mt20id>
        <prfnm>퍼커셔니스트 고길영 &amp; 홍진영 세 번째 듀오 리사이틀</prfnm>
        <prfpdfrom>2024.03.31</prfpdfrom>
        <prfpdto>2024.03.31</prfpdto>
        <fcltynm>대전예술의전당</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236097_240223_142644.gif</poster>
        <genrenm>서양음악(클래식)</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
    <db>
        <mt20id>PF236096</mt20id>
        <prfnm>코리아아르츠그룹 베스트 아티스트 시리즈, 1. The Best Sopranos</prfnm>
        <prfpdfrom>2024.03.11</prfpdfrom>
        <prfpdto>2024.03.11</prfpdto>
        <fcltynm>롯데콘서트홀</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236096_240223_141522.jpg</poster>
        <genrenm>서양음악(클래식)</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
    <db>
        <mt20id>PF236095</mt20id>
        <prfnm>지브리 페스티벌</prfnm>
        <prfpdfrom>2024.05.12</prfpdfrom>
        <prfpdto>2024.05.12</prfpdto>
        <fcltynm>롯데콘서트홀</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236095_240223_140619.gif</poster>
        <genrenm>서양음악(클래식)</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
    <db>
        <mt20id>PF236094</mt20id>
        <prfnm>지브리 봄 음악 대축전</prfnm>
        <prfpdfrom>2024.04.18</prfpdfrom>
        <prfpdto>2024.04.18</prfpdto>
        <fcltynm>롯데콘서트홀</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236094_240223_140210.jpg</poster>
        <genrenm>서양음악(클래식)</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
    <db>
        <mt20id>PF236093</mt20id>
        <prfnm>오페라속 여인들1 [제주 서귀포]</prfnm>
        <prfpdfrom>2024.03.30</prfpdfrom>
        <prfpdto>2024.03.30</prfpdto>
        <fcltynm>서귀포예술의전당</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236093_240223_135545.jpg</poster>
        <genrenm>서양음악(클래식)</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
    <db>
        <mt20id>PF236090</mt20id>
        <prfnm>프린세스 공주뮤지컬쇼 [청주]</prfnm>
        <prfpdfrom>2024.04.14</prfpdfrom>
        <prfpdto>2024.04.14</prfpdto>
        <fcltynm>청주예술의전당</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236090_240223_133927.jpg</poster>
        <genrenm>뮤지컬</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
    <db>
        <mt20id>PF236088</mt20id>
        <prfnm>기형도 35주기 추모 행사, 기형도 플레이</prfnm>
        <prfpdfrom>2024.03.22</prfpdfrom>
        <prfpdto>2024.03.22</prfpdto>
        <fcltynm>광명시민회관</fcltynm>
        <poster>http://www.kopis.or.kr/upload/pfmPoster/PF_PF236088_240223_132953.jpg</poster>
        <genrenm>연극</genrenm>
        <openrun>N</openrun>
        <prfstate>공연예정</prfstate>
    </db>
</dbs>

 

API 통신응답을 JSON으로 밖에 받아 본 경험 밖에 없어서 XML 을 파싱하는데 많은 시행착오와 씨뻘건 오류 메세지만 이틀간 보면서 씨름 했다. 결국 Json이랑 다를 건 별로 없는데, Xml을 파싱하는 과정이 순조롭지 못 했고 TikXml이 2020년에 commit 된게 마지막이라고 한다. 

 

안드로이드에서는 XmlPullParser 사용을 추천하는 것 같은데 Retrofit을 사용하지 않는 것 같아서 다음에 한 번 알아봐야 겠다.

 

 

+ Recent posts