Things take time

[Android] XML Parsing, URL로부터 XML 파싱하기(RSS 데이터) 본문

Android(기능)

[Android] XML Parsing, URL로부터 XML 파싱하기(RSS 데이터)

겸손할 겸 2019. 7. 5. 13:49

[개요]

 

날씨를 알려주는 앱, 공공기관에서 준 데이터를 바탕으로 정보를 알려주는 앱들은 각 기상청, 공공기관에서 제공하는 데이터를 받아서 그것을 업데이트 하며 사용자에게 UI를 예쁘게 입혀 보여준다.

 

이것을 간단히 구현해본다.

 

[티스토리]

 

글 쓴 날 기준으로 티스토리에 들어오게 되면 보이는 화면

현재 내 티스토리의 메인화면이다.

나는 여기서 저 제목들만 뽑아서 리스트에 보이고 싶은 것이다.

 

여기서 RSS라는 개념이 들어가는데, RSS란 기본적으로 각 사이트에서 해당 정보를 제공해줘야만(조건) 얻을 수 있는 데이터로써, XML의 데이터 타입으로 얻어진다.

 

그래서 RSS피드 구독 이란 개념이 있는 것이다. 조건에서처럼 모든 사이트에서 제공하는 것은 아니다.

 

참고 : http://mwultong.blogspot.com/2007/10/rss-rss-feed.html

 

RSS란? RSS피드란 무엇인가요? 사이트 피드(Feed)의 뜻, 의미

 

mwultong.blogspot.com

티스토리에서도 제공하게 되는데 예를 들어, 현재 티스토리는 주소 끝에 /rss를 붙이면 아래와 같은 데이터가 제공된다.

https://g-y-e-o-m.tistory.com/rss

 

익숙해 보이는 방식,

이처럼 XML은 HTML처럼 트리구조를 지닌다.

 

여기서 중요한 <>안의 값들을 추출하는 것이다. 이런 URL들은 각 사이트에서 제공해주므로, 이 값들은 당연히 사전에 알아야 한다.

 

[소스]

 

public class OKXmlParser extends AsyncTask<String, Void, Document> {

    Context mContext;

    public OKXmlParser(Context context){
        this.mContext = context;
    }
    @Override
    protected Document doInBackground(String... strings) {
        URL url;
        Document doc = null;
        try{
            url = new URL(strings[0]);
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            doc = db.parse(new InputSource(url.openStream()));
            doc.getDocumentElement().normalize();
        }catch (Exception e){
            Toast.makeText(mContext, e.toString(), Toast.LENGTH_SHORT).show();
        }
        return doc;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Document doc) {
        super.onPostExecute(doc);
        NodeList itemNodeList = doc.getElementsByTagName("item");

        for(int i=0; i<itemNodeList.getLength(); i++){
            Node node = itemNodeList.item(i);
            Element element = (Element) node;

            NodeList titleNodeList = element.getElementsByTagName("title");
            String title = titleNodeList.item(0).getChildNodes().item(0).getNodeValue();
            Log.e("title", title);
        }
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
    }
}

소스가 어렵지 않다.

해당 작업은 UI까지 건드려야하므로(위 예제에는 UI에 대한건 없다, 이너클래스로 사용하던, 생성자로 받던 그건 자유) 통신 및 UI작업, 메인쓰레드를 위해 Async를 사용한다.

 

Async의 첫 번째 인자(String)는 doInBackground의 매개변수이므로 URL이 적합하다.

그리고 DocumentBuilderFactory클래스를 사용하여 해당 페이지를 Document타입으로 만든 뒤, onPostExecute에게 전달한다.(Async의 세 번째 인자)

 

그리고 post에서는 해당 Document를 NodeList로 나눈뒤 각 노드 값을 얻어내면 된다.

여기서 document의 getElemetsByTagName에 들어가는 "값" 은 해당 태그를 지닌 부분을 다 찾게 된다.

 

즉, 첨부에 올린 XML에서 item태그들을 모두 찾아 저장시킨다.

그리고 item안에는 title, url, link, description 등의 태그가 있으므로 여기서 title이란 태그를 따와 리스트로 다시 바꾼뒤 getNodeValue()를 하면 된다.

 

결과 로그, title만 뽑아낸 결과다.

그럼 정상적으로 얻어올 수 있게 된다. 이 값들을 바탕으로 리스트 뷰에 그리던, UI작업을 하는 등의 후속 작업을 수행하면 끝

 

[참고]

 

구글링을통해 XML 파싱에 대해 조사하면 DocumentBuilderFactory클래스 말고도 XmlPullParserFactory라던지 여러 클래스가 있다. 그래서 조금은 헛갈릴 수 있지만, 각각 XML을 어떤 방식으로 파싱하겠는지에 따른 방법에 대한 차이다.

 

위의 예제는 흔히 DOM형식 파싱을 한 결과고, 이 외에도 SAX Parser, XmlPull Parser가 있다. 각기 방법에 따라 장,단점이 다르다. 그러나 사용하는 알고리즘이 동일하고 함수명만 달라지는 정도이므로, 상황에 맞게 키워드만 알면 구글링해서 따라해보면 간단하다.

 

참고 사이트 : https://dpdpwl.tistory.com/24

파싱 종류 예제 : http://blog.naver.com/PostView.nhn?blogId=javaking75&logNo=140179651659