I finally finished my XML parsing code, and now looking at it, it scares me. This code is for a simple Android-based, text adventure game.
I have all my data about encounters, locations, and characters stored in XML files in the ‘res’ folder.
I coded this XML parser to go through the XML files and store data into a class called Encounter. I can then access the data inside Encounter anywhere in my code.
So I guess I got the OOP part down. But the actual parsing just looks so messy.
Is there a better way to go about parsing XML data?
Here is my code:
public class XmlParser extends Activity {
private String xmlValue;
private int encounterID;
Encounter encounter;
public XmlParser()
throws XmlPullParserException, IOException
{
XmlPullParser xpp = getResources().getXml(R.xml.encounters);
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String elName = xpp.getName();
if(eventType == XmlPullParser.START_TAG) { //creature
eventType = xpp.next();
//top level nodes
if(xpp.getName().equalsIgnoreCase("identity")){
eventType = xpp.next();
if(elName.equalsIgnoreCase("name")) {
encounter.name = xpp.getText();
} else if(elName.equalsIgnoreCase("race")) {
encounter.race = xpp.getText();
} else if(elName.equalsIgnoreCase("gender")) {
encounter.gender = xpp.getText();
} else if(elName.equalsIgnoreCase("alignment")) {
encounter.alignment = xpp.getText();
} else if(elName.equalsIgnoreCase("age")) {
try {
encounter.age = Integer.parseInt(xpp.getText());
} catch (NumberFormatException e) {
//ok
}
}
} else if (xpp.getName().equalsIgnoreCase("appearance")) {
eventType = xpp.next();
if(elName.equalsIgnoreCase("condition")){
encounter.condition = xpp.getText();
} else if(elName.equalsIgnoreCase("skinColor")) {
encounter.skinColor = xpp.getText();
} else if(elName.equalsIgnoreCase("hairColor")) {
encounter.hairColor = xpp.getText();
} else if(elName.equalsIgnoreCase("size")) {
encounter.size = xpp.getText();
} else if(elName.equalsIgnoreCase("height")) {
encounter.height = xpp.getText();
} else if(elName.equalsIgnoreCase("weight")) {
encounter.weight = xpp.getText();
}
} else if (xpp.getName().equalsIgnoreCase("stats")) {
eventType = xpp.next();
if(elName.equalsIgnoreCase("hitPoints")) {
try {
encounter.HP = Integer.parseInt(xpp.getText());
} catch (NumberFormatException e) {
//ok
}
} else if(elName.equalsIgnoreCase("armorClass")) {
try {
encounter.AC = Integer.parseInt(xpp.getText());
} catch (NumberFormatException e) {
//ok
}
} else if(elName.equalsIgnoreCase("actionPoints")) {
try {
encounter.AP = Integer.parseInt(xpp.getText());
} catch (NumberFormatException e) {
//ok
}
} else if(elName.equalsIgnoreCase("magicPoint")) {
try {
encounter.AP = Integer.parseInt(xpp.getText());
} catch (NumberFormatException e) {
//ok
}
} else if(elName.equalsIgnoreCase("strength")) {
try {
encounter.strength = Integer.parseInt(xpp.getText());
} catch (NumberFormatException e) {
//ok
}
} else if(elName.equalsIgnoreCase("dexterity")) {
try {
encounter.dexterity = Integer.parseInt(xpp.getText());
} catch (NumberFormatException e) {
//ok
}
} else if(elName.equalsIgnoreCase("intelligence")) {
try {
encounter.intelligence = Integer.parseInt(xpp.getText());
} catch (NumberFormatException e) {
//ok
}
}
} else if (xpp.getName().equalsIgnoreCase("inventory")) {
eventType = xpp.next();
if(elName.equalsIgnoreCase("weapon")) {
encounter.weapon = xpp.getText();
} else if(elName.equalsIgnoreCase("armor")) {
encounter.armor = xpp.getText();
} else if(elName.equalsIgnoreCase("magicItem")) {
encounter.magicItem = xpp.getText();
}
} else if (xpp.getName().equalsIgnoreCase("magic")) {
eventType = xpp.next();
if(elName.equalsIgnoreCase("attackSpell")) {
encounter.attackSpell = xpp.getText();
} else if(elName.equalsIgnoreCase("defenseSpell")) {
encounter.defenseSpell = xpp.getText();
}
} else if (xpp.getName().equalsIgnoreCase("treasureItems")) {
eventType = xpp.next();
if(elName.equalsIgnoreCase("item1")) {
encounter.item1 = xpp.getText();
} else if(elName.equalsIgnoreCase("item2")) {
encounter.item2 = xpp.getText();
}
}
} else if(eventType == XmlPullParser.END_TAG) {
//System.out.println("End tag "+xpp.getName());
}
eventType = xpp.next();
}
//System.out.println("End document");
}
In case anyone is interested, here is my XML file for encounters:
<?xml version="1.0" encoding="UTF-8"?>
<encounters>
<creature id="1" type="monster">
<identity>
<name></name>
<race></race>
<gender></gender>
<age></age>
<alignment></alignment>
</identity>
<appearance>
<condition></condition>
<skinColor></skinColor>
<hairColor></hairColor>
<size></size>
<height></height>
<weight></weight>
</appearance>
<stats>
<hitPoints></hitPoints>
<armorClass></armorClass>
<actionPoints></actionPoints>
<magicPoints></magicPoints>
<strength></strength>
<dexterity></dexterity>
<intelligence></intelligence>
</stats>
<inventory>
<weapon></weapon>
<armor></armor>
<magicItem></magicItem>
</inventory>
<magic>
<attackSpell></attackSpell>
<defenseSpell></defenseSpell>
</magic>
<treasureItems>
<item1></item1>
<item2></item2>
</treasureItems>
</creature>
You can check out VTD-XML, the lightweight library works
excellent with android (the larger does too, but it is much larger in filesize).
There is also the SAX-parser that comes with android.
Other than that, when I use the XmlPullParser, I usually have a map with the tagnames as keys and integers, then I can just get the value from the map and then use a simple switch, which clears up the code a bit: