안드로이드에서 XML 데이터 객체로 바꾸기 - XmlPullParser


원본 출처 : http://itreading.tumblr.com/post/78317598864/xml-xmlpullparser


아래는 원본에 있는 내용 그대로 입니다..


안드로이드에서 XML을 객체로 바꾸는 방법은 여러가지가 있습니다. 자바에서 제공하는 대부분의 라이브러리를 사용할 수 있는 안드로이드는 SAX, DOM 등을 사용하여 비교적 쉽게 XML을 객체로 변환할 수 있습니다. JAXB를 사용하여 seamless한 marshalling을 수행할 수 있으면 좋겠으나 안드로이드에서 직접 지원하지 않을뿐더러 모바일 환경에서 사용하기엔 조금 무거운 탓에 이상적인 구현이 아닙니다.

안드로이드 플랫폼이 추천하는 방법은 XmlPullParser를 사용하여 Xml을 객체로 변환하는 것입니다. 안드로이드 개발자 페이지와 IBM Developer Works에 비교적 간단하게 XML변환을 구현하는 방법이 있어 살짝 옮겨봤습니다.

다음과 같은 XML을 객체 리스트로 변환해 보겠습니다.

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>android_news</title>
        <description>android_news</description>
        <link>http://www.androidster.com/android_news.php</link>
        <lastBuildDate>Sun, 19 Apr 2009 19:43:45 +0100</lastBuildDate>
        <generator>FeedCreator 1.7.2</generator>
        <item>
            <title>Samsung S8000 to Run Android, Play DivX</title>
            <link>http://www.androidster.com/android_news/samsung-s8000</link>
            <description>More details have emerged on the first Samsung...</description>
            <pubDate>Thu, 16 Apr 2009 07:18:51 +0100</pubDate>
        </item>
        <item>
            <title>Android Cupcake Update on the Horizon</title>
            <link>http://www.androidster.com/android_news/android-cupcake</link>
            <description>After months of discovery and hearsay, the ...</description>
            <pubDate>Tue, 14 Apr 2009 04:13:21 +0100</pubDate>
        </item>
    </channel>
</rss>

위 XML의 item을 표현하는 Message 클래스를 만듭니다.

import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Message {
    private String title;
    private URL link;
    private String description;
    private Date date;

    // Message 클래스에 필요한 메소드를 추가합니다.
}

XML을 읽어 List<Message> 형태로 객체 리스트를 반환하는 메소드를 가진 인터페이스를 선언합니다.

import java.util.List;

public interface FeedParser {
    List<Message> parse();
}

XML 정보를 특정 url에서 읽어오는 것을 가정하고 다음과 같은 클래스를 만듭니다. 이 클래스를 상속받아 SAX, DOM, XmlPullParser등 을 사용하여 XML을 변환할 수 있게 준비합니다.

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

public abstract class BaseFeedParser implements FeedParser {
    // 읽어들일 XML 태그를 선언합니다.
    static final String PUB_DATE = "pubDate";
    static final String DESCRIPTION = "description";
    static final String LINK = "link";
    static final String TITLE = "title";
    static final String ITEM = "item";
    static final String CHANNEL = "channel";

    final URL feedUrl;

    protected BaseFeedParser(String feedUrl){
        try {
            this.feedUrl = new URL(feedUrl);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    protected InputStream getInputStream() {
        try {
            return feedUrl.openConnection().getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

XmlPullParser는 InputStream을 받아 순차적으로 정보를 쌓아 객체를 만듭니다.

import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import java.util.ArrayList;
import java.util.List;

public class XmlPullFeedParser extends BaseFeedParser {
    public XmlPullFeedParser(String feedUrl) {
        super(feedUrl);
    }

    @Override
    public List<Message> parse() {
        List<Message> messages = null;
        XmlPullParser parser = Xml.newPullParser();
        try {
            // 스트림에서 인코딩을 자동으로 인식합니다.
            parser.setInput(this.getInputStream(), null);

            int eventType = parser.getEventType();
            Message currentMessage = null;
            boolean done = false;

            while (eventType != XmlPullParser.END_DOCUMENT && !done){
                String name = null;
                switch (eventType){
                    case XmlPullParser.START_DOCUMENT:
                        // 스트림의 시작입니다. 리스트를 생성합니다.
                        messages = new ArrayList<Message>();
                        break;
                    case XmlPullParser.START_TAG:
                        // 태그를 식별한 뒤 태그에 맞는 작업을 수행합니다.
                        name = parser.getName();
                        if (name.equalsIgnoreCase(ITEM)){
                            currentMessage = new Message();
                        } else if (currentMessage != null){
                            if (name.equalsIgnoreCase(LINK)){
                                // XmlPullParser#nextText()는 String을 리턴하므로 Message 클래스에
                                // setLink(String)을 만들어 URL 객체를 생성할 수 있게 합니다. 
                                currentMessage.setLink(parser.nextText());
                            } else if (name.equalsIgnoreCase(DESCRIPTION)){
                                currentMessage.setDescription(parser.nextText());
                            } else if (name.equalsIgnoreCase(PUB_DATE)){
                                // XmlPullParser#nextText()는 String을 리턴하므로 Message 클래스에
                                // setDate(String)을 만들어 Date 객체를 생성할 수 있게 합니다.
                                currentMessage.setDate(parser.nextText());
                            } else if (name.equalsIgnoreCase(TITLE)){
                                currentMessage.setTitle(parser.nextText());
                            }
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        // 태그의 마지막을 읽었습니다. ITEM을 처리하는 중이면 리스트에 Message를 추가합니다.
                        name = parser.getName();
                        if (name.equalsIgnoreCase(ITEM) &&
                            currentMessage != null){
                            messages.add(currentMessage);
                        } else if (name.equalsIgnoreCase(CHANNEL)){
                            done = true;
                        }
                        break;
                }
                eventType = parser.next();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return messages;
    }
}

이제 XML을 url로 읽어들일 준비가 되었습니다. 이렇게 만들어진 XmlPullFeedParser를 사용하는 방법은 다음과 같습니다.

XmlPullFeedParser parser = new XmlPullFeedParser("http://www.example.com/api/xml/100");
List<Message> messages = parser.parse();


+ Recent posts