0

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?

Rok Rovan
  • 23
  • 5

2 Answers2

0

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;
colens
  • 467
  • 3
  • 12
  • Thank you for replying, but sadly this does nothing, since values inside tags/tag/name are also at depth 4. – Rok Rovan Jan 16 '18 at 23:50
  • Sorry, my bad. I overseen the name tag inside tags/tag. Please check if the alternative solution does the job. – colens Jan 17 '18 at 07:17
0

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();
}
colens
  • 467
  • 3
  • 12
  • I tried this and it still logged all the 22 tag values to the console. When I try to parse it through to a ListView I get **Attempt to invoke virtual method 'void XmlTracks.setTrackName(java.lang.String)' on a null object reference**. I have given up on finding an elegant solution, so I basically added all 22 values to a string array and used `for (int i = 0; i tags found in the xml, and looped through the values only parsing every second entry. It's not the best solution, but works since I use this parser for tracks only. – Rok Rovan Jan 17 '18 at 11:57
  • Sorry, again I've maid a mistake. Look at the code, it should work now! – colens Jan 17 '18 at 19:08