April 2004
Introducing the Digester Component
The emergence of Extensible Markup Language (XML) has led to a complete transformation
of the application development world. All development seems to revolve around
XML these days. In fact, it is difficult to find any new development that does
not directly or indirectly rely on XML. For instance, Web services are unimaginable
without XML, and with the usage of Web services projected to boom over the next
few years, there is no escaping XML. In this article, you will look at the Jakarta
Commons Digester component and how it can make working with XML a simple task.
Table 7-1 shows the component details.
Table 7-1. Component Details
| Name |
Version |
Package |
| Digester |
1.5 |
org.apache.commons.digester |
One problem that has plagued XML development is the complexity of parsing
and using XML. Everybody knows the advantages of using XML, but I doubt many
people are able to write a piece of code that parses an XML file and picks up
the value of a certain XML tag. Writing a piece of Java code to parse a piece
of XML directly using the two core Application Programming Interfaces (APIs)—the
Document Object Model (DOM) and Simple API for XML (SAX)—is anything but
simple. APIs such as JDOM are relatively simple, but considering how often you
have to encounter and tackle XML, Digester provides an easier option. You can
be parsing and using XML in your Java code in less than the time it will take
you to read this article. (No, I will not eat my hat if you do not manage to
accomplish the task.)
To quickly get up and running with Digester, you will see an example first.
Do not worry about the syntax because you will look at that in detail later
in this article. The scenario for this example is that you are presented with
an XML file containing the details of all the students attending the various
courses at your training institute. What you are expected to do is to pick up
all the details present in the XML file, and for each student detail, populate
an instance of a class Student, which you create. You will
then store all the Student instances created in an instance
of the java.util.Vector class for further processing.
You first need to create a Student class that will hold the details of a student
(see Listing 7-1).
Listing 7-1. Student Class
package com.commonsbook.chap7;
public class Student {
private String name;
private String course;
public Student() {
}
public String getName() {
return name;
}
public void setName(String newName) {
name = newName;
}
public String getCourse() {
return course;
}
public void setCourse(String newCourse) {
course = newCourse;
}
public String toString() {
return("Name="+this.name + " & Course=" + this.course);
}
}
Apart from the overridden toString method, there is nothing
special about this class. It has just two properties with getter and setter
methods for each. You want to create instances of this class based on the data
you retrieve from an XML file.
Listing 7-2 shows the XML file contents. The number of student
tags is not relevant; you could very well introduce more students if you like.
Listing 7-2. students.xml
<?xml version="1.0"?>
<students>
<student>
<name>Java Boy</name>
<course>JSP</course>
</student>
<student>
<name>Java Girl</name>
<course>EJB</course>
</student>
</students>
NOTE
In Listings 7-1 and 7-2 you can see that the names of the tags and properties
match exactly. So, for a tag course, you have a property named course in the
Student class. However, you can have different tag names and property names.
No mapping of the XML and the Java class is required; you could very well
store the value of a tag ABC into a property XYZ. The matching names merely
keep things simple.
The Java class DigestStudents, shown in Listing 7-3, will
pick up the contents of the various XML tags and create a Vector
class instance that can hold many instances of the class Student.
Listing 7-3. DigestStudents
package com.commonsbook.chap7;
import java.util.Vector;
import org.apache.commons.digester.Digester;
public class DigestStudents {
Vector students;
public DigestStudents() {
students= new Vector();
}
public static void main(String[] args) {
DigestStudents digestStudents = new DigestStudents();
digestStudents.digest();
}
private void digest() {
try {
Digester digester = new Digester();
//Push the current object onto the stack
digester.push(this);
//Creates a new instance of the Student class
digester.addObjectCreate( "students/student", Student.class );
//Uses setName method of the Student instance
//Uses tag name as the property name
digester.addBeanPropertySetter( "students/student/name");
//Uses setCourse method of the Student instance
//Explicitly specify property name as 'course'
digester.addBeanPropertySetter( "students/student/course", "course" );
//Move to next student
digester.addSetNext( "students/student", "addStudent" );
DigestStudents ds = (DigestStudents) digester.parse(this.getClass()
.getClassLoader()
.getResourceAsStream("students.xml"));
//Print the contents of the Vector
System.out.println("Students Vector "+ds.students);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void addStudent( Student stud ) {
//Add a new Student instance to the Vector
students.add( stud );
}
}
In very few lines of code you have managed to create the Vector
of Student instances. The output of the program is as follows,
displaying the tag values in the file students.xml:
Students Vector [Name=Java Boy Course=JSP,
Name=Java Girl Course=EJB]
Pretty cool, eh? I would have loved to write the corresponding DOM and SAX
code to compare and illustrate the advantage of using the Digester component,
but writing DOM and SAX code is something I forgot a long time ago and am not
very keen on learning again. So you will just continue with the Digester experiments.
Specifically, you will next look at some Digester fundamentals and learn how
the example in Listing 7-3 works.
Understanding Digester Concepts
The Digester component has its origins in the Struts framework project. It
began its life as a tool to quickly parse the struts-config.xml
file without having to directly interact with SAX. Because the Digester functionality
can be useful to all kinds of applications, it later moved to the Commons project.
The Digester is not an XML parser but just a high-level interface that uses
SAX underneath to accomplish the actual XML parsing. So a requirement for Digester
is the presence of an XML parser conforming to Java API for XML Processing (JAXP)
version 1.1 or later. The Digester also depends on the following Commons components:
- The BeanUtils component
- * The Collections component
- * The Logging component
Because Digester uses SAX to do the parsing, XML processing with Digester
happens in an event-driven manner. An event-driven manner is when events are
triggered while the document is being parsed; what you need to do is provide
handlers for these events. That is the way SAX works. SAX is all about events
being fired when a certain occurrence is found. SAX events are fired on occurrences
such as starting tags, ending tags, and so on. DOM works a little differently:
Object models are created in memory and parsed. However, when using the Digester,
you do not need to understand how SAX or DOM works, and you do not need to do
any SAX-specific tasks in your code. Just stick to Digester’s rules, and
you should soon be parsing XML documents with ease.
Digester uses a stack to store or retrieve objects as the XML file is being
parsed. If you are not familiar with what a stack is, just think of it as a
box in which you keep putting items and can remove them only on the basis of
Last In First Out (LIFO). Java provides a stack implementation with java.util.Stack.
Based on the rules defined and the XML encountered, the Digester component
pushes objects on the stack. Upon encountering the start of a tag, the associated
object is pushed onto the stack, and it is popped only after all the nested
contents of that tag are processed. So, in Listing 7-3 upon the student
tag being encountered, an instance of Student class will be
pushed onto the stack and will be popped once the processing of its child tags
name and course is complete.
Using Matching Patterns
The big advantage of using the Digester component instead of other APIs is
the presence of element matching patterns. Unlike other APIs where you have
to worry about parent/child relationships among tags, what is important with
Digester is the matching pattern specified. For example, in Listing 7-3, you
used the matching patterns students/student, students/student/name,
and students/student/course. This is an easy and developer-friendly
usage to precisely convey the tag to which you want to refer. If you have to
map the tags in Listing 7-2 to the corresponding matching pattern, the mapping
will be as shown in Table 7-2.
Table 7-2. Tag Pattern Mapping
| Tag |
Pattern |
| <students> |
students |
| <students> |
students/students |
| <name> |
students/students/name |
| <course> |
students/students/course |
You can also use the wildcard * if you want to have a more generalized matching.
So the pattern */name would have matched all name tags within the document.
Using Rules
With element matching patterns you convey the exact location of the tag in
the XML structure. However, to tell the Digester component what needs to be
done upon finding that tag, you need to define processing rules. These rules
fire when the matching pattern is found. All rules are expected to extend the
abstract class org.apache.commons.digester.Rule and define
specific actions that need to be taken when a certain element occurs.
You can define your own rules to handle application-specific cases. The Digester
component comes with a set of rule implementations that extend the Rule class;
you can find them in the package org.apache.commons.digester.
As you move along, you will see some of these rules in the examples. In Listing
7-3 you used ObjectCreateRule to create an instance of the
Student class, and you used BeanPropertySetterRule to set the
properties of the class.
Before getting into a more complex XML example than the one you saw in Listing
7-2, you will look at the steps you need to perform for Digester to successfully
retrieve data from XML:
- You need to create a new instance of org.apache.commons.digester.Digester
and configure it using the various setXxx methods provided
by the class. Among other properties, you can define whether the XML should
be validated, define the logger to be used, and define the Rules
implementation object.
- You push any initial objects on the object stack using the Digester’s
push method before you define the patterns and the rules
to be used. In Listing 7-3, you pushed the current object on the stack using
the keyword this. The reason you need to push this initial
object is because Digester keeps pushing and popping objects from the stack
as it encounters tags. So the first object is created and pushed onto the
stack upon encountering the first tag, and this object is popped off the stack
when the last tag is processed. Because you need to hold a reference to the
object for the first tag, the initial object you push before you parse the
XML serves the purpose and retains a reference to that object.
- Register element matching patterns and the rules you want to be fired for
each case. In Listing 7-3 you register three patterns and two rules that you
want to be fired.
- Finally, you parse the XML file using the parse method
of the Digester instance you created.
NOTE
The order in which you do things is important for Digester. You cannot randomly
move around statements before the call to the parse method.
For example, in Listing 7-3, you cannot move the call to addObjectCreate
to after the call to addSetNext.
You will now look at a more complex XML example and try to process it using
Digester. You will also see how you can move the specifying of Digester patterns
and rules from code to a configuration XML file.
Following XML Rules
In Listing 7-3, most of the code is dedicated to configuring the Digester
instance. Hardly any of the code can be termed as action-oriented code.
The most common usage of Digester is to process XML-based configuration files.
The reason why these configuration files are used is to keep code free of configuration
information and make changes possible without having to change the code and
recompile it. It would be unfair if you placed Digester configuration information
within Java code. Even this bit has to move to a configuration XML file.
The package org.apache.commons.digester.xmlrules deals with
this issue, and the DigesterLoader class that is present in
this package makes it possible to create a Digester instance using just the
information in an XML file.
In the following example, you will first look at Java code that will accomplish
the task along somewhat similar lines as the example in Listing 7-3 and then
move to an XML-based configuration file for the same example.
Listing 7-4 shows the XML file from which you want to fetch information. The
XML stores information about an academy, its students, and its teachers. The
Digester code picks up these details and makes them manageable within Java code
Listing 7-4. academy.xml
<?xml version="1.0"?>
<academy name="JAcademy" >
<student name="JavaBoy" division="A">
<course>
<id>C1</id>
<name>JSP</name>
</course>
<course>
<id>C2</id>
<name>Servlets</name>
</course>
</student>
<student name="JavaGirl" division="B">
<course>
<id>C3</id>
<name>EJB</name>
</course>
</student>
<teacher name="JavaGuru">
<certification>SCJP</certification>
<certification>SCWCD</certification>
</teacher>
<teacher name="JavaMaster">
<certification>OCP</certification>
<certification>SCJP</certification>
<certification>SCEA</certification>
</teacher>
</academy>
NOTE With Listing 7-4 I have tried
to address the many scenarios you might encounter when parsing XML files.
Using this code from this example can get you started in no time.
Because you have to hold the XML data in Java objects, you need to decide which
classes you have to create. Instances of these classes will hold the data for
you. Looking at this example, you should see four classes that together can
do a good job of holding the data in a properly structured format. These classes
are Academy, Student, Course,
and Teacher. You could very well create more classes, such
as Certification. The most important thing is that you cannot
have these as just separate classes; you also need to maintain the relationships
among them as depicted in the XML file. So, you will first put down the Java
classes. Instances of the Java classes will hold the data for you.
An instance of the Course class is meant to store just the
name and the ID of the course. The Course instance will not
be maintaining its relation to the Student; this will be done
by the Student instance. Listing 7-5 shows the Course
class; it has two properties and the corresponding get and
set methods. Note that the package name for classes used in
this example is com.commonsbook.chap7.academy.
Listing 7-5. Course Class
package com.commonsbook.chap7.academy;
import org.apache.commons.beanutils.PropertyUtils;
import java.util.Vector;
public class Course {
private String id;
private String name;
public Course() {
}
public String getId() {
return id;
}
public void setId(String newId) {
id = newId;
}
public String getName() {
return name;
}
public void setName(String newName) {
name = newName;
}
public String toString() {
StringBuffer buf = new StringBuffer(60);
buf.append("\n\tCourseId>>> " + this.getId() + "\t");
buf.append("CourseName>>> " + this.getName());
return buf.toString();
}
}
Next you will define the Student class that not only has to
hold information about the student but also about the courses the student attends.
As shown in Listing 7-6, the student details are stored using properties, and
the courses will be stored as a Vector of Course
instances.
Listing 7-6. Student Class
package com.commonsbook.chap7.academy;
import java.util.Vector;
public class Student {
private Vector courses;
private String name;
private String division;
public Student() {
courses = new Vector();
}
public void addCourse(Course course) {
courses.addElement(course);
}
public String getName() {
return name;
}
public void setName(String newName) {
name = newName;
}
public String getDivision() {
return division;
}
public void setDivision(String newDivision) {
division = newDivision;
}
public void setCourses(Vector courses) {
this.courses = courses;
}
public Vector getCourses() {
return courses;
}
public String toString() {
StringBuffer buf = new StringBuffer(60);
buf.append("\nStudent name>> " + this.getName());
Vector courses = this.getCourses();
//Iterate through vector. Append content to StringBuffer.
for (int i = 0; i < courses.size(); i++) {
buf.append(courses.get(i));
}
return buf.toString();
}
}
Listing 7-4 shows that, for a teacher, you are expected to store the name and
the list of certifications held by the teacher. The Teacher
class, shown in Listing 7-7, does this by using a String property
for the name and a Vector holding String instances
for the certifications list.
Listing 7-7. Teacher Class
package com.commonsbook.chap7.academy;
import org.apache.commons.beanutils.PropertyUtils;
import java.util.Vector;
public class Teacher {
private String name;
private Vector certifications;
public Teacher() {
certifications = new Vector();
}
public void addCertification(String certification) {
certifications.addElement(certification);
}
public String getName() {
return name;
}
public void setName(String newName) {
name = newName;
}
public void setCertifications(Vector certifications) {
this.certifications = certifications;
}
public Vector getCertifications() {
return certifications;
}
public String toString() {
StringBuffer buf = new StringBuffer(60);
buf.append("\nTeacher name>> " + this.getName());
Vector certs = this.getCertifications();
//Iterate through vector. Append content to StringBuffer.
for (int i = 0; i < certs.size(); i++) {
buf.append("\n\tCertification>> " + certs.get(i));
}
return buf.toString();
}
}
The academy tag is the root tag shown in Listing 7-4. So the
Academy class not only has to store the name of the academy
but also references to the data held by the child tags of the academy
tag. Therefore, the Academy class, shown in Listing 7-8, has two Vectors,
one that will store instances of Student classes and another
that will store instances of Teacher classes. So directly or
indirectly you should be able to access all the data depicted in Listing 7-4
using a reference to a properly populated Academy class instance.
The overridden toString method will be used later in the article
to print the data held by an Academy instance.
Listing 7-8. Academy Class
package com.commonsbook.chap7.academy;
import org.apache.commons.beanutils.PropertyUtils;
import java.util.Vector;
public class Academy {
private Vector students;
private Vector teachers;
private String name;
public Academy() {
students = new Vector();
teachers = new Vector();
}
public void addStudent(Student student) {
students.addElement(student);
}
public void addTeacher(Teacher teacher) {
teachers.addElement(teacher);
}
public Vector getStudents() {
return students;
}
public void setStudents(Vector newStudents) {
students = newStudents;
}
public Vector getTeachers() {
return teachers;
}
public void setTeachers(Vector newTeachers) {
teachers = newTeachers;
}
public String getName() {
return name;
}
public void setName(String newName) {
name = newName;
}
public String toString() {
StringBuffer buf = new StringBuffer(60);
buf.append("Academy name>> " + this.getName());
Vector stud = this.getStudents();
Vector teach = this.getTeachers();
buf.append("\n\n**STUDENTS**");
//Iterate through vectors. Append content to StringBuffer.
for (int i = 0; i < stud.size(); i++) {
buf.append(stud.get(i));
}
buf.append("\n\n**TEACHERS**");
for (int i = 0; i < teach.size(); i++) {
buf.append(teach.get(i));
}
return buf.toString();
}
}
Now that you are done with the classes that will store the data for you, you
will move to the Digester code that will actually parse the XML. You will first
see how you specify Digester instructions within the Java code. Next you will
move out these instructions to an easily configurable XML file, making your
Java code short and simple. Listing 7-9 shows the Java code to specify Digester
rules and parse the XML accordingly. The thing to note in this piece of code
is the usage of the following rules:
- ObjectCreate: This rule creates a new instance
of the classes Academy, Student, Teacher,
and Course on a matching pattern being found.
- SetProperties: The SetProperties
rule sets the properties of the class using the attribute values. Because
the name of the attribute and the property in the class matches exactly, you
did not specify those details; however, if the attribute names in XML and
property names in Java differ, you have to specify that mapping.
- BeanPropertySetter: This rule sets the properties
of the bean using the values of the child tags. For example, the id
and name properties of the instance of the class Course are
set using this rule.
- SetNext: The SetNext rule moves
to the next course, student, and teacher
tags. You have also specified the method to call in each case.
- CallMethod: The CallMethod rule
specifies the method to be called upon a certain pattern being found. You
also specify the number of parameters that this method expects.
- CallParam: The CallParam rule
specifies the parameter value to be passed to the method call defined using
the CallMethod rule.
Listing 7-9. DigestJavaAcademy Class (Digester Rules Defined
in Java Code)
package com.commonsbook.chap7.academy;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.digester.Digester;
import java.util.Vector;
public class DigestJavaAcademy {
public static void main(String[] args) throws Exception {
DigestJavaAcademy d = new DigestJavaAcademy();
d.digest();
}
public void digest() throws Exception {
Digester digester = new Digester();
digester.addObjectCreate("academy", Academy.class);
//Set the attribute values as properties
digester.addSetProperties("academy");
//A new Student instance for the student tag
digester.addObjectCreate("academy/student", Student.class);
//Set the attribute values as properties
digester.addSetProperties("academy/student");
//A new Course instance
digester.addObjectCreate("academy/student/course", Course.class);
//Set properties of the Course instance with values of two child tags
digester.addBeanPropertySetter("academy/student/course/id", "id");
digester.addBeanPropertySetter("academy/student/course/name", "name");
//Next Course
digester.addSetNext("academy/student/course", "addCourse");
//Next student
digester.addSetNext("academy/student", "addStudent");
//A new instance of Teacher
digester.addObjectCreate("academy/teacher", Teacher.class);
///Set teacher name with attribute value
digester.addSetProperties("academy/teacher");
//Call Method addCertification that takes a single parameter
digester.addCallMethod("academy/teacher/certification",
"addCertification", 1);
//Set value of the parameter for the addCertification method
digester.addCallParam("academy/teacher/certification", 0);
//Next Teacher
digester.addSetNext("academy/teacher", "addTeacher");
//Parse the XML file to get an Academy instance
Academy a = (Academy) digester.parse(this.getClass().getClassLoader()
.getResourceAsStream("academy.xml"));
System.out.println(a);
}
}
The order in which you define rules is important. You have just represented
what was obvious to you in the XML in a form that Digester can understand.
To execute this piece of code, you need to have the academy.xml
file present in the CLASSPATH. Listing 7-10 shows the output
upon executing this piece of code.
Listing 7-10. Output Upon Executing the Code in Listing 7-9
Academy name>> JAcademy
**STUDENTS**
Student name>> JavaBoy
CourseId>>> C1 CourseName>>> JSP
CourseId>>> C2 CourseName>>> Servlets
Student name>> JavaGirl
CourseId>>> C3 CourseName>>> EJB
**TEACHERS**
Teacher name>> JavaGuru
Certification>> SCJP
Certification>> SCWCD
Teacher name>> JavaMaster
Certification>> OCP
Certification>> SCJP
Certification>> SCEA
Looking at Listing 7-9, it is obvious that almost all the code is dedicated
to configuring the Digester. Did they not teach us in school that wherever possible
move all configurable items to a file that can be easily managed and manipulated?
So why not do that in this case?
The org.apache.commons.digester.xmlrules package provides
for an XML-based definition of Digester rules. Defining Digester rules in XML
is quite simple once you get the hang of the various rules and what they do
for you. Considering the more widespread nature of XML, your Digester rules
are now more easily understandable to a wide variety of people involved. Even
your manager might understand a thing or two!
Listing 7-11 shows the rules you defined using Java in Listing 7-9 but using
XML instead.
Listing 7-11. academyRules.xml Digester Rules Defined in XML
<?xml version="1.0"?>
<digester-rules>
<pattern value="academy">
<object-create-rule classname="com.commonsbook.chap7.academy.Academy" />
<set-properties-rule />
<pattern value="student">
<object-create-rule classname="com.commonsbook.chap7.academy.Student" />
<set-properties-rule />
<pattern value="course">
<object-create-rule classname="com.commonsbook.chap7.academy.Course" />
<bean-property-setter-rule pattern="id"/>
<bean-property-setter-rule pattern="name"/>
<set-next-rule methodname="addCourse" />
</pattern>
<set-next-rule methodname="addStudent" />
</pattern>
<pattern value="teacher">
<object-create-rule classname="com.commonsbook.chap7.academy.Teacher" />
<set-properties-rule />
<call-method-rule pattern="certification" methodname="addCertification"
paramcount="1" />
<call-param-rule pattern="certification" paramnumber="0"/>
<set-next-rule methodname="addTeacher" />
</pattern>
</pattern>
</digester-rules>
In the XML in Listing 7-11, the rules defined in XML almost directly map to
the methods defined in the Java in Listing 7-9. All the rules now are defined
using tags of that name. The easiest way to check the usage of these tags is
to open the digester-rules.dtd file. You can easily find this
file in the source download of the Digester component. However, even with the
binary download, this file can be extracted out of commons-digester.jar
file and is present in the org.apache.commons.digester.xmlrules
package. You can also look at the file and Digester code using ViewCVS at http://jakarta.apache.org/site/cvsindex.html.
Document Type Definition (DTD) files define the syntax and structure of XML
files, and although they take some getting used to, understanding them is not
difficult.
Once you are done defining the rules in XML, the Java bit left is simple.
Listing 7-12 shows the Java code where you just define the rules file to be
used to create a Digester instance and then parse the XML file using that Digester
instance.
Listing 7-12. DigestXMLJavaAcademy Class (Java Code Using
Rules Defined in XML)
package com.commonsbook.chap7.academy;
import java.io.File;
import java.util.Vector;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
public class DigestXMLJavaAcademy {
public static void main( String[] args ) {
DigestXMLJavaAcademy xmlDigest= new DigestXMLJavaAcademy();
xmlDigest.digest();
}
public void digest(){
try {
//Create Digester using rules defined in academyRules.xml
Digester digester = DigesterLoader.createDigester(
this.getClass().getClassLoader().getResource("academyRules.xml"));
//Parse academy.xml using the Digester to get an instance of Academy
Academy a = (Academy)digester.parse(
this.getClass().getClassLoader().getResourceAsStream("academy.xml"));
Vector vStud=a.getStudents();
Vector vTeach=a.getTeachers();
for (int i = 0; i < vStud.size(); i++) {
System.out.println("Student>> "+PropertyUtils.describe(vStud.get(i)));
}
for (int i = 0; i < vTeach.size(); i++) {
System.out.println("Teacher>> "+ PropertyUtils.describe(vTeach.get(i)));
}
} catch( Exception e ) {
e.printStackTrace();
}
}
}
The two files academy.xml and academyRules.xml
have to be present in the CLASSPATH, and upon execution of
the code, you get the same output as shown in Listing 7-10 that you got using
the Java code in Listing 7-9.
Introducing Other Digester Features
Apart from these Digester features, I will mention some other features of
Digester:
- The Logging capability of Digester can be useful while troubleshooting.
Digester uses the Commons Logging component and the Digester class even provides
a setLogger method with which you can define the exact logger
to be used.
- The org.apache.commons.digester.rss package provides an
example usage of Digester to parse XML in the Rich Site Summary (RSS) format,
which is widely used by news sites to provide news feeds. Most of the popular
content providers support RSS, and you can find more information about RSS
at http://blogs.law.harvard.edu/tech/rss/.
- You can configure Digester to validate XML using a DTD file. You should
register the DTD using the register method, and you can switch
on validation using the setValidating method of the Digester
class.
- You can configure Digester to match patterns based on namespaces. You use
the methods setNamespaceAware and setRuleNamespaceURI
so that the Digester does not confuse a name tag in a namespace
X with a similar name tag in a namespace
Y.
Summary
In this article, you looked at the Digester component, which drastically cuts
down on the complexity involved in parsing XML. You saw how Digester works on
the simple concept of element matching patterns and how you can define rules
in Java code as well as in a separate XML file. You also saw some examples that
reflected common XML parsing requirements.
Using Digester and defining the rules in a separate XML file gets a big thumbs-up
from me. I highly recommend Digester for all your XML parsing requirements.
About the Author
Harshad wrote the books Pro Jakarta Commons (Apress, 2004), Oracle JDeveloper 10g: Empowering J2EE Development (Apress, 2004) and also coauthored Java 2 Enterprise Edition 1.4 Bible (Wiley & Sons, 2003).
Harshad Oak has a master's degree in computer management and is a Sun Certified Java Programmer and a Sun Certified Web Component Developer. He is the founder of Rightrix Solutions (http://www.rightrix.com) that is primarily involved in software development and content management services. Harshad has earlier been part of several J2EE projects at i-flex Solutions and Cognizant Technology Solutions.
Furthermore, he has written several articles about Java/J2EE for CNET Builder.com (http://www.builder.com/). He is also a guest lecturer on Java and J2EE. He can be reached at harshad@rightrix.com
PRINTER FRIENDLY VERSION
|