How do you move and store XML in a Blackberry Java application?
I am having a problem accessing the content of an XML document. My goal is this: Take the XML source and parse it into a fair equivalent of an associative array, then store it as a persistent object.
xml is pretty simple:
<root>
<element>
<category_id>1</category_id>
<name>Cars</name>
</element>
<element>
<category_id>2</category_id>
<name>Boats</name>
</element>
</root>
The main java class is below. I almost just call save (xml) after the HTTP response above. Yes, the xml is formatted correctly.
import java.io.IOException;
import java.util.Hashtable;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.Vector;
import net.rim.device.api.system.PersistentObject;
import net.rim.device.api.system.PersistentStore;
import net.rim.device.api.xml.parsers.DocumentBuilder;
import net.rim.device.api.xml.parsers.DocumentBuilderFactory;
public class database{
private static PersistentObject storeVenue;
static final long key = 0x2ba5f8081f7ef332L;
public Hashtable hashtable;
public Vector venue_list;
String _node,_element;
public database()
{
storeVenue = PersistentStore.getPersistentObject(key);
}
public void save(Document xml)
{
venue_list = new Vector();
storeVenue.setContents(venue_list);
Hashtable categories = new Hashtable();
try{
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory. newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
docBuilder.isValidating();
xml.getDocumentElement ().normalize ();
NodeList list=xml.getElementsByTagName("*");
_node=new String();
_element = new String();
for (int i=0;i<list.getLength();i++){
Node value=list.item(i).getChildNodes().item(0);
_node=list.item(i).getNodeName();
_element=value.getNodeValue();
categories.put(_element, _node);
}
}
catch (Exception e){
System.out.println(e.toString());
}
venue_list.addElement(categories);
storeVenue.commit();
}
The above code is work in progress and most likely badly flawed. However, I have been doing this for several days now. I can never get all the child nodes or a name / value pair. When I print a vector as a string, I usually get results like this: [{= root, = element}] and that's it. No "category_id", no "name"
Ideally, I would get something like [{1 = cars, 2 = boats}]
Any help is appreciated.
thanks
source to share
Here's a fixed version of your program. The changes I have made are as follows:
- I removed the DocBuilder stuff from the method
save()
. These calls are needed to create a new oneDocument
. Once you have an object like this (and you do, since it was passed as an argument), you won't need it anymoreDocumentBuilder
. The correct usage isDocumentBuilder
shown below in the methodmain
. - _node, _element doesn't have to be fields. They get new values ββwith each pass through the loop inside
save
, so I made them local variables. I also changed their names tocategory
andname
to reflect their relationship to elements in the XML document. - You should never need to create a new String object with
new String()
. Simple""
enough (see variable initializationcategory
andname
). - Instead of
"*"
iterating over everything (through ), the loop is now iterating over the elementselement
. Then there is an inner loop that iterates over the children of each element, namely its elementscategory_id
andname
. - In each pass of the internal value, we set either a variable
category
orname
depending on the node name. - The actual value set for these variables is obtained via
node.getTextContent()
, which returns stuff between the node tags.
class database
:
public class database {
private static PersistentObject storeVenue;
static final long key = 0x2ba5f8081f7ef332L;
public Hashtable hashtable;
public Vector venue_list;
public database() {
storeVenue = PersistentStore.getPersistentObject(key);
}
public void save(Document xml) {
venue_list = new Vector();
storeVenue.setContents(venue_list);
Hashtable categories = new Hashtable();
try {
xml.getDocumentElement().normalize();
NodeList list = xml.getElementsByTagName("element");
for (int i = 0; i < list.getLength(); i++) {
String category = "";
String name = "";
NodeList children = list.item(i).getChildNodes();
for(int j = 0; j < children.getLength(); ++j)
{
Node n = children.item(j);
if("category_id".equals(n.getNodeName()))
category = n.getTextContent();
else if("name".equals(n.getNodeName()))
name = n.getTextContent();
}
categories.put(category, name);
System.out.println("category=" + category + "; name=" + name);
}
} catch (Exception e) {
System.out.println(e.toString());
}
venue_list.addElement(categories);
storeVenue.commit();
}
}
Here's the main method:
public static void main(String[] args) throws Exception {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
docBuilder.isValidating();
Document xml = docBuilder.parse(new File("input.xml"));
database db = new database();
db.save(xml);
}
source to share
Thank you very much. With a few minor changes, I was able to do exactly what I was looking for.
Here are the changes I had to make: Although I'm building in 1.5, getTextContent is not available. I had to use category = n.getFirstChild (). GetNodeValue (); to get the value of each node. While there might be a simple solution such as updating my build settings, I don't know enough about BB's requirements to know when to safely deviate from the default recommended build settings.
I basically had to change this line:
Document xml = docBuilder.parse(new File("input.xml"));
so it was reading from an InputStream supplied from my webserver and not necessarily a local file, even if I'm wondering if storing a local XML file would be more efficient than storing a vector full of hash tables. ...
InputStream responseData = connection.openInputStream();
Document xmlParsed = docBuilder.parse(result);
Obviously I missed the HTTP connection part to keep this readable.
Your help saved me this whole weekend of blind debugging. Many thanks! Hope this post helps someone else too.
source to share
//res/xml/input.xml
private static String _xmlFileName = "/xml/input.xml";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream inputStream = getClass().getResourceAsStream( _xmlFileName );
Document document = builder.parse( inputStream );
source to share