问题
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
回答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;
}
}
回答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.
回答3:
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
来源:https://stackoverflow.com/questions/12448570/how-can-i-parse-such-a-document