Consuming a SOAP Web Service: Android SAX Alternative

Initially, the web service response that was seen in Android Lists V: Accessing and Consuming a SOAP Web Service II was parsed using SAX.  I discussed that the way SAX can be used in Android is identical to the way it is used in any other Java application.  This is useful because a SAX implementation can be reused between a Java desktop application and an Android mobile application without any special tailoring to make it work for Android.

There is another SAX option that is provided by Android.  It offers a few shortcuts and a cleaner looking syntax than typical SAX handlers.

In the android.sax namespace, there are some classes that provide a more structured method to handle XML parsing using SAX.  This is especially useful when parsing complex documents, since it allows you to be able to separate out the parsing logic of different elements into different classes easily.

This method is also beneficial when parsing less complex documents, as you’ll see with our StockQuote example, because it provides greater readability and easier maintainability than the previous SAX handler we implemented.

Let’s take a look at how the Android SAX components can be used to re-write our SAX handler:

package com.austinrasmussen.stockviewer;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;

import org.xml.sax.SAXException;

import android.sax.Element;
import android.sax.EndElementListener;
import android.sax.EndTextElementListener;
import android.sax.RootElement;
import android.util.Xml;

public class StockQuoteHandler {

	private final ArrayList<StockQuote> quotes = new ArrayList<StockQuote>();
	private final StringReader xmlReader;

	private final String STOCK = "Stock";
	private final String SYMBOL = "Symbol";
	private final String LAST = "Last";

	public StockQuoteHandler(String xml) {
		xmlReader = new StringReader(xml);
	}

	public void parse() throws IOException, SAXException {
		// The StockQuote that is currently being parsed
		final StockQuote currentQuote = new StockQuote();
		// The root element of the XML to parse
		RootElement root = new RootElement("StockQuotes");
		// The individual stock quote node
		Element stockQuote = root.getChild(STOCK);

		// Listener invoked when a </Stock> is encountered
		stockQuote.setEndElementListener(new EndElementListener() {
			public void end() {
				quotes.add(currentQuote.copy());
			}
		});

		// Listener invoked when a </Symbol> is encountered
		stockQuote.getChild(SYMBOL).setEndTextElementListener(new EndTextElementListener() {
			public void end(String body) {
				currentQuote.setTickerSymbol(body);
			}
		});

		// Listener invoked when a </Last> is encountered
		stockQuote.getChild(LAST).setEndTextElementListener(new EndTextElementListener() {
			public void end(String body) {
				currentQuote.setQuote(Double.parseDouble(body));
			}
		});

		Xml.parse(xmlReader, root.getContentHandler());
	}

	public ArrayList<StockQuote> getQuotes() {
		return quotes;
	}
}

This strategy removes the large chain of if(elementLocalName.equalsIgnoreCase(…)) { } else if(elementLocalName.equalsIgnoreCase(…)) { } that we previously saw embedded into the endElement method.

You may see that the ability to move the anonymous classes out into a defined class exists, and that is definitely a plus of this technique.  If I wanted, I could move the parsing of the </Last> element out into a separate class, like this:

package com.austinrasmussen.stockviewer;

import android.sax.EndTextElementListener;

public class LastEndTextElementListener implements EndTextElementListener {
	private final StockQuote currentQuote;

	LastEndTextElementListener(StockQuote currentQuote) {
		this.currentQuote = currentQuote;
	}

	public void end(String body) {
		currentQuote.setQuote(Double.parseDouble(body));
	}
}

I could then replace this in src/com/austinrasmussen/stockviewer/StockQuoteHandler.java

stockQuote.getChild(LAST).setEndTextElementListener(new EndTextElementListener() {
    public void end(String body) {
        currentQuote.setQuote(Double.parseDouble(body));
    }
});

with this:

stockQuote.getChild(LAST).setEndTextElementListener(new LastEndTextElementListener(currentQuote));

How cool is that? 🙂

Alright, it’s silly to separate out the simple parsing code that we have here, but it displays the flexibility of the Android SAX components.

Tags: , , , , , ,

This entry was posted on Saturday, May 14th, 2011 at 12:43 pm and is filed under Android. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

4 Responses to “Consuming a SOAP Web Service: Android SAX Alternative”

Marcin August 12th, 2011 at 8:23 am

I have one questiion.

There is one thing I dont understand.

At 39 line of StockQuoteHandler you have
quotes.add(currentQuote.copy());
What is this copy() method?

Austin Rasmussen August 12th, 2011 at 10:44 pm

Hey Marcin,

Good question. It’s just a simple shallow copy method that returns a copy of the current object (this allows the use of the final modifier on the currentQuote object).

public StockQuote copy() {
	StockQuote clonedQuote = new StockQuote();
	clonedQuote.setQuote(getQuote());
	clonedQuote.setTickerSymbol(getTickerSymbol());
	return clonedQuote;
}

kanchan August 26th, 2011 at 7:05 am

nice .job

Deals Nanaimo December 10th, 2012 at 10:30 am

Fine way of explaining, and good paragraph to get data concerning my presentation topic, which i am going to convey in university.

Leave a Reply

You must be logged in to post a comment.