Saturday, September 19, 2009

XML parsing on different mobile platforms (J2ME, Android, iPhone)

Before writing this post, I was thinking that there is a big difference between parsing xml in different mobile platforms (J2ME, Android, iPhone) but it appeared that they are much similar to each other.

The following is the file that is to be parsed in that tutorial

---------------
<xml>
<data id="5</data>
<name>Forrest</name>
<age>25</age>
<username>forrestgrant</username>
</data>
</xml>
------------------
J2ME

To be able to parse xml in J2ME you will need to add Kxml.zip to your project resource files because parsing xml in J2ME requires XmlParser which is not available in the default J2ME package.
To start parsing XML in J2ME you created XmlParser object, give it a reader object from the string, file, URL or whatever you are trying to read from, Then you start using that parser to get something called ParseEvents which contains type, name, text.

Type is used to know type of the current tag, the parser is handling whether it is
Xml.START_DOCUMENT:
Indication that parser has just started parsing the xml document.
Xml.START_TAG
Indicates the parser is current handling a starting tag.

More tags and its usage can be found here.

Name is used to get the tag name of the current node that is being parsed.
Text is used to get the get the string value within the current node you parsing.

Sample J2ME code
Creating XMLParser For String

byte[] xmlByteArray = xmlString.getBytes();
ByteArrayInputStream xmlStream = new ByteArrayInputStream(xmlByteArray);
InputStreamReader xmlReader = new InputStreamReader(xmlStream);
XmlParser parser = new XmlParser(xmlReader);

Iterating Over XML Tree

boolean isParsing = true;
while(isParsing)
{
pe = parser.read();
switch (pe.getType())
{
case Xml.START_TAG:
tagName = pe.getName();
if(tagName.equals("data"))
{
Attribute id = pe.getAttribute("id");
System.out.println("id value = "+id.getValue());
}
if(tagName.equals("name"))
{
pe = parser.read();
tagValue = pe.getText();
System.out.println("name value = "+tagValue);
}
else if(tagName.equals("age"))
{
pe = parser.read();
tagValue = pe.getText();
System.out.println("age value = "+tagValue);
}
else if(tagName.equals("username"))
{
pe = parser.read();
tagValue = pe.getText();
System.out.println("username value = "+tagValue);
}
break;
case Xml.END_TAG:
tagName = pe.getName();
if(tagName.equals("data"))
{
isParsing = false;
}
break;
}
}
Android

The main difference parsing xml in J2ME and Android is the following
  1. The xml parsing library is already available in the Android SDK , so you don’t have to download anything.
  2. The navigation through the xml Tree, is done automatically, you only state your Parser handler class, all xml event are sent to that class whether it is start document , tag, end document or tag or whatever, so to be able to parser XML in Android, you first need to create You XML handler class which extends DefaultHandler class where you override the method you are going to write your handler within it.
Sample Android Code
Creating XMLParser For String

SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();

/* Get the XMLReader of the SAXParser we created. */
XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader*/
MYXMLParser myExampleHandler = new MYXMLParser();
xr.setContentHandler(myExampleHandler);
byte[] xmlByteArray = xmlString.getBytes();
ByteArrayInputStream xmlStream = new ByteArrayInputStream(xmlByteArray);
InputStreamReader xmlReader = new InputStreamReader(xmlStream);
xr.parse(new InputSource(xmlReader));

My XML handler Example

public class MYXMLParser extends DefaultHandler{
private String textBetween;

@Override
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
if(localName.equals("data"))
{
String id = attributes.getValue("id");
System.out.println("id value = "+id);
}
textBetween = "";
}
@Override
public void characters(char ch[], int start, int length) {
textBetween += new String(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String name)
throws SAXException {
if(localName.equals("name") ||localName.equals("age") || localName.equals("username"))
System.out.println(localName+" value = "+textBetween);
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}

}

iPhone (Objective C)

Parsing XML in that SDK is identical to parsing XML in Android , the only difference here is that you optionally implement NSXMLParserDelegate, after identifying the delegate you will receive the events in the NSXMLParserDelegate methods like


- (void)parserDidStartDocument:(NSXMLParser *)parser
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
and other methods

Creating XMLParser For String

NSXMLParser* mParser = [[NSXMLParser alloc] initWithData:[xmlString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];
[mParser setDelegate:self];
BOOL success = [mParser parse];

Handling XML Events

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if([elementName isEqual:@"data"])
{
NSString* value = [attributeDict objectForKey:@"id"];
NSLog([NSString stringWithFormat:@"id value = %@",value]);
}
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (!currentStringValue) {
// currentStringValue is an NSMutableString instance variable
currentStringValue = [[NSMutableString alloc] initWithCapacity:50];
}
[currentStringValue appendString:string];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqual:@"name"])
{
NSLog([NSString stringWithFormat:@"name value = %@",currentStringValue]);
}else if([elementName isEqual:@"age"])
{
NSLog([NSString stringWithFormat:@"age value = %@",currentStringValue]);
}else if([elementName isEqual:@"username"])
{
NSLog([NSString stringWithFormat:@"username value = %@",currentStringValue]);
}
[currentStringValue release];
currentStringValue = nil;
}



More detailed Sample code is available to download from here

1 comment:

  1. You may also want to try vtd-xml, which is more powerful than the SAX parser ...

    http://vtd-xml.sf.net

    ReplyDelete