print("와챠의 개발 기록장")

[안드로이드] 안드로이드 XML 데이터 파싱 본문

코딩 일기장/Android(Kotlin)

[안드로이드] 안드로이드 XML 데이터 파싱

minWachya 2021. 5. 14. 16:45
반응형

실행 결과 - 다크모드에서 실행

 

안드로이드에서 XML로 데이터 파싱하기

 

1) id 선언/연결 쉽게 하려고

glable에 id 'kotlin-android-extensions' 추가

 

2) AndroidManifest.xml에서

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 추가

 

application 안에

android:usesCleartextTraffic="true" 추가

 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myopenhospital">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyOpenHospital">
<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>

 

 

hospital.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tvHospitalName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="기관명"
android:textColor="#0000ff"
android:textSize="30dp"/>
<TextView
android:id="@+id/tvAreaName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="시도명"/>
<TextView
android:id="@+id/tvPhoneNumber"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="전화번호"/>
</LinearLayout>
view raw hospital.xml hosted with ❤ by GitHub

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<RadioGroup
android:id="@+id/rGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="8">
<RadioButton
android:id="@+id/A0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="국민 안심 병원"/>
<RadioButton
android:id="@+id/A97"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="코로나 검사 실시 기관"/>
<RadioButton
android:id="@+id/A99"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="코로나 선별 진료소 운영 기관"/>
</RadioGroup>
<Button
android:id="@+id/btnSeatch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="병원 검색"/>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="9"/>
</LinearLayout>

 

Hospital.kt

package com.example.myopenhospital
// 데이터 클래스
data class Hospital (
val hospitalName : String,
val areaName : String,
val phoneNumber : String
)
view raw Hospital.kt hosted with ❤ by GitHub

 

HospitalAdapter.kt

package com.example.myopenhospital
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.hospital.view.*
class HospitalAdapter (var items : ArrayList<Hospital>) : RecyclerView.Adapter<HospitalAdapter.ViewHolder>() {
// 뷰 홀더 만들어서 반환, 뷰릐 레이아웃은 hospital.xml
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HospitalAdapter.ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.hospital, parent, false)
return ViewHolder(itemView)
}
// 전달받은 위치의 아이템 연결
override fun onBindViewHolder(holder: HospitalAdapter.ViewHolder, position: Int) {
val item = items[position]
holder.setItem(item)
}
// 아이템 갯수 리턴
override fun getItemCount() = items.count()
// 뷰 홀더 설정
inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
fun setItem(item : Hospital) {
itemView.tvHospitalName.text = item.hospitalName
itemView.tvAreaName.text = item.areaName
itemView.tvPhoneNumber.text = item.phoneNumber
}
}
}

 

MainActivity.kt

package com.example.myopenhospital
import android.os.AsyncTask
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.StringReader
import java.net.URL
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 버튼 클릭 시 병원 검색
btnSeatch.setOnClickListener {
// 리사이클러 뷰 매니저 설정정
listView.layoutManager = LinearLayoutManager(this)
val serviceUrl = "http://apis.data.go.kr/B551182/pubReliefHospService/getpubReliefHospList" // End Point
val serviceKey = "인증키"
// pageNo=1&numOfRows=10 은 그대로
var spclAdmTyCd = ""
when(rGroup.checkedRadioButtonId) {
R.id.A0 -> spclAdmTyCd = "A0"
R.id.A97 -> spclAdmTyCd = "97"
R.id.A99 -> spclAdmTyCd = "99"
else -> Toast.makeText(applicationContext, "병원 코드를 먼저 선택하세요.", Toast.LENGTH_SHORT).show()
}
// 이 url 주소 가지고 데이터 획득하기
val requstUrl = serviceUrl + "?serviceKey=" + serviceKey +
"&pageNo=1&numOfRows=10&spclAdmTyCd=" + spclAdmTyCd
fetchXML(requstUrl)
}
}
fun fetchXML(url : String) {
lateinit var page : String // url 주소 통해 전달받은 내용 저장할 변수
// xml 데이터 가져와서 파싱하기
// 외부에서 데이터 가져올 때 화면 계속 동작하도록 AsyncTask 이용
class getDangerGrade : AsyncTask<Void, Void, Void>() {
// url 이용해서 xml 읽어오기
override fun doInBackground(vararg p0: Void?): Void? {
// 데이터 스트림 형태로 가져오기
val stream = URL(url).openStream()
val bufReader = BufferedReader(InputStreamReader(stream, "UTF-8"))
// 한줄씩 읽어서 스트링 형태로 바꾼 후 page에 저장
page = ""
var line = bufReader.readLine()
while (line != null) {
page += line
line = bufReader.readLine()
}
return null
}
// 읽어온 xml 파싱하기
override fun onPostExecute(result: Void?) {
super.onPostExecute(result)
var itemList : ArrayList<Hospital> = arrayListOf() // 저장될 데이터 배열
var bSet1 = false // 시도 태그
var bSet2 = false // 시군구 태그
var bSet3 = false // 기관명 태그
var bSet4 = false // 전화번호 태그
lateinit var sidoNm : String // 시도명
lateinit var sgguNm : String // 시군구명
lateinit var yadmNm : String // 기관명
lateinit var telno : String // 전화번호
var factory = XmlPullParserFactory.newInstance() // 파서 생성
factory.setNamespaceAware(true) // 파서 설정
var xpp = factory.newPullParser() // XML 파서
// 파싱하기
xpp.setInput(StringReader(page))
// 파싱 진행
var eventType = xpp.eventType
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_DOCUMENT) {}
else if (eventType == XmlPullParser.START_TAG) {
var tagName = xpp.name
if (tagName.equals("sidoNm")) bSet1 = true
else if (tagName.equals("sgguNm")) bSet2 = true
else if (tagName.equals("yadmNm")) bSet3 = true
else if (tagName.equals("telno")) bSet4 = true
}
if (eventType == XmlPullParser.TEXT) {
if (bSet1) { // 시도명
sidoNm = xpp.text
bSet1 = false
}
else if (bSet2) { // 시군구명
sgguNm = xpp.text
bSet2 = false
}
else if (bSet3) { // 기관명
yadmNm = xpp.text
bSet3 = false
// 기관명까지 다 읽으면 하나의 데이터 다 읽은 것임
var item = Hospital(yadmNm, sidoNm + " " + sgguNm, telno)
itemList.add(item)
}
else if (bSet4) { // 전화번호
telno = xpp.text
bSet4 = false
}
}
if (eventType == XmlPullParser.END_TAG) {}
// itemList.add()
eventType = xpp.next()
}
// 리아시클러 뷰에 데이터 연결
listView.adapter = HospitalAdapter(itemList)
}
}
getDangerGrade().execute()
}
}
view raw MainActivity.kt hosted with ❤ by GitHub

 

참고로 xml 이렇게 생김

반응형
Comments