Article

Consume XML In JSP

Page: 1 2 3 4 Next

Detecting the Elements

The fully qualified name of each element is the name as defined above, <price> for the price, and so on. The share element is detected in order to create a new InvestorInformation instance .

 public void startElement(String uri, String localName, String qName,  
                                            org.xml.sax.Attributes attributes) {  
   if(qName.equals("share") && info==null) {  
     info=new InvestorInformation();  
 
   } else if (qName.equals("code")) {  
     setName=true;  
 
   } else if(qName.equals("price")) {  
     setCurrentPrice = true;  
 
   } else if(qName.equals("change")) {  
     setChange = true;  
 
   } else if(qName.equals("time")) {  
     setTime = true;  
 
   } else if(qName.equals("date")) {  
     setDate = true;  
 
   } else if(qName.equals("percentageChange")) {  
     setPercentage = true;  
   }  
 }  
 
 public void endElement(String uri, String localName, String qName) {  
   if(qName.equals("share")) {  
       foundCode = false;  
   } else if(qName.equals("code")) {  
     setName = false;  
 
   } else if(qName.equals("price")) {  
     setCurrentPrice = false;  
 
   } else if(qName.equals("change")) {  
     setChange = false;  
 
   } else if(qName.equals("time")) {  
     setTime = false;  
 
   } else if(qName.equals("date")) {  
     setDate = false;  
 
   } else if(qName.equals("percentageChange")) {  
     setPercentage = false;  
   }  
 }

Setting Share Values

The characters() method then collects the share information.

 public void characters(char[] ch, int start, int length){  
   if(setName) {  
     String localName = new String(ch, start, length);  
     if(localName.equals(code)) {  
   this.foundCode = true;  
   if(name==null) {  
           info.setName(localName);  
   } else {  
           info.setName(name);  
   }  
     } else {  
   // reset the found code class in case there are multiple share entries  
   foundCode = false;  
   }  
 
   } else if(foundCode && setCurrentPrice) {  
     info.setCurrentPrice(new String(ch, start, length));  
 
   } else if(foundCode && setChange) {  
     info.setChange(new String(ch, start, length));  
 
   } else if(foundCode && setPercentage) {  
     info.setPercentage(new String(ch, start, length));  
 
   } else if(foundCode && setTime) {  
     info.setTime(new String(ch, start, length));  
 
   } else if(foundCode && setDate) {  
     info.setDate(new String(ch, start, length));  
 
   }  
 }

The only thing that’s particularly notable here is the handling of the code element. Since the document may contain multiple share offerings, we need to detect the correct share offering, but we can do so only after a new ShareInformation class has been created, and we’re inside a share-offering object. This is where the foundCode flag comes in.

The funny thing about this code is that almost all SAX processing code looks exactly like that above. It's actually quite straightforward, so that most of the programming required to use the information gathered by the service happens elsewhere.

At this point I would strongly recommend testing this class, as its simplicity might fool you into assuming it will work first time. Try out some range testing to make sure you've covered all the possible values.

Designing the Web Component

Until this point, the coding has been quite simple. There have been relatively few decisions to make, namely whether or not we’ll turn on the various optional features of a parser.

If, upon testing, the class doesn't work as expected, you may find it easier to break out the handler from the work class. Although the classes are tiny, the separation of roles usually helps make clear where you've been going wrong. It depends on how confident you are at juggling static and instance roles.

In addition, it wasn't absolutely necessary to make the loadInvestorInfo() method static. It could have worked just as well to make the instantiation of the InvestorInfoLoader class mandatory. I guess in the back of my mind somewhere I considered the possibility of caching the result -- a static factory-class-like class is one of the few ways we could achieve this.

I've considered 10 different designs before settling on this as the solution I’d use -- sometimes you just have to get on and write the code, or nothing gets done. Other considerations included keeping a Hashtable of results that could be cached (and flushed) and indexed according to code at this level, versus holding the data in the context, and so on.

In the end, I chose to implement the main functionality as a Tag. This allows me to teach designers (non-programmers) how to use the tag, and provides reasonable performance. Additionally, this approach requires no intervention on my part when combined in Ant with a standard build script that copies the necessary jar file and configuration for the tag to work. But even without that, the designers at work were ok about making sure the required assets were present in the script.

The alternative solutions of using a Servlet or even a struts class, in my opinion introduce too much configuration for what is often the only dynamic feature on the site. They also require actual programming on my part each time the service is used, which was inappropriate for this application.

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