2021. 1. 11. 16:36ㆍ개발 관련/안드로이드 스튜디오
XML 파싱 방법
- DOM (Document Object Model ) Parser
- Dom parser ( Document, DocumentBuilder )
- jsoup : 자바 HTML 파서
- SAX (Simple API for XML ) Parser
- XML Pull Parser
1. DOM 파서
-
xml 문서를 파싱 -> 1:1로 매핑되는 object로 생성 -> 메모리에 문서 구조 그대로인 Tree 구조 ( 리턴된 Object ) 로 적재
-
끝까지 파싱하고 객체를 생성하여 리턴하기 전까지는 다른 event 발생 불가 ( 완료될 때까지 대기 )
-
+ 한번 파싱하면 언제든 원하는 element 정보를 얻을 수 있다( name, text, attribute )
-
+ root, child, parent, sibling 노드 탐색 기능을 사용할 수 있다
-
+ DOM 객체를 수정하여 xml로 문서화할 수 있다. ( Generator 기능 )
-
- 문서가 커질수록 메모리를 많이 소모한다.
-
추천 : xml 문서 탐색이 빈번하게 발생할 경우, 문서 구조가 자주 변경되는 경우
- DocumentBuilder 이용
- Jsoup 파서
-
Java에서 HTML을 파싱하기 위해 만들어진 library
-
build.gradle(Module.app)에 의존성 추가 -> sync now
2. SAX 파서
-
event 기반 파서
-
xml 문서를 단방향 스트림( 라인 단위 )으로 취급하여 읽어들이는 중에 유효한 element가 식별되면 event를 parser의 외부로 전달, 처리 ( 사용자가 처리 )
-
+ 동작 방식 간단
-
+ 필요한 요소만 식별 시 속도 빠름
-
+ 적은 메모리 소요 ( 개발자가 의도적으로 남긴 것만 메모리에 남는다 )
-
- 그냥 지나갔던 정보를 얻고 싶을 때 다시 파싱해야하는 번거로움 ( 자유로운 탐색 x )
-
- 추가, 수정, 삭제, 이동 구현 어려움 ( event로부터 데이터를 Tree로 구조화해야하는 작업 필요 -> DOM이 훨씬 효율적 )
-
추천 : 요소의 값이 중요한 경우 ( 문서의 구조 x ), xml 문서의 구조가 간단하거나 동일한 요소가 반복되는 경우
- XML Pull 파서
- XmlPullParserFactory를 통해 XmlPullParser 인스턴스 생성하거나 newPullParser() 함수를 통해 생성
-
event 기반 파서 (= SAX 파서 )
- 안드로이드에서 기본적으로 지원되는 xml 파서 ( XmlPullParser 인터페이스 )
- XmlPullParserFactory.newPullParser() 함수를 통해 KXmlParser,
Xml.newPullParser() 함수를 통해 ExpatPullParser 생성 가능
( 둘 다 XmlPullParser을 통해 xml 파싱 관련 함수 호출 가능 ) -
모든 파싱을 하지 않고도 특정 부분까지의 파싱내용을 활용
-
+ 원하는 부분 파싱
-
- 그냥 지나갔던 정보를 얻고 싶을 때 다시 파싱해야하는 번거로움
-
- SAX 파서보다 느리다.
공공데이터 가져오기
1. ../main/res/xml/network_config.xml 생성
2. network_config.xml 내용
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">openapi.gg.go.kr/AnimalPharmacy?</domain>
</domain-config>
</network-security-config>
3. Permission 추가 - AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
4. 이후는 깃 참조 :
ERROR :
- Cleartext HTTP traffic to ~ not permitted
network_config.xml을 manifest에 등록을 안해서 생긴 오류
% in AndroidManifest.xml
<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"
android:networkSecurityConfig="@xml/network_config" > % <- 여기 추가
- DOM parser 중 url이 null으로 읽힘 -> 해결 x
System.err: org.xml.sax.SAXParseException: Unexpected token (position:TEXT https://openapi....@1:77 in java.io.StringReader@b88ccaf)
...
2021-01-20 00:37:15.788 15951-16062/com.androidapp.practiceapp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.androidapp.practiceapp, PID: 15951
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:354)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'org.w3c.dom.Element org.w3c.dom.Document.getDocumentElement()' on a null object reference
at com.androidapp.practiceapp.OpenAPIDistinct.doInBackground(OpenAPIDistinct.java:50)
at com.androidapp.practiceapp.OpenAPIDistinct.doInBackground(OpenAPIDistinct.java:21)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Jsoup에서는 이상이 없었으나 DocumentBuilder으로 적용시켰을 때 url을 null로 읽는 문제가 발생.
MainActivity에서 실행했을 때도 마찬가지였다.
- XML Pull Parser 구현 중 OpenAPIDistinct는 적절한 결과가 나오나 OpenAPI는 에러 발생
2021-01-20 02:19:53.806 25086-25239/com.androidapp.practiceapp W/System.err: org.xmlpull.v1.XmlPullParserException: Expected a quoted string (position:DOCDECL @1:50 in java.io.InputStreamReader@90995fb)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at org.kxml2.io.KXmlParser.readQuotedId(KXmlParser.java:671)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at org.kxml2.io.KXmlParser.readExternalId(KXmlParser.java:650)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at org.kxml2.io.KXmlParser.readDoctype(KXmlParser.java:591)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at org.kxml2.io.KXmlParser.next(KXmlParser.java:421)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at org.kxml2.io.KXmlParser.next(KXmlParser.java:313)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at com.androidapp.practiceapp.OpenAPI.doInBackground(OpenAPI.java:92)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at com.androidapp.practiceapp.OpenAPI.doInBackground(OpenAPI.java:14)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:333)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
2021-01-20 02:19:53.807 25086-25239/com.androidapp.practiceapp W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
2021-01-20 02:19:53.808 25086-25239/com.androidapp.practiceapp W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
2021-01-20 02:19:53.808 25086-25239/com.androidapp.practiceapp W/System.err: at java.lang.Thread.run(Thread.java:764)
위의 경우와 같은 에러 발생
async가 두 곳에서 쓰여서 그런걸까?
참고 :
openAPI 데이터 가져오기 : android55.tistory.com/5
Data Load 방법 : recipes4dev.tistory.com/134
Jsoup 관련 : offbyone.tistory.com/116
DOM parser (DocumentBuilder 관련 ) : ddangeun.tistory.com/65
blog.naver.com/PostView.nhn?blogId=javaking75&logNo=140179651659
m.blog.naver.com/qbxlvnf11/221324667993
XML Pull Parser : recipes4dev.tistory.com/134
error 관련 :
http 접속 오류 -> androidManifest.xml 추가 : developside.tistory.com/85
'개발 관련 > 안드로이드 스튜디오' 카테고리의 다른 글
[안드로이드 스튜디오] Fragment (0) | 2021.01.08 |
---|---|
[안드로이드 스튜디오] ListView (0) | 2020.12.28 |
[안드로이드 스튜디오] Drawer layout (0) | 2020.12.23 |
[안드로이드 스튜디오] 이벤트 처리 방법 - 리스너 구현 및 이벤트 핸들링 (0) | 2020.12.21 |
[안드로이드 스튜디오] 휴대폰에 개발중인 앱 설치하기 (0) | 2020.12.21 |