Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

Web Services APIs for J2ME, Part 2: Java API for XML processing

C. Enrique Ortiz, Mobility Technologist and Writer, J2MEDeveloper.com
C. Enrique Ortiz is a software engineer with over 14 years of experience, most recently serving as Director of Mobile Applications at Aligo Inc., VP of Wireless at AGEA Corp., and as software engineer at Pervasive Software, Intelligent Reasoning Systems, and IBM. Enrique is a co-designer of the Mobile Java Developer Certification Exam of Sun Microsystems. He also co-authored of one of the first books on J2ME, the Mobile Information Device Profile for J2ME. Enrique is an active participant in the wireless Java community and in various J2ME expert groups. You can reach him at C. Enrique Ortiz.

Summary:  Become familiar with the Web Services APIs for J2ME. This article, focusing on the JAXP, spotlights the general remote service invocation and XML parsing that saves you from embedding these functions into every application.

Date:  02 Nov 2004
Level:  Introductory

Comments:  

Introduction

The Web Services APIs (WSA) for Java 2 Platform, Micro Edition (J2ME), as defined by the Java Community Process Java Specification Request (JSR) 172 (see Resources), defines two independent optional packages for remote service invocation and XML parsing. These Java APIs are targeted at both the Connected Device Configuration (CDC) and the Connected Limited Device Configuration (CLDC 1.0 and CLDC 1.1)-based profiles. Because JSR 172 provides support for remote service invocation (see Web Services API for J2ME, Part 1) and XML parsing at the device level, you don't have to embed these functions into each application. This article introduces the Java API for XML Processing (JAXP) optional package.


The JAXP for J2ME

The JSR 172 XML parsing API for J2ME is based on a subset of Java 2 Platform, Standard Edition (J2SE) JAXP 1.2 API and Simple API for XML Parsing (SAX) 2.0 interfaces. JAXP for J2ME is based on a subset of JAXP 1.2 and SAX 2.0 because of the memory constraints found on typical J2ME platforms. JAXP for J2ME consists of the following Java packages:

  • javax.xml.parsers: contains the SAX parser, exception, and error classes
    • Interfaces: None
    • Classes: SAXParserFactory (factory of SAX parsers), SAXParser (represents a SAX parser)
    • Exceptions: ParserConfigurationException (parser configuration)
    • Errors: FactoryConfigurationError (error related to parser factories such as parser not found)
  • org.xml.sax: the SAX 2.0 subset API
    • Interfaces: Attributes (an element's attributes), Locator (an event's document location)
    • Classes: InputSource (represents an XML input source)
    • Exceptions: SAXException (general/base SAX exception), SAXNotRecognizedException (feature not recognized), SAXNotSupportedException (feature recognized but not supported), SAXParseException (SAX parsing exception)
    • Errors: None
  • org.xml.sax.helpers: defines the base class for event processing
    • Interfaces: None
    • Classes: DefaultHandler (base event processing handler with default implementation)
    • Exceptions: None
    • Errors: None

JAXP for J2ME provides all the classes, interfaces, and exceptions needed to parse XML documents. The J2ME JAXP Javadoc or specification (see Resources) provides more information on these classes and interfaces.


XML parsers

JAXP for J2ME parsers must be XML 1.0 conformant, and can either be validating (based on a DTD) or not; the parsers follow the validation and non-validation rules found in the XML 1.0 specification (see Resources). Because validation is an expensive operation, the decision for including a validating parser implementation is decided by the device vendor based on the handset's resource and processing constraints. You can test if the parser is validating by calling the SAXParser.isValidating() method.

JAXP for J2ME XML parsers must support XML namespaces, as defined by the W3C XML Namespaces 1.0 Recommendation (see Resources), UTF-8 and UTF-16 character encoding, and DTDs. Not supported because of memory and run-time requirements are the Document Object Model (DOM) Level 1.x or 2.x and the Extensible Stylesheet Language Transformations (XSLT).


Typical elements of a JAXP for J2ME-based application

The JAXP for J2ME subset API provides all the functions needed to parse XML documents. In fact, you can parse XML documents by just using a subset of the functions provided by JAXP for J2ME. Figure 1 shows the typical elements of a JAXP for J2ME application.


Figure 1. Typical elements of a JAXP application
Typical elements of a JAXP application

These elements are:

  • MyApplication: the J2ME application that you write.
  • MyEventHandler: a class that you write that performs the application-specific event handling. It extends org.xml.sax.DefaultHandler.
  • Default event handler (DefaultHandler): the base event processing class that your event handler extends. This base class provides default event processing.
  • SAX parser factory (SAXParserFactory): the SAX parser factory class that you use to get an instance of the SAX parser.
  • SAX parser (SAXParser): the SAX parser that you use to parse your input XML documents. SAX parser is created by calling SAXParserFactory.
  • XML input stream: the input XML document to be parsed that is represented as a java.io.InputStream or, preferably, as an org.xml.sax.InputSource. The input XML document could be read from a network connection or from local storage.

Of course, typical applications have more elements than the ones illustrated in Figure 1, such as screens, data models and controllers, command listeners to capture user interface input, and base classes such as MIDlet, if developing a MIDP application. Also note that it is a good practice to implement a class that encapsulates the application-specific XML logic. This logic basically consists of owning all the JAXP objects, initializing, invoking the parser, and processing the input XML document processing events.


Using JAXP for J2ME

Using the JAXP consists of three main steps:

  1. Define (write) your application-specific event handler, a subclass of DefaultHandler.
  2. Use SAXParserFactory to create an instance of the SAX parser (SAXParser).
  3. Parse the input XML document by invoking the SAXParser.parse() method.

The SAX parser invokes your event handler's event-processing callbacks startDocument(), endDocument(), startElement(), endElement(), and characters() as different parts of the XML document are processed.

To understand the interaction between the different application objects over time, take a look at the high-level sequence diagram shown in Figure 2.


Figure 2. The JAXP API sequence diagram
The JAXP API Sequence Diagram

These interactions are:

  1. The JAXP application instantiates the event handler (subclass of DefaultHandler).
  2. The JAXP application instantiates the XML input source (InputSource).
  3. The JAXP application gets an instance of the SAX parser factory (SAXParserFactory).
  4. The JAXP application gets an instance of the SAX parser (SAXParser) by calling the SAX parser factory.
  5. The SAX parser factory instantiates and returns a SAXParser.
  6. The JAXP application calls the SAX parser to initiate the parsing of the XML document.

After parsing is initiated, the SAXParser invokes the event handler's callbacks as follows:

  1. startDocument() is called at the start of the document parsing.
  2. startElement() is called when a new element is encountered. This call also includes the element's attributes, if any.
  3. characters() is called when an element's characters are encountered.
  4. endElement() is called when a closing element is encountered.
  5. endDocument() is called at the end of the document parsing.

Now, I'll discuss how to use the JAXP API by covering in more detail the three main steps previously mentioned:

  1. Define (write) your application-specific event handler.
  2. Create an instance of the SAX parser.
  3. Parse the input XML document.

These steps can be performed in the main application logic (for example, the MIDlet) or, as previously mentioned, I recommend that you encapsulate this XML-specific logic into its own set of classes, hiding these details from the application.

Write your application-specific event handler

The first step is to write an application-specific event handler. This event handler is a class that must extend org.xml.sax.helpers.DefaultHandler, typically overriding the methods startElement(), endElement(), and characters() to process your XML document elements and attributes. You can also override the startDocument() and endDocument() methods to perform logic at the beginning and end of the XML document parsing.

Listing 1 shows a typical XML document with nested elements and elements with attributes. The simple JAXP event handler MyEventHandler shown in Listing 2 parses the XML document shown in Listing 1.


Listing 1. Sample XML document
<?xml version="1.0"?>
<element1 attribute1="aaaa">
    <element2>XXX</element2>
    <element2>YYY</element2>
    <element2>ZZZ</element2>
</element1>

MyEventHandler in Listing 2 shows how to parse elements element1, its attribute attribute1, and sub-element element2, while maintaining a list of element2 values.


Listing 2. A sample SAX event handler
/**
 * Parser handler class to parse the XML input stream.
 */
class MyEventHandler extends DefaultHandler {

  // Private members needed to parse the XML document
  private boolean parsingInProgress; // keep track of parsing
  private Stack qNameStack = new Stack(); // keep track of QName
  private Vector myElement2s = new Vector(); // keep track of element2

  // XML TAGS
  private static final String ELEMENT1 = "element1";
  private static final String ELEMENT2 = "element2";
  private static final String ATTRIBUTE1 = "attribute1";

  /**
   * Start of document processing.
   * @throws org.xml.sax.SAXException is any SAX exception, 
   * possibly wrapping another exception.
  */
  public void startDocument() 
          throws SAXException {
      parsingInProgress = true;
      qNameStack.removeAllElements();
      myElement2s.removeAllElements();
  }

  /**
   * End of document processing.
   * @throws org.xml.sax.SAXException is any SAX exception, 
   * possibly wrapping another exception.
   */
  public void endDocument() 
          throws SAXException {
      parsingInProgress = false;
      // We have encountered the end of the document. Do any processing that is desired, 
      //   for example dump all collected element2 values.
      for (int i=0; i<myElement2s.size(); i++) {
          MyElement2 o = (MyElement2) myElement2s.elementAt(i);
          o.dump();
      }
  }

  /**
   * Process the new element.
   * @param uri is the Namespace URI, or the empty string if the element 
   * has no Namespace URI or if Namespace processing is not being performed.
   * @param localName is the The local name (without prefix), or the empty 
   * string if Namespace processing is not being performed.
   * @param qName is the qualified name (with prefix), or the empty string 
   * if qualified names are not available.
   * @param attributes is the attributes attached to the element. If there 
   * are no attributes, it shall be an empty Attributes object.
   * @throws org.xml.sax.SAXException is any SAX exception, 
   * possibly wrapping another exception.
   */
  public void startElement(String uri, String localName, String qName, Attributes attributes) 
          throws SAXException {
      if (ELEMENT1.equals(qName)) {
          // ELEMENT1 has an attribute, get it by name
          String attribute1 = attributes.getValue(ATTRIBUTE1);
          // Do something with the attribute
          // ...
      } else {
          if (ELEMENT2.equals(qName)) {
              // Keep track of the value of element2
              MyElement2 o = new MyElement2();
              myElement2s.addElement(o);
          }
      }
      // Keep track of QNames
      qNameStack.push(qName);
  }

  /**
   * Process the character data for current tag.
   * @param ch are the element's characters.
   * @param start is the start position in the character array.
   * @param length is the number of characters to use from the 
   * character array.
   * @throws org.xml.sax.SAXException is any SAX exception, 
   * possibly wrapping another exception.
   */
  public void characters(char[] ch, int start, int length)
          throws SAXException {
      String qName;
      String chars = new String(ch, start, length);
      // Get current QName
      qName = (String) qNameStack.peek();
      if (ELEMENT1.equals(qName)) {
          // Nothing to process
      } else if (ELEMENT2.equals(qName)) {
          // Keep track of the value of element2
          if (myElement2s.size() > 0) {
              MyElement2 o = (MyElement2) myElement2s.lastElement();
              o.setValue(chars);
          }
      }
  }

  /**
   * Process the end element tag.
   * @param uri is the Namespace URI, or the empty string if the element 
   * has no Namespace URI or if Namespace processing is not being performed.
   * @param localName is the The local name (without prefix), or the empty 
   * string if Namespace processing is not being performed.
   * @param qName is the qualified name (with prefix), or the empty 
   * string if qualified names are not available.
   * @throws org.xml.sax.SAXException is any SAX exception, 
   * possibly wrapping another exception.
   */
  public void endElement(String uri, String localName, String qName)
          throws SAXException {
      // Pop QName, since we are done with it
      qNameStack.pop();
      if (ELEMENT1.equals(qName)) {
          // We have encountered the end of ELEMENT1
          // ...
      } else {
          if (ELEMENT2.equals(qName)) {
              // We have encountered the end of an ELEMENT2
              // ...
          }
      }
  }
}

Note how I use a Stack to keep track of the current qualified name (QName); the top of the Stack is the current XML element tag being processed. Using a Stack simplifies handling nested elements. I also use a Vector to keep track of element2 values. Element2 values are represented by the MyElement2 class as shown in Listing 3. Note how callback method startElement() processes element1's attribute1, how callback method characters() extracts and assigns the character data, and how endDocument() dumps any collected element2 values when the XML parsing has finished.


Listing 3. Class MyElement2
class MyElement2 {
    private String value;

    /** Constructor */
    public MyElement2() {}

    /**
     * Sets Element2 value.
     * @param v is the value to set.
     */
    public void setValue(String v) {
        this.value = v;
    }

    /**
     * Dumps Element2 value.
     */
    public void dump() {
        System.out.println("Value is: " + value);
    }
}

Create an instance of a SAX parser

Now, create an instance of the SAX parser by getting an instance of the SAXParserfactory to create a SAXParser.


Listing 4. Create a SAX parser
// Get an instance of the SAX parser factory
SAXParserFactory factory = SAXParserFactory.newInstance();

// Get an instance of the SAX parser
SAXParser saxParser = factory.newSAXParser();

The statements in Listing 4 might throw a SAXException, a FactoryConfigurationError, or a ParserConfigurationException, so you must enclose these within a try/catch block.

Parse the input XML document

Next, start parsing the XML document by calling the SaxParser.parse() method. The parse() method takes as arguments the XML document to parse, represented as an org.xml.sax.InputSource or as a java.io.InputStream, and the event handler to use (created in the first step). The preferred way to represent the XML document is to use an InputSource as it provides a number of helper methods such as setting and getting the input source's character encoding and the system identifier.

An InputSource can be created from a java.io.InputStream or a java.io.Reader. In the snippet shown in Listing 5 I use a java.io.InputStream that was created from a network connection such as an HttpConnection. After you have created the input source, you call the SAXParser.parse() method to initiate parsing.


Listing 5. Create the input source and calling the SAX Parser
// Initialize the URI and XML Document InputStream
String uri = "http://www.j2medeveloper.com/xmldocument.xml";
InputStream inputStream = getXMLDoc(uri);

// Create an InputSource from the InputStream
InputSource inputSource = new InputSource(inputStream);

// Parse the input XML document stream, using my event handler
MyEventHandler = new MyEventHandler();
saxParser.parse(inputSource, myEventHandler);

Because parsing is a long operation, you should call parse() in its own thread of execution; otherwise, if invoked in the main event thread, the user interface freezes until parsing completes. The parse method might throw an IOException or SAXException, so you must enclose these within a try/catch block.


Testing your application

You can write and test your JAXP application by using the J2ME Wireless Toolkit 2.1. The Wireless Toolkit provides support for the Web Services APIs as well as other optional packages. See Resources for a list of related resources.


Conclusion

This article introduced the JSR 172 Web Services API for the J2ME platform, with emphasis on the JAXP for J2ME XML parsing API. The article covered the typical elements of a JAXP application, the sequence of interactions between JAXP objects, and how to use the JAXP API to parse an input XML document. With JAXP for J2ME, a standard XML parsing API for J2ME is defined, and developers don't have to embed such functions into each of their applications, leaving them with more memory space and time to concentrate on their applications.


Resources

About the author

C. Enrique Ortiz is a software engineer with over 14 years of experience, most recently serving as Director of Mobile Applications at Aligo Inc., VP of Wireless at AGEA Corp., and as software engineer at Pervasive Software, Intelligent Reasoning Systems, and IBM. Enrique is a co-designer of the Mobile Java Developer Certification Exam of Sun Microsystems. He also co-authored of one of the first books on J2ME, the Mobile Information Device Profile for J2ME. Enrique is an active participant in the wireless Java community and in various J2ME expert groups. You can reach him at C. Enrique Ortiz.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, XML
ArticleID=31707
ArticleTitle=Web Services APIs for J2ME, Part 2: Java API for XML processing
publish-date=11022004
author1-email=eortiz@j2medeveloper.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).