There are loads of pages out there explaining XML, but I haven't found anything that addresses my particular issue. I have an XML file defining all the items for a simple game I'm working on. Since I don't want to have the entire map loaded at all times, I also don't need to have every item in the game loaded at all times either. Just the ones in the part of the map I'm working with. I understand SAX is the best method. Basically what I want to do is to have something like this:
<item>
<id>12345</id>
<name>note</name>
<weight>.1</weight>
</item>
<item>
.......
</item>
I want to write a function that can take an array of item id's(pulled from another list specific to the map I'm loading up at the time), and for each id given parse through the xml file, then when it finds an item tag whose id tag contains the id it's looking for, take the data from each tag within that item and set it to variables (id, note, and weight) that I can pass to a constructor method. This way, I'm only building and item objects that are relevant. But I'm not sure how to do this. Any help would be highly appreciated.
Edit:
Okay, I think I just about have this figured out, but still running into a problem. Here's what I have
public class SaxParsing {
public static void main(String argv[]) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
String foundName = null;
int idGiven = 101002;
boolean b_id = false;
boolean b_idToFind = false;
boolean b_name = false;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (localName.equalsIgnoreCase("id")) {
b_id = true;
}
if (localName.equalsIgnoreCase("name")) {
b_name = true;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (localName.equalsIgnoreCase("id")) {
b_id = false;
}
if (localName.equalsIgnoreCase("name")) {
b_name = false;
}
if (localName.equalsIgnoreCase("item")) {
b_idToFind = false;
}
}
public void characters(char buffer, int start, int length) throws SAXException {
if (b_id) {
String temp = new String();
temp = String.valueOf(buffer);
if (temp == Integer.toString(idGiven)) {
b_idToFind = true;
}
}
if (b_name) {
if (b_idToFind) {
foundName = new String();
foundName = String.valueOf(buffer);
}
}
}
};
saxParser.parse("path\\to\\GameItems.xml", handler);
System.out.println(foundName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Everything is working, except I can't access the variable foundName
outside of the the DefaultHandler
. NetBeans gives a "can't find symbol" error. I feel like this is a simple scope issue, but I can't seem to get it worked out.
You can't access foundName
because it is declared inside of the new DefaultHandler() { ... }
inner class.
You could move foundName
up two lines, outside of the inner class, but in order to access it inside the inner class, you'd need to make it final
, which makes it useless for what you want.
What you want is something like handler.foundName
, but handler
is declared as the type DefaultHandler
, which does not have a field named foundName
. Your inner class does have that field, but that type doesn't have a typename. There in lies your problem. The solution is to make it into a full-fledged class:
class ItemHandler extends DefaultHandler {
String foundName;
public void startElement(...) {...}
public void endElement(...) {...}
public void characters(...) {...}
}
And then you can declare handler
to be of type ItemHandler
, and gain the ability to access its fields:
ItemHandler handler = new ItemHandler();
saxParser.parse("path\\to\\GameItems.xml", handler);
System.out.println(handler.foundName);
As a side note. Your SAX processing is flawed. You are not guaranteed to get all the characters between tags <tag>yada,yada,yada</tag>
in a single call to public void characters(char[] ch, int start, int length)
(note correct signature). You should only accumulate them, and process them in the end tag. Something like:
class ItemHandler extends DefaultHandler {
int idGiven = 101002;
String foundName = null;
private StringBuilder sb = new StringBuilder();
private String item_name;
private int item_id;
@Override
public void startElement(String uri, String localName, String qName, Attributes attr) {
sb.setLength(0); // Clear the buffer
}
@Override
public void characters(char[] buffer, int start, int length) {
sb.append(buffer, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) {
switch(localName) {
case "id":
item_id = Integer.parseInt(sb.toString());
break;
case "name":
item_name = sb.toString();
break;
case "item":
if (item_id == idGiven) {
foundName = item_name;
}
break;
default:
System.err.println("Unexpected tag: "+localName);
}
sb.setLength(0); // Clear the buffer
}
}