이 글에서는 Kotlin을 사용해 Android 앱에서 XmlPullParser로 XML 데이터를 구문 분석(파싱)하는 방법을 단계별로 살펴봅니다. 프로젝트 생성부터 실제 기기에서 실행하기까지 전체 과정과 예제 코드를 함께 정리했습니다.
XmlPullParser란 무엇인가?
XmlPullParser는 Android에 기본 포함된 경량 XML 파서입니다. 문서 전체를 한 번에 메모리에 올리는 DOM 방식과 달리, START_TAG·TEXT·END_TAG 같은 이벤트를 순서대로 읽어 처리하는 풀(Pull) 방식으로 동작합니다. 따라서 용량이 큰 XML 문서를 다룰 때도 메모리를 효율적으로 사용할 수 있어 Android 환경에 특히 적합합니다.
구현 단계
1단계 — 새 프로젝트 생성
Android Studio에서 File → New Project를 선택한 뒤, 필요한 정보를 모두 입력하여 새 프로젝트를 생성합니다.
2단계 — 메인 레이아웃 작성
res/layout/activity_main.xml 파일에 아래 코드를 추가합니다. 화면에는 파싱 결과를 보여줄 ListView 하나가 배치됩니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:dividerHeight="1dp" />
</LinearLayout>
3단계 — 리스트 항목 레이아웃 작성(row.xml)
새 레이아웃 리소스 파일(row.xml)을 만들고 다음 코드를 추가합니다. 각 리스트 항목은 이름, 직책, 지역을 표시하는 세 개의 TextView로 구성됩니다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="4dp">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/background_dark"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvDesignation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tvName"
android:layout_marginTop="7dp"
android:textColor="#343434"
android:textSize="12sp" />
<TextView
android:id="@+id/tvLocation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/tvDesignation"
android:layout_alignBottom="@+id/tvDesignation"
android:layout_alignParentEnd="true"
android:textColor="@android:color/background_dark"
android:textSize="16sp" />
</RelativeLayout>
4단계 — assets 폴더에 XML 데이터 파일 추가(model.xml)
새 asset 폴더를 만들고, 그 안에 Android 리소스 파일(model.xml)을 생성한 후 아래 코드를 입력합니다. 이 파일에는 파싱할 사용자 데이터가 담겨 있습니다. 참고로 XML의 태그 이름(name, designation, location)은 이후 파서 코드에서 비교하는 문자열과 반드시 일치해야 하므로 오타에 주의하세요.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<users>
<user>
<name>Sehwag</name>
<designation>Vice Captain</designation>
<location>Delhi</location>
</user>
<user>
<name>Ashwin</name>
<designation>Off Spin Bowler</designation>
<location>Chennai</location>
</user>
<user>
<name>Dhoni</name>
<designation>Captain</designation>
<location>Ranchi</location>
</user>
</users>
</resources>
5단계 — MainActivity.kt 작성
src/MainActivity.kt에 다음 코드를 추가합니다. assets 폴더의 model.xml을 열어 XmlPullParserFactory로 파서를 생성한 뒤, 이벤트 루프를 돌며 각 user 요소의 값을 HashMap에 저장하고 ListView에 바인딩합니다.
import android.os.Bundle
import android.widget.ListAdapter
import android.widget.ListView
import android.widget.SimpleAdapter
import androidx.appcompat.app.AppCompatActivity
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import org.xmlpull.v1.XmlPullParserFactory
import java.io.IOException
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
title = "KotlinApp"
try {
val userList = ArrayList<java.util.HashMap<String?, String?>>()
var user: HashMap<String?, String?>? = HashMap()
val lv: ListView = findViewById(R.id.listView)
val inputStream = assets.open("model.xml")
val parserFactory: XmlPullParserFactory = XmlPullParserFactory.newInstance()
val parser: XmlPullParser = parserFactory.newPullParser()
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true)
parser.setInput(inputStream, null)
var tag: String?
var text = ""
var event = parser.eventType
while (event != XmlPullParser.END_DOCUMENT) {
tag = parser.name
when (event) {
XmlPullParser.START_TAG -> if (tag == "user") user = HashMap()
XmlPullParser.TEXT -> text = parser.text
XmlPullParser.END_TAG -> when (tag) {
"name" -> user!!["name"] = text
"designation" -> user!!["designation"] = text
"location" -> user!!["location"] = text
"user" -> if (user != null) userList.add(user)
}
}
event = parser.next()
}
val adapter: ListAdapter = SimpleAdapter(this@MainActivity, userList, R.layout.row,
arrayOf("name", "designation", "location"), intArrayOf(R.id.tvName,
R.id.tvDesignation, R.id.tvLocation))
lv.adapter = adapter
} catch (e: IOException) {
e.printStackTrace()
} catch (e: XmlPullParserException) {
e.printStackTrace()
}
}
}
파싱 로직 핵심 정리
- START_TAG: <user> 태그를 만나면 해당 사용자의 데이터를 담을 새 HashMap을 생성합니다.
- TEXT: 현재 태그 사이의 텍스트 값(이름, 직책, 지역)을 임시 변수에 저장합니다.
- END_TAG: name, designation, location 태그가 닫힐 때 각각의 값을 HashMap에 넣고, <user> 태그가 닫히면 완성된 데이터를 userList에 추가합니다.
파싱이 끝나면 SimpleAdapter를 통해 userList와 row.xml 레이아웃을 연결해 ListView에 표시합니다.
6단계 — AndroidManifest.xml 확인
androidManifest.xml이 아래와 같이 MainActivity가 런처 액티비티로 등록되어 있는지 확인합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android" package="com.example.q11">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
앱 실행하기
이제 애플리케이션을 실행해 보겠습니다. 실제 Android 기기를 컴퓨터에 연결했다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤, 툴바의 Run 아이콘을 클릭하세요. 실행 옵션에서 자신의 모바일 기기를 선택하면, 기기 화면에 파싱된 사용자 목록이 ListView로 표시되는 것을 확인할 수 있습니다.