Android Studio Java XmlPullParser how to get only certain tag values

1k views Asked by At

I'm having trouble parsing some xml tags. I'm very new to Android development and I'm still struggling with basics.

I'm sorry if this post is sort of hard to read.

I want to read the following XML file that I download:

    <lfm status="ok">
    <album>
        <name>Now, Diabolical</name>
        <artist>Satyricon</artist>
        <mbid>28d51e3f-b12c-4948-b35b-c1f5aae76ed2</mbid>
        <image size="">...</image>
        <listeners>131741</listeners>
        <playcount>2876007</playcount>
        <tracks>
            <track rank="1">
                <name>Now, Diabolical</name>
                <url>...</url>
                <duration>367</duration>
                <streamable fulltrack="0">0</streamable>
                <artist>
                    <name>Satyricon</name>
                    <mbid>8eed05a5-e9a1-4dda-8b33-e354c4ecc8b6</mbid>
                    <url>https://www.last.fm/music/Satyricon</url>
                </artist>
            </track>
            <track rank="2">
                <name>K.I.N.G.</name>
                <url>https://www.last.fm/music/Satyricon/_/K.I.N.G.</url>
                <duration>216</duration>
                <streamable fulltrack="0">0</streamable>
                <artist>
                    <name>Satyricon</name>
                    <mbid>8eed05a5-e9a1-4dda-8b33-e354c4ecc8b6</mbid>
                    <url>https://www.last.fm/music/Satyricon</url>
                </artist>
            </track>
        </tracks>
        <tags>
            <tag>
                <name>black metal</name>
                <url>https://www.last.fm/tag/black+metal</url>
            </tag>
            <tag>...</tag>
            <tag>...</tag>
        </tags>
    </album>
</lfm>

I read it with my XmlPullParser class:

try {
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xpp = factory.newPullParser();

            FileInputStream fis = ctx.openFileInput("AlbumInfo.xml");

            BufferedReader reader = new BufferedReader(new InputStreamReader(fis));

            xpp.setInput(reader);

            int eventType = xpp.getEventType();

            while (eventType != XmlPullParser.END_DOCUMENT) {
                String tagName = xpp.getName();

                switch (eventType) {
                    case XmlPullParser.START_TAG:
                        if (tagName.equalsIgnoreCase("track")) {
                            currentXmlAlbumTrack = new XmlTracks();
                        }
                        break;

                    case XmlPullParser.TEXT:
                        curText = xpp.getText();
                        break;

                    case XmlPullParser.END_TAG:
                        if (tagName.equals("track")) {
                            xmlTrackItems.add(currentXmlAlbumTrack);
                        } else if (tagName.equals("name")) {
                            currentXmlAlbumTrack.setTrackName(curText);
                            Log.d("tag","name: " + curText);
                        } else if (tagName.equalsIgnoreCase("url")) {
                            //TODO
                        } else if (tagName.equalsIgnoreCase("duration")){
                            //TODO
                        }
                        break;

                    default:
                        break;

                }
                eventType = xpp.next();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

I only want to parse the name tags that are inside of each track tag.

So basically I want to parse all the track names (8 of them) into a ListView, but when I use currentXmlAlbumTrack.setTrackName(curText); it tries to output every name tag inside the XML file, like this:

D/tag: name text: Now, Diabolical
D/tag: name text: Now, Diabolical
D/tag: name text: Satyricon
D/tag: name text: K.I.N.G.
D/tag: name text: Satyricon
D/tag: name text: The Pentagram Burns
D/tag: name text: Satyricon
D/tag: name text: A New Enemy
D/tag: name text: Satyricon
D/tag: name text: The Rite of Our Cross
D/tag: name text: Satyricon
D/tag: name text: That Darkness Shall Be Eternal
D/tag: name text: Satyricon
D/tag: name text: Delirium
D/tag: name text: Satyricon
D/tag: name text: To the Mountains
D/tag: name text: Satyricon
D/tag: name text: black metal
D/tag: name text: albums I own
D/tag: name text: Black n Roll
D/tag: name text: Norwegian Black Metal
D/tag: name text: metal

Is there any way to avoid this without completely rewriting the parser?

2

There are 2 answers

2
colens On

You could try with getDepth() https://developer.android.com/reference/org/xmlpull/v1/XmlPullParser.html#getDepth()

It returns the depth of an element, so for the name you are interested in, the depth should be 4, since the root depth is 1. It takes just a minor change to your code in the last case statment, checking the depth with xpp.getDepth()==4:

                    case XmlPullParser.END_TAG:
                    if (tagName.equals("track")) {
                        xmlTrackItems.add(currentXmlAlbumTrack);
                    } else if (tagName.equals("name") && xpp.getDepth()==4) {
                        currentXmlAlbumTrack.setTrackName(curText);
                        Log.d("tag","name: " + curText);
                    } else if (tagName.equalsIgnoreCase("url")) {
                        //TODO
                    } else if (tagName.equalsIgnoreCase("duration")){
                        //TODO
                    }
                    break;
2
colens On

Alternative solution would be to add a flag that is raised when a track tag is found, cleared at the end of track tag and checked at the name tag:

try {
    XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    XmlPullParser xpp = factory.newPullParser();

    FileInputStream fis = ctx.openFileInput("AlbumInfo.xml");

    BufferedReader reader = new BufferedReader(new InputStreamReader(fis));

    xpp.setInput(reader);

    int eventType = xpp.getEventType();

    // add flag to distinguish parent tag
    bool isTrack=false;

    while (eventType != XmlPullParser.END_DOCUMENT) {
        String tagName = xpp.getName();

        switch (eventType) {
            case XmlPullParser.START_TAG:

                // WRONG PLACE, IT SHOULD BE INSIDE IF !!!
                // isTrack=true; // <track> tag found

                if (tagName.equalsIgnoreCase("track")) {
                    currentXmlAlbumTrack = new XmlTracks();

                    isTrack=true; // <track> tag found

                }
                break;

            case XmlPullParser.TEXT:
                curText = xpp.getText();
                break;

            case XmlPullParser.END_TAG:
                if (tagName.equals("track")) {

                    isTrack=false; // </track> end tag found

                    xmlTrackItems.add(currentXmlAlbumTrack);
                } else if (tagName.equals("name") && isTrack) {
                    currentXmlAlbumTrack.setTrackName(curText);
                    Log.d("tag","name: " + curText);
                } else if (tagName.equalsIgnoreCase("url")) {
                    //TODO
                } else if (tagName.equalsIgnoreCase("duration")){
                    //TODO
                }
                break;

            default:
                break;

        }
        eventType = xpp.next();
    }
} catch (Exception e) {
    e.printStackTrace();
}