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에서 확인할 수 있습니다.
참고
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력