next up previous
Next: Implementing XML Pull Parser Up: Design of a Pull Previous: Push and Pull: complementary

Design of Pull API

As we have seen pull parsing has some advantages and therefore it is very important to provide developers with one consistent and simple API to work with.

For such an API to stay minimal we need to expose only a few things to the user. We need to expose the parser state, such as : START_TAG, END_TAG, CONTENT, END_DOCUMENT. This number of states is minimal for any XML parser. We will also need an ability to to get next state, for example by calling method named next(). Finally for each state we will need to retrieve information associated with the parser state (current event). When we reach END_DOCUMENT there is no more input and in this case no extra information is needed. However for CONTENT, to get element content as String, readContent() can be used. Then for start and end tags we need the name of the tag and its namesapace: getLocalName() and getNamespaceUri(). Finally START_TAG is the hard part as it can also contain the list of attributes declared in this start tag. It is a good idea to make it look like SAX Attributes/AttributeList to simplify potential conversion of pull events into SAX push callbacks.

So we can say that such minimal Pull Parser API should have at least:

public interface XmlPullParser {
    /** signal logical end of xml document */
    public final static byte END_DOCUMENT = 1;
    /** start tag was just read */
    public final static byte START_TAG = 2;
    /** end tag was just read */
    public final static byte END_TAG = 3;
    /** element content was just read */
    public final static byte CONTENT = 4;
    
        
    int next() throws PullParserException;
    public String readContent() throws XmlPullParserException;
    public void readEndTag(XmlEndTag etag) throws XmlPullParserException;
    public void readStartTag(XmlStartTag stag) throws XmlPullParserException;
    public String getLoacalName();
    public String getNamespaceUri();
}

It is useful to represent XmlStartTag and XmlEndTag as separate interfaces but sharing common functionality in XmlTag. It is possible to have state retrieval methods in XmlPullParser instead of creating extra interfaces such as XmlEndTag and XmlStartTag. However having separate interfaces allows us to maintain parsing state in those classes easily and allows to record state of parsing for any number of steps in the past.

public interface XmlTag {
  public String getNamespaceUri();
  public String getLocalName();
}

public interface XmlEndTag extends XmlTag {
}

public interface XmlStartTag extends XmlTag {

    public int getAttributeCount();
    public String getAttributeNamespaceUri(int index);
    public String getAttributeLocalName(int index);
    public String getAttributeValue(int index);
    public String getAttributeValueFromName(String namespaceUri,
                                            String localName);

}

This API will have to be extended to allow for more efficient handling of namespace declarations, setting parser input, resetting parser state for parser reuse and some other utility methods. However the core API for XML pull parser will probably be similar to what is shown above.

We should mention here that use of XmlTag interfaces is not essential for such API and may be abandoned when memory size constraints are of premium such as is the case with handheld devices in J2ME. In these cases embedding all state into one XmlPullParser interface will be very advantageous.


next up previous
Next: Implementing XML Pull Parser Up: Design of a Pull Previous: Push and Pull: complementary
Aleksander Andrzej Slominski
2002-02-10