Article

Consume XML In JSP

Page: 1 2 3 4 Next

The Data Class

As we’ve already discussed, the information we’re interested in is the share’s:

  • name
  • current price
  • dollar change
  • time
  • date
  • percentage change

The price, time, and all other values except date will be stored as Strings.

The data class for this example would therefore be as shown below. Note that I've omitted the obvious pieces of code such as the constructors and straight forward getters-and-setters:

package com.clearlysomethingwrong;  
 
import java.util.Date;  
import java.text.SimpleDateFormat;  
import java.text.ParseException;  
 
public class InvestorInformation {  
 String name;  
 String currentPrice;  
 String change;  
 String time;  
 Date date;  
 String percentage;  
 
 public String getFormattedDate() {  
   SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");  
   if(date!=null) {  
     return formatter.format(date);  
   } else {  
       return formatter.format(new Date());  
   }  
 }  
 
 public void setDate(String strdate) {  
   SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yy");  
 
   try {  
     date = formatter.parse(strdate);  
   } catch (ParseException e) {  
     date = new Date();  
   }  
 }  
}

The String formats for the incoming and outgoing dates are hard-coded here, but it would not be difficult to change that. The check for NULL in the getter ensures that we don't get a NullPointerException by passing NULL to the formatter.

Loading the XML Document

Well, that was straightforward, as data classes should be! The next class we’ll write is a kind of factory. We give it a java.io.InputStream of the XML source, and it returns a populated InvestorInformation class.

SAX parsing usually involves the use of identical base code; you create a parser to read the incoming XML, and you pass that parser a Handler, which handles each of the types of content in the XML file.

As the combined code (that which creates the parser and handles the XML elements) is quite simple, the next class we’ll create will achieve both tasks. It will implement the Handler class, and provide a method for processing an XML source.

To start with, we extend the org.xml.sax.helpers.DefaultHandler class:

package com.clearlysomethingwrong;  
 
import org.xml.sax.helpers.DefaultHandler;  
import org.xml.sax.SAXException;  
 
import javax.xml.parsers.ParserConfigurationException;  
import java.io.InputStream;  
import java.io.IOException;  
 
public class InvestorInfoLoader extends DefaultHandler {  
 
 static InvestorInformation info;  
 static String code;  
 static String name;  
 
 private boolean foundCode;  
 private boolean setName;  
 private boolean setCurrentPrice;  
 private boolean setChange;  
 private boolean setPercentage;  
 private boolean setTime;  
 private boolean setDate;

Each of these flags indicates a state of the XML document in which we’re interested. As the program enters each of the appropriate elements, the matching flag will be set. Then, when character content is sent to the program, it can assign this content to the appropriate property of the InvestorInformation class.

The foundCode property notes that the share with the given code has been found. The name property allows the user of the class to substitute a user-friendly name for the company, as usual share names (such as IBM, SUNW, XOM, and FNM) can be cryptic for those not in the know. If the value is null, we can simply return the code as the name of the share information object.

Next, we define the static processor method, loadInvestorInfo(). This method instantiates a parser via the factory method, creates an instance of itself to act as a Handler, and then passes the input stream and itself in. The result is stored in the static InvestorInformation property for this class, which is then returned:

 public static InvestorInformation loadInvestorInfo(InputStream is,  
                             String code, String name)  
   throws SAXException, IOException, ParserConfigurationException {  
 
 // detect invalid code, invalid input stream will be detected by parser.  
 if(code==null || code.length() == 0) {  
   throw new IllegalArgumentException("Code is null. Please provide a " +  
                               "share code.");  
 }  
 InvestorInfoLoader.code = code;  
 InvestorInfoLoader.name = name;  
 
   InvestorInfoLoader iil = new InvestorInfoLoader();  
   // load the XML file  
 
   // create a new sax parser factory  
   javax.xml.parsers.SAXParserFactory factory =  
                 javax.xml.parsers.SAXParserFactory.newInstance();  
 
   // turn off namespaces for now  
   factory.setNamespaceAware(false);  
   factory.setValidating(true);  
   javax.xml.parsers.SAXParser parser = factory.newSAXParser();  
   parser.parse(is, iil);  
 
   // load each bit of info for font  
   return info;  
 }

Fairly standard stuff. The handler methods are pretty basic, as well. Notice that I've turned off name space awareness here -- a DTD is usually provided, but for applications of the level of simplicity shown here (and I find this is quite typical), it may not be vital to have namespace awareness.

The payoff is usually performance versus security, and is your decision. No doubt your choice will depend on the level of relationship you have with the service’s supplier (many change their configuration without notice), and how critical the application is.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links