HOME > android > tips

안드로이드 - XmlResourceParser로 XML 파싱하는 방법

By JS | 26 Nov 2019

XmlResourceParser로 앱의 /res/xml/에 저장된 xml파일을 파싱하는 방법을 소개합니다.

이 글에서 파싱할 xml파일은 custom styleable을 사용하여 데이터를 표현한 xml파일입니다.

XmlResourceParser를 이용하여 xml 파일을 파싱할 수 있습니다.

파싱하는 방법은 다음과 같이 두가지가 있습니다.

  • Attribute 이름을 하드코딩해서 파싱
  • Styleable을 이용하여 파싱

위의 두가지 방법에 대해서 모두 알아보겠습니다.

Styleable 정의

xml에 Custom styleable을 이용하여 데이터를 표현하려면 먼저 Styleable을 정의해야 합니다.

/res/values/attrs.xml파일을 생성하고 다음과 같이 입력합니다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="codechacha">
        <attr name="title" format="string" />
        <attr name="url" format="string" />
    </declare-styleable>
</resources>

XML 파일 생성

그럼 다음과 같이 xml파일을 생성할 수 있습니다. 만약 Styleable이 정의되지 않았다면 안드로이드 스튜디오에서 에러를 발생시킵니다.

<?xml version="1.0" encoding="utf-8"?>
<codechacha
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <site app:title="@string/site_title_1"
          app:url="https://codechacha.com/ko/get-free-and-total-size-of-volumes-in-android/"/>
    <site app:title="@string/site_title_2"
          app:url="https://codechacha.com/ko/android-q-scoped-storage/"/>
    <site app:title="@string/site_title_3"
          app:url="https://codechacha.com/ko/how-to-parse-json-in-android/"/>
    <site app:title="site_title_4"
          app:url="https://codechacha.com/ko/how-to-parse-json-in-android/"/>

</codechacha>

그리고 언어별로 String을 정의해 줍니다. 저는 공통 String을 정의하고 한국어를 추가로 정의하였습니다.

/res/values/strings.xml

<resources>
    <string name="app_name">XmlResourceParser</string>

    <string name="site_title_1">How to get stroage size</string>
    <string name="site_title_2">Android Q, Scoped Storage</string>
    <string name="site_title_3">How to parse JSON in android</string>
</resources>

/res/values-ko/strings.xml

<resources>
    <string name="site_title_1">스토리지 크기를 얻는 방법</string>
    <string name="site_title_2">안드로이드 Q, 스코프드 스토리지</string>
    <string name="site_title_3">안드로이드에서 Json을 파싱하는 방법</string>
</resources>

Attribute 이름을 하드코딩해서 파싱

이제 xml을 파싱하는 코드를 구현해야 합니다.

다음과 같이 구현하였습니다. 자세한 내용은 주석에 적었습니다. "title"과 같은 속성이름으로 할당된 Resource id를 구하고 그것으로 String을 가져왔습니다. 이렇게 하면 시스템 Locale에 따라서 다른 언어의 문자열을 가져옵니다. xml에서 문자열을 직접 넣어준 경우, Resource id가 없기 때문에 이런 경우 직접 스트링을 가져와서 사용하면 됩니다.

private fun parseXmlDataV1(parser: XmlResourceParser) {
    var eventType = -1
    val namespace = "http://schemas.android.com/apk/res-auto"
    val defaultValue = 0

    while (eventType != XmlResourceParser.END_DOCUMENT) {
        if (eventType == XmlResourceParser.START_TAG) {
            val element = parser.name

            // 처음 아이템의 이름이 "site"인지 확인
            if (element == "site") {
                // "title"의 resource id를 가져옵니다.
                val titleResId = parser.getAttributeResourceValue(
                    namespace, "title", defaultValue)
                var title: String

                // 만약 titleResId가 defaultValue라면 문자열이 하드코딩되었다는 의미입니다.
                if (titleResId == defaultValue) {
                    // 하드코딩된 경우 그냥 읽어오면 됩니다.
                    title = parser.getAttributeValue(namespace, "title")
                } else {
                    // resource id인 경우 getString()을 통해 문자열을 가져옵니다.
                    title = resources.getString(titleResId)
                }
                // url은 문자열을 직접 입력했습니다. resource id를 가져올 필요가 없습니다.
                val url  = parser.getAttributeValue(namespace, "url")
                Log.d(TAG, "title : $title, url: $url")
            }
        }
        eventType = parser.next()
    }
}

xml파일을 가져와 파싱해보면 잘 됩니다.

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    var parser = resources.getXml(R.xml.sites)
    try {
        Log.d(TAG, "Parsing with v1")
        parseXmlDataV1(parser)
    } catch (e: Exception) {
        Log.d(TAG, "Failed to parse a xml file")
    }
}

결과

11-26 22:11:48.701  6385  6385 D MainActivity: title : How to get stroage size, url: https://codechacha.com/ko/get-free-and-total-size-of-volumes-in-android/
11-26 22:11:48.701  6385  6385 D MainActivity: title : Android Q, Scoped Storage, url: https://codechacha.com/ko/android-q-scoped-storage/
11-26 22:11:48.701  6385  6385 D MainActivity: title : How to parse JSON in android, url: https://codechacha.com/ko/how-to-parse-json-in-android/
11-26 22:11:48.701  6385  6385 D MainActivity: title : site_title_4, url: https://codechacha.com/ko/how-to-parse-json-in-android/

Styleable을 이용하여 파싱

위에서 구현한 것은 Parser가 파싱할 때 속성 이름을 직접 넣어주었습니다. 큰 차이는 없지만 Styleable을 이용하여 파싱할 수도 있습니다.

private fun parseXmlDataV2(parser: XmlResourceParser) {
    var eventType = -1
    while (eventType != XmlResourceParser.END_DOCUMENT) {
        if (eventType == XmlResourceParser.START_TAG) {
            val element = parser.name

            if (element == "site") {
                // attrs에 정의한 custom styleable을 가져옵니다.
                val ta: TypedArray = resources.obtainAttributes(
                    parser, R.styleable.codechacha)

                // TypedArray.getString() 메소드에
                // 다음처럼 인자를 전달하여 스트링을 파싱합니다.
                var title = ta.getString(R.styleable.codechacha_title)
                val url  = ta.getString(R.styleable.codechacha_url)
                Log.d(TAG, "title : $title, url: $url")
            }
        }
        eventType = parser.next()
    }
}

xml파일을 가져와 파싱해보면 잘 됩니다.

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    var parser = resources.getXml(R.xml.sites)
    try {
        Log.d(TAG, "Parsing with v2")
        parseXmlDataV2(parser)
    } catch (e: Exception) {
        Log.d(TAG, "Failed to parse a xml file")
    }
}

결과

11-26 22:11:48.701  6385  6385 D MainActivity: title : How to get stroage size, url: https://codechacha.com/ko/get-free-and-total-size-of-volumes-in-android/
11-26 22:11:48.701  6385  6385 D MainActivity: title : Android Q, Scoped Storage, url: https://codechacha.com/ko/android-q-scoped-storage/
11-26 22:11:48.701  6385  6385 D MainActivity: title : How to parse JSON in android, url: https://codechacha.com/ko/how-to-parse-json-in-android/
11-26 22:11:48.701  6385  6385 D MainActivity: title : site_title_4, url: https://codechacha.com/ko/how-to-parse-json-in-android/

이 글에서 사용한 샘플은 GitHub: XmlResourceParser에서 확인할 수 있습니다.

참고