0

I have a problem, and it would be very kind if someone could help me out :) I am trying to parse this XML file:

   <data>
    <day>
        <match>

            <team1>foo</team1>
            <team2>foo</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>

            <venue>1</venue>
            <gmt>10:00</gmt>
            <groupe>B</groupe>

        </match>

        <match>

            <team1>foo</team1>
            <team2>foo</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>

            <venue>1</venue>
            <gmt>14:00</gmt>
            <groupe>A</groupe>

        </match>
    </day>

    <day>
        <match>

            <team1>foo</team1>
            <team2>foo</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>

            <venue>1</venue>
            <gmt>10:00</gmt>
            <groupe>B</groupe>

        </match>

        <match>

            <team1>foo</team1>
            <team2>foo</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>

            <venue>1</venue>
            <gmt>14:00</gmt>
            <groupe>A</groupe>

        </match>
    </day>

</data>

But I can't figure out how to accomplish that. With my parser I can parse files like that:

<data>
    <match>

        <team1>aust</team1>
        <team2>irl</team2>

        <resultfinal></resultfinal>
        <result1></result1>
        <result2></result2>

        <venue>1</venue>
        <gmt>10:00</gmt>
        <groupe>B</groupe>

    </match>

    <match>

        <team1>ind</team1>
        <team2>afg</team2>

        <resultfinal></resultfinal>
        <result1></result1>
        <result2></result2>

        <venue>1</venue>
        <gmt>14:00</gmt>
        <groupe>A</groupe>

    </match>
</data>

But I don't know how to store the data for each <day> tag.

My XML Handler looks like this:

@Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {

        if (localName.equalsIgnoreCase("team1"))
            data.setTeam1(elementValue);
        else if (localName.equalsIgnoreCase("team2"))
            data.setTeam2(elementValue);
        else if (localName.equalsIgnoreCase("resultfinal"))
            data.setResultfinal(elementValue);
        else if (localName.equalsIgnoreCase("result1"))
            data.setResult1(elementValue);
        else if (localName.equalsIgnoreCase("result2"))
            data.setResult2(elementValue);
        else if (localName.equalsIgnoreCase("date"))
            data.setDate(elementValue);
        else if (localName.equalsIgnoreCase("venue"))
            data.setVenue(elementValue);
        else if (localName.equalsIgnoreCase("gmt"))
            data.setGmt(elementValue);

    }

    @Override
    public void startElement(String uri, String localName, String qName,
            org.xml.sax.Attributes attributes) throws SAXException {
        // TODO Auto-generated method stub
        super.startElement(uri, localName, qName, attributes);
        elementOn = true;

        if (localName.equals("data")) {
            data = new XMLGettersSetters();
        } else if (localName.equals("match")) {

        }
    }

But with that I can just only parse files like the second. How can I parse the first file and how should I store the data? I can't store it in an Arraylist.

EDIT:

I tried to build it like Don Roby suggested, but my app always crashes. Here is what I did so far:

MainActivity:

public class MainActivity extends Activity {
    XMLHandler data;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


try {
             Log.i("PARSER", "versuch!");

                /**
                 * Create a new instance of the SAX parser
                 **/

                SAXParserFactory saxPF = SAXParserFactory.newInstance();
                SAXParser saxP = saxPF.newSAXParser();
                XMLReader xmlR = saxP.getXMLReader();


                URL url = new URL("my xml file"); // URL of the XML

                /** 
                 * Create the Handler to handle each of the XML tags. 
                 **/
                 data = new XMLHandler();
                xmlR.setContentHandler(data);
                xmlR.parse(new InputSource(url.openStream()));


            } catch (Exception e) {
                System.out.println(e);
                Log.i("PARSER", "ES KLAPPT NICHT!");
            }




        TextView txt1 = (TextView) findViewById(R.id.txtview1);
        txt1.setText(data.getTournament().get(0).get(0).getTeam1().toString());

    }

XMLHandler:

public class XMLHandler extends DefaultHandler {

    private Tournament tournament;
    private TournamentDay currentDay;
    private Match currentMatch;
    private StringBuilder builder;

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {

        if (qName.equalsIgnoreCase("team1"))
            currentMatch.setTeam1(builder.toString());
        else if (qName.equalsIgnoreCase("team2"))
            currentMatch.setTeam2(builder.toString());
        else if (qName.equalsIgnoreCase("resultfinal"))
            currentMatch.setResultfinal(builder.toString());
        else if (qName.equalsIgnoreCase("result1"))
            currentMatch.setResult1(builder.toString());
        else if (qName.equalsIgnoreCase("result2"))
            currentMatch.setResult2(builder.toString());
        else if (qName.equalsIgnoreCase("venue"))
            currentMatch.setVenue(builder.toString());
        else if (qName.equalsIgnoreCase("gmt"))
            currentMatch.setGmt(builder.toString());
        else if (qName.equals("match"))
            currentDay.add(currentMatch);
        else if (qName.equals("day"))
            tournament.add(currentDay);
    }

    @Override
    public void startElement(String uri, String localName, String qName,
                             org.xml.sax.Attributes attributes) throws SAXException {
        if (qName.equals("data")) {
            tournament = new Tournament();
        }
        if (qName.equals("day")) {
            currentDay = new TournamentDay();
        }
        else if (qName.equals("match")) {
            currentMatch = new Match();
        }
        else {
            builder = new StringBuilder();
        }
    }

    @Override
    public void characters(char[] chars, int start, int length) throws SAXException {
        builder.append(chars, start, length);
    }

    public Tournament getTournament() {
        return tournament;
    }
}

Tournament:

public class Tournament {

    private List<TournamentDay> days;

    public Tournament() {
        this.days = new ArrayList<TournamentDay>();
    }

    public void add(TournamentDay day) {
        days.add(day);
    }
    public TournamentDay get(int i) {
       return days.get(i); 
    }
}

Match:

public class Match {
    private String team1;
    private String team2;
    private String resultfinal;
    private String result1;
    private String result2;
    private String date;
    private String venue;
    private String gmt;

    public String getTeam1() {
        return team1;
    }

    public void setTeam1(String team1) {
        this.team1 = team1;
    }

    public String getTeam2() {
        return team2;
    }

    public void setTeam2(String team2) {
        this.team2 = team2;
    }

    public String getResultfinal() {
        return resultfinal;
    }

    public void setResultfinal(String resultfinal) {
        this.resultfinal = resultfinal;
    }

    public String getResult1() {
        return result1;
    }

    public void setResult1(String result1) {
        this.result1 = result1;
    }

    public String getResult2() {
        return result2;
    }

    public void setResult2(String result2) {
        this.result2 = result2;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getVenue() {
        return venue;
    }

    public void setVenue(String venue) {
        this.venue = venue;
    }

    public String getGmt() {
        return gmt;
    }

    public void setGmt(String gmt) {
        this.gmt = gmt;
    }

}

And finally my XML file:

<data>
    <day>

        <match>

            <team1>ind</team1>
            <team2>afg</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>
            <date>19.09</date>
            <venue>1</venue>
            <gmt>14:00</gmt>


        </match>

        <match>

            <team1>eng</team1>
            <team2>afg</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>

            <date>21.09</date>
            <venue>1</venue>
            <gmt>14:00</gmt>


        </match>
        <match>

            <team1>ind</team1>
            <team2>eng</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>
            <date>23.09</date>
            <venue>2</venue>
            <gmt>10:00</gmt>


        </match>
    </day>
    <day>
        <match>

            <team1>aust</team1>
            <team2>irl</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>
            <date>19.08</date>
            <venue>1</venue>
            <gmt>10:00</gmt>


        </match>
        <match>

            <team1>aust</team1>
            <team2>west</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>
            <date>22.09</date>
            <venue>1</venue>
            <gmt>14:00</gmt>


        </match>
        <match>

            <team1>west</team1>
            <team2>irl</team2>

            <resultfinal></resultfinal>
            <result1></result1>
            <result2></result2>

            <date>24.09</date>
            <venue>1</venue>
            <gmt>14:00</gmt>


        </match>

    </day>

</data>

Edit2: Here is the logcat:

09-17 15:26:49.299: I/System.out(3392): java.lang.NullPointerException
09-17 15:26:49.299: I/PARSER(3392): ES KLAPPT NICHT!
09-17 15:26:49.299: D/AndroidRuntime(3392): Shutting down VM
09-17 15:26:49.299: W/dalvikvm(3392): threadid=1: thread exiting with uncaught exception (group=0xb40a64f0)
09-17 15:26:49.299: I/Process(3392): Sending signal. PID: 3392 SIG: 9
09-17 15:26:49.299: D/AndroidRuntime(3392): procName from cmdline: com.example.xmldownloader
09-17 15:26:49.299: E/AndroidRuntime(3392): in writeCrashedAppName, pkgName :com.example.xmldownloader
09-17 15:26:49.299: D/AndroidRuntime(3392): file written successfully with content: com.example.xmldownloader StringBuffer : ;com.example.xmldownloader
09-17 15:26:49.299: E/AndroidRuntime(3392): FATAL EXCEPTION: main
09-17 15:26:49.299: E/AndroidRuntime(3392): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.xmldownloader/com.example.xmldownloader.MainActivity}: java.lang.NullPointerException
09-17 15:26:49.299: E/AndroidRuntime(3392):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1698)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1726)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:949)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at android.os.Handler.dispatchMessage(Handler.java:99)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at android.os.Looper.loop(Looper.java:130)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at android.app.ActivityThread.main(ActivityThread.java:3770)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at java.lang.reflect.Method.invokeNative(Native Method)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at java.lang.reflect.Method.invoke(Method.java:507)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:880)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:638)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at dalvik.system.NativeStart.main(Native Method)
09-17 15:26:49.299: E/AndroidRuntime(3392): Caused by: java.lang.NullPointerException
09-17 15:26:49.299: E/AndroidRuntime(3392):     at com.example.xmldownloader.MainActivity.onCreate(MainActivity.java:58)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
09-17 15:26:49.299: E/AndroidRuntime(3392):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1662)
09-17 15:26:49.299: E/AndroidRuntime(3392):     ... 11 more
Ahmad
  • 69,608
  • 17
  • 111
  • 137

3 Answers3

2

A good practice is to use an object model that reflects your XML schema. Something like this: an object called Day which contains a Collection of Matches, which contains 8 fields (team1, team2, result1, and so on).

With that model, all what your parser have to do is to build the object during the parse process.

And with that you can also use some great frameworks build just to convert XML files to java objects, like XStream.

Gilberto Torrezan
  • 5,113
  • 4
  • 31
  • 50
1

Try using the DOM parser, you will get access to any part of the Object Model tree flawlessly.....

If you want more control on it, try the below mentioned XML parser....

- JAXP AND JAXB

- Castor

Kumar Vivek Mitra
  • 33,294
  • 6
  • 48
  • 75
1

Gilberto's advice to make the object model reflect the XML schema is good.

In my interpretation of your domain, I've created a class Match that is more or less your XMLGettersSetters, a class Day which just contains a List<Match>, and a class Tournament which contains a List<Day>.

You can of course just represent the whole mess as a List<List<Match>>, but it's a bit nicer to encapsulate these in your own classes.

I had to change all your references to localName to use qName instead, which may just reflect a screwup in my testing, but this approximately works and should give the idea of how you can handle this kind of structure.

The classes listed above are pretty trivial, but here they are.

Tournament and TournamentDay are just wrappers around lists:

public class Tournament {

    private List<TournamentDay> days;

    public Tournament() {
        this.days = new ArrayList<TournamentDay>();
    }

    public void add(TournamentDay day) {
        days.add(day);
    }
}

public class TournamentDay {

    private List<Match> matches;

    public TournamentDay() {
        this.matches = new ArrayList<Match>();
    }

    public void add(Match match) {
        matches.add(match);
    }
}

Matcher is just a class with a bunch of String fields and setters for them. In real use, you might also want getters, and may not want all the fields to be Strings.

public class Match {
    private String gmt;
    private String team1;
    private String team2;
    private String venue;
    private String result1;
    private String result2;
    private String resultfinal;

    public void setGmt(String s) {
        gmt = s;
    }

    public void setVenue(String s) {
        venue = s;
    }

    public void setResult2(String s) {
        result2 = s;
    }

    public void setResult1(String s) {
        result1 = s;
    }

    public void setResultfinal(String s) {
        resultfinal = s;
    }

    public void setTeam2(String s) {
        team2 = s;
    }

    public void setTeam1(String s) {
        team1 = s;
    }
}

And the handler class to build this structure should look something like this, with a getTournament() method to retrieve the result after the parse.

public class TournamentHandler extends DefaultHandler {

    private Tournament tournament;
    private TournamentDay currentDay;
    private Match currentMatch;
    private StringBuilder builder;

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {

        if (qName.equalsIgnoreCase("team1"))
            currentMatch.setTeam1(builder.toString());
        else if (qName.equalsIgnoreCase("team2"))
            currentMatch.setTeam2(builder.toString());
        else if (qName.equalsIgnoreCase("resultfinal"))
            currentMatch.setResultfinal(builder.toString());
        else if (qName.equalsIgnoreCase("result1"))
            currentMatch.setResult1(builder.toString());
        else if (qName.equalsIgnoreCase("result2"))
            currentMatch.setResult2(builder.toString());
        else if (qName.equalsIgnoreCase("venue"))
            currentMatch.setVenue(builder.toString());
        else if (qName.equalsIgnoreCase("gmt"))
            currentMatch.setGmt(builder.toString());
        else if (qName.equals("match"))
            currentDay.add(currentMatch);
        else if (qName.equals("day"))
            tournament.add(currentDay);
    }

    @Override
    public void startElement(String uri, String localName, String qName,
                             org.xml.sax.Attributes attributes) throws SAXException {
        if (qName.equals("data")) {
            tournament = new Tournament();
        }
        if (qName.equals("day")) {
            currentDay = new TournamentDay();
        }
        else if (qName.equals("match")) {
            currentMatch = new Match();
        }
        else {
            builder = new StringBuilder();
        }
    }

    @Override
    public void characters(char[] chars, int start, int length) throws SAXException {
        builder.append(chars, start, length);
    }

    public Tournament getTournament() {
        return tournament;
    }
}
Don Roby
  • 40,677
  • 6
  • 91
  • 113
  • thank you very much, that was eactly what I was looking for :) – Ahmad Sep 16 '12 at 19:13
  • Can you please explain, how to create these List and List(the classes Tournament and Match ) and how I can retrieve the data? :) – Ahmad Sep 16 '12 at 21:17
  • Does the app give a stacktrace when it crashes? If so, including that might help. – Don Roby Sep 17 '12 at 17:25
  • Looking at your code for the activity, I see you're creating a new XMLHandler after the parse. You need to hold on to the one that's actually used in the parse and pull the result out of that. – Don Roby Sep 17 '12 at 17:41