[컴][안드로이드] rss feed atom parser

sax parser / atom parser / atom parser with sax parser



ATOM feed


android 에서 rss feed 의 parser 로 sax parser 를 사용하고 있다. 그런데 ATOM feed 를 parse 하는 데에도 쓰고 싶어서, 기존의 rss feed 와 같은 방식으로 사용을 해봤는데, 이상하게 children 이 보이지 않았다.

그런데, 아래 link 에서 해결책을 찾았다.

기존의 rss feed 를 parsing 할 때는 바로 tag name 을 적어주면 됐다.

 RootElement root = new RootElement("feed");
 Element entry = root.getChild("entry");


그런데 ATOM 을 처리할 때는 uri 를 넣어줘야 한다. xml 의 parsing 을 위한 namespace 를 지정해 주는 듯 하다.

static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";
 RootElement root = new RootElement(ATOM_NAMESPACE, "feed");
 Element entry = root.getChild(ATOM_NAMESPACE, "entry");


Content Handler

ref. 1 에서 SAX parser(Expat Parser) 를 사용하는 방법을 알려준다. 위에서 이야기 한 부분도 Sax parser 를 사용하고, RootElement 를 사용해서 parser 부분에서 사용하는 contentHandler 를 정의한 것이었지만,

ref. 1 에서는 DefaultHandler를 상속받아서 자신만의 contentHandler 를 만들어 사용한다.






XmlPullParser

XmlPullParser 를 사용하고 싶으면 아래 예제를 보고 따라하자.
좀 더 간단하고, XmlPullParserFactory 를 이용하는 예제는 see also. 2 에서 확인할 수 있다.


주의할점

보통 network 에서 Url을 통해 Rss 에 대한 InputStream 을 가져오기 때문에 이녀석을 바로 XmlPullParser.setInput 의 InputStream 으로 넘겨주게 된다. 대부분의 경우 문제가 없지만, GZIPInputStream 으로 오는 경우에 XmlPullParser 내부에서 제대로 읽지 못하는 듯 하다. 이때는 String 으로 변환해서 StringReader 를 이용해서 넘겨줄 수 있다.

MainActivity.java

InputStream is = getInputStream(XML_FEED_URL);

PodXmlParser parser = new PodXmlParser(MAX_ITEM);
entries = parser.parse(is);



PodXmlParser.java

package com.grabeco.podlist;

/**
 * Created with IntelliJ IDEA.
 * User: namh
 * Date: 13. 9. 13
 * Time: 오후 10:32
 * To change this template use File | Settings | File Templates.
 */


import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class PodXmlParser implements Runnable {


    /**
     * XML parser
     * http://developer.android.com/training/basics/network-ops/xml.html
     */

    private static final String ns = null;  // namespace

    private static final String FEED_TAG = "rss";
    private static final String CHANNEL_TAG = "channel";
    private static final String ENTRY_TAG = "item";

    private static final String ENCLOSURE_TAG = "enclosure";
    private static final String PUBDATE_TAG = "pubDate";
    private static final String TITLE_TAG = "title";

    private static final int ITEM_LIMIT_MAX = 1000;
    private int mLimit = ITEM_LIMIT_MAX;

    private static final String SEQ_ID_TAG = "SeqID";
    private static final String Uno_TAG = "Uno";
    private static final String UserID_TAG = "UserID";
    private static final String USER_NAME_TAG = "UserNm";
    private static final String COMMENT_TAG = "Comment";
    private static final String REG_DATE_TAG = "RegDate";
    private static final String Rank_TAG = "Rank";



    public PodXmlParser(int limit) {
        mLimit = limit;
    }

    /**
     * This parser for the podcast feed
     * itunes xml example : http://minicast.imbc.com/PodCast/pod.aspx?code=1000671100000100000
     *
     * @param in
     * @return {@link List}
     * @throws XmlPullParserException
     * @throws IOException
     */
    public List parse(InputStream in) throws XmlPullParserException, IOException {
        try {
            XmlPullParser parser = Xml.newPullParser();
            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
            parser.setInput(in, null);
            parser.nextTag();
            return readFeed(parser);
        } finally {
            in.close();
        }
    }


    private List readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {

        List entries = null;

        parser.require(XmlPullParser.START_TAG, ns, FEED_TAG);
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            String name = parser.getName();
            // Starts by looking for the entry tag
            if (name.equals(CHANNEL_TAG)) {
                entries = readChannel(parser);
            } else {
                skip(parser);
            }
        }
        return entries;
    }

    private List readChannel(XmlPullParser parser) throws IOException, XmlPullParserException {

        PodItemList entries = new PodItemList();

        int count = 0;
        parser.require(XmlPullParser.START_TAG, ns, CHANNEL_TAG);
        while (count < mLimit
                && parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            String name = parser.getName();

            if (name.equals(ENTRY_TAG)) {
                entries.add(readEntry(parser));
                count++;
            } else {
                skip(parser);
            }
        }
        return entries;
    }



    // Parses the contents of an entry. If it encounters a username, comment, or regdate tag, hands them
    // off
    // to their respective &quot;read&quot; methods for processing. Otherwise, skips the tag.
    private PodRssItem readEntry(XmlPullParser parser) throws XmlPullParserException, IOException {

        parser.require(XmlPullParser.START_TAG, ns, ENTRY_TAG);

        String title = null;
        String podUrl = null;
        String pubDate = null;

        int count = 0;

        while (parser.next() != XmlPullParser.END_TAG) {

            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            String name = parser.getName();

            if (name.equals(TITLE_TAG)) {
                title = readTitle(parser);
            } else if (name.equals(ENCLOSURE_TAG)) {
                podUrl = readEnclosure(parser);
            } else if (name.equals(PUBDATE_TAG)) {
                pubDate = readPubDate(parser);
            } else {
                skip(parser);
            }
        }
        return new PodRssItem(title, podUrl, pubDate);
    }

    private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
        parser.require(XmlPullParser.START_TAG, ns, TITLE_TAG);
        String title = readText(parser);
        parser.require(XmlPullParser.END_TAG, ns, TITLE_TAG);

        return title;
    }

    private String readPubDate(XmlPullParser parser) throws IOException, XmlPullParserException {

        parser.require(XmlPullParser.START_TAG, ns, PUBDATE_TAG);
        String date = readText(parser);
        parser.require(XmlPullParser.END_TAG, ns, PUBDATE_TAG);

        return date;

    }


    // Processes link tags in the feed.
    private String readEnclosure(XmlPullParser parser) throws IOException, XmlPullParserException {

        parser.require(XmlPullParser.START_TAG, ns, ENCLOSURE_TAG);
        String tag = parser.getName();
        String podUrl = parser.getAttributeValue(null, "url");
        parser.nextTag();
        parser.require(XmlPullParser.END_TAG, ns, ENCLOSURE_TAG);
        return podUrl;
    }


    // For the tags username and comment, extracts their text values.
    private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
        String result = "";
        if (parser.next() == XmlPullParser.TEXT) {
            // CDATA is also treated, here.
            result = parser.getText();
            parser.nextTag();
        }
        return result;
    }


    // Skips tags the parser isn't interested in. Uses depth to handle nested tags. i.e.,
    // if the next tag after a START_TAG isn't a matching END_TAG, it keeps going until it
    // finds the matching END_TAG (as indicated by the value of "depth" being 0).
    private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
        if (parser.getEventType() != XmlPullParser.START_TAG) {
            throw new IllegalStateException();
        }
        int depth = 1;
        while (depth != 0) {
            switch (parser.next()) {
                case XmlPullParser.END_TAG:
                    depth--;
                    break;
                case XmlPullParser.START_TAG:
                    depth++;
                    break;
            }
        }
    }


    //--------------------------------------------------------
    @Override
    public void run() {
        //this.parse();
    }


    //--------------------------------------------------------
//    public List<PodRssItem> getMessages(){
//        return this.messages;
//    }


}

See Also

  1. [컴][안드로이드] 간단한 rss feed parser
  2. XmlPullParser | Android Developers



References

  1. http://www.ibm.com/developerworks/opensource/library/x-android/index.html

댓글 없음:

댓글 쓰기