Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Simplify Java XML Parsing with Jakarta Digester : Page 2

Jakarta's Digester maps data from an XML source to Java objects. Learn all about this package and its advantages over other similar APIs. Then follow a real life Digester parsing example.


WEBINAR: On-Demand

Unleash Your DevOps Strategy by Synchronizing Application and Database Changes REGISTER >

Digester in the Real World
Although Digester is a straightforward solution, things are not always so ideal in the real world. For example, say you have to parse XML whose elements keep changing based on the input. You typically find such request/response streams in the search world. If you search for a book, you get content that contains data to be populated in the Book object. Searching for a magazine returns content that contains data to be populated in the Magazine object. In such a situation, you end up writing custom Rules.

Listing 5 shows the response from a book search. The boldface lines show the dynamic section of the response.

Listing 5. BookResponse.xml <?xml version="1.0" encoding="UTF-8"?> <response> <request> <name>books</name> <value>xml</value> </request> <matches>2</matches> <content> <books> <book> <title>book1</title> <author>author1</author> </book> <book> <title>book2</title> <author>author2</author> </book> </books> </content> </response>

Listing 6 shows the response from a magazine search. Again, the boldface lines show the dynamic section of the response.

Listing 6. MagazineResponse.xml <?xml version="1.0" encoding="UTF-8"?> <response> <request> <name>magazines</name> <value>security</value> </request> <matches>3</matches> <content> <magazines> <name>securityMagazine 1</name> <name>securityMagazine2</name> <name>securityMagazine3</name> </magazines> </content> </response>

You can use the same Digester class you used earlier (DigesterExample) with a little modification to parse XML whose elements continually change this way. Just add the two new methods shown in Listing 7 to the Response class.

Listing 7. Content Related Methods public void addContent(Object o) { _content = o; } public Object getContent() { return _content; }

Now, you need to create a custom Rule that gets triggered whenever Digester encounters the content element. Listing 8 demonstrates how to use a custom Rule. The boldface lines are the extra code that is required.

Listing 8. DigesterExample Class Using a Custom Rule import org.apache.commons.digester.*; import java.io.*; public class DigesterExample { public static void main(String ar[]) { Class contentClass = ar[0]; ContentBuilder contentBuilder = ar[1]; try { Digester digester = new Digester(); digester.setValidating( false ); digester.setRules(new ExtendedBaseRules()); digester.addObjectCreate( "response", Response.class ); digester.addObjectCreate( "response/request", Request.class ); digester.addBeanPropertySetter("response/request/name", "name" ); digester.addBeanPropertySetter("response/request/value", value" ); digester.addSetNext( "response/request", "setRequest" ); digester.addBeanPropertySetter( "response/matches", "matches" ); digester.addObjectCreate("response/content", contentClass); digester.addRule("response/content/?",new DefaultRule(digester, contentBuilder)); digester.addSetNext("response/content","addContent", "java.lang.Object"); File input = new File("input.xml"); Response response = (Response)digester.parse( input ); System.out.println( response.toString() ); } catch( Exception exc ) { exc.printStackTrace(); } } }

Two arguments are passed to the program, and the Classes are passed through the command line. The first argument is "contentClass", which is the container for the data in the content elements (boldfaced text in Listings 5 and 6). So, for a Book content item, you need a Book.class. The second argument is the class that is responsible for populating the Book.class.

Listing 9 shows the code for a custom Rule. The boldfaced text, getDigester.peek(), returns a reference to the object on the stack. In this example, it would be the type of content object based on the search request.

Listing 9. CustomRule Class import org.apache.commons.digester.Rule; import org.apache.commons.digester.Digester; public class DefaultRule extends Rule { public DefaultRule(Digester digester, ContentBuilder builder) { super(); _digester = digester; _builder = builder; } public void body(String namespace, String name, String text) throws Exception { _builder.addAttribute(name, text, getDigester().peek()); } }

Listing 10 shows the BookBuilder class. The boldfaced text is a reference to the Book object.

Listing 10. BookBuilder Class public class BookBuilder implements ContentBuilder{ public void body(String name, String text, Object object) throws Exception { Book book = (Book)Object; If (name.equals("title")) { book.setAuthor(text); } else if (name.equals("author")) { book.setAuthor(text); } } }

Since you extended the Rules, you have to tell Digester to use the ExtendedBaseRules class, which allows more kinds of matching patterns. The methods exposed when you extend the Rule object are add, begin, end, finish, and body.

Just like that, you've seen how the Digester package offers simplicity in parsing XML. You can use it with a straightforward mapping, as well as more complex XML schemas, with some simple variations.

Srinivas C. Nallapati is a developer at WW Grainger, Inc. He is a Sun-certified Java programmer.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date