http://www.developer.com/

Back to article

JDOM: XML Meets Java Meets Open Source


January 3, 2001

XML is an extensible framework for encapsulating data. Its widespread usage has depended to a large degree on how various programming languages could support reading, writing, and manipulating XML. Standards like DOM and SAX were developed early on and provide a language-independent API for XML manipulation. As the technology matures, issues such as performance, ease of use, and productivity become important. While many consider XML the universal language for data, there is no such thing as a universal programming language. Different languages have different capabilities and are optimized for certain tasks. While DOM and SAX continue to dominate the development world, new language-specific APIs are emerging. One such API is JDOM, an open source project whose goal is to make XML manipulation easier for Java programmers. This article is an introduction to JDOM.

JDOM takes an intuitive approach to XML manipulation. All XML building blocks (node types) are represented in JDOM as a class. For example, an element, an attribute, or a processing instruction, all have a corresponding class in JDOM. Using an underlying SAX or DOM parser, an XML document is parsed and represented as a Document object. The root element of the Document object is your key to gaining access to the rest of the XML document. Since Java naturally supports object inheritance, you are able to navigate the object hierarchy representing your XML document and extract the information you want. There is no event model to follow or DOM tree nodes to traverse. Your interaction with the XML document is done via Java objects (something that is very familiar to Java programmers).

The API is actually quite simple. The org.jdom.input package handles SAX or DOM input by offering a SAXBuilder and a DOMBuilder class. The org.jdom.output package wraps XMLOutput, DOMOutput, and SAXOutput classes which allow you to export XML as XML, DOM tree or a stream of SAX events respectively. The org.jdom.adapters package contain a series of adapter classes for various XML parsers that can be plugged into JDOM. Finally, the org.jdom package includes the classes representing the familiar XML building blocks: Attribute, CDATA, Comment, DocType, Document, Element, Entity, Namespace, and ProcessingInstruction.

Reading and Writing

Let's jump into an example right away. Listing 1 shows an Echo program that parses an XML file and then writes it out to the console.

Listing 1.

import java.io.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;

public class EchoXML {
    public static void main(String[] args) {
          
          try {
              SAXBuilder saxbuild = new SAXBuilder();
              DOMBuilder dombuild = new DOMBuilder();

              Document d = saxbuild.build(new File(args[0]));
              Document d2 = dombuild.build(new File(args[0]));
            
              XMLOutputter xmlout = new XMLOutputter("%%%%%");
              xmlout.output(d, System.out);

              System.out.println("\n----------------------------");

              xmlout.setTrimText(true);
              xmlout.setIndent(false);

              xmlout.output(d2, System.out);
         }
         catch (Exception ex) {
              ex.printStackTrace();
         }
    }
}

We used both the SAXBuilder and the DOMBuilder to parse the incoming XML document. If performance is a concern to you, you should use the SAXBuilder. If you need to validate the XML document, you can specify a Boolean "true" as a parameter in the

build()
method. After the parsing is done, we produce two outputs. When using XMLOutputter, you can turn indentation on or off, specify a string that will be used for indentation and indicate whether new lines should be inserted or removed. We just used a couple of these methods for demonstration purposes in the above example.

In order to compile and run the above code, you need to download JDOM. At the time of writing of this article the latest version was JDOM Beta 5. After you unzip (or untar) the file, go to the build directory. You will find the jdom.jar file there which needs to be added to your CLASSPATH. You will also see a build.bat (or build.sh) file. By running this file, you can rebuild the jdom.jar file. You should also build the API documentation files by typing

build javadoc

at the command prompt. With the jdom.jar file in your CLASSPATH and the documentation at hand, you are ready to use JDOM. Go ahead and compile the above the program and run it with a sample XML file.

Data Extraction

Reading and writing is easy. Most of the challenge comes when programs need to manipulate XML data. JDOM addresses this issue by providing an object representation of the XML document which act as your interface to the information contained in the XML document as well as its structure. To demonstrate some of the capabilities, assume that we have a file containing some customer information as shown in Listing 2.

Listing 2.




 John 
  Doe 

1234 Long Street
Chicago IL 87654

We also have a number of files each containing information about a product that we sell. These files are numbered item1.xml, item2.xml, item3.xml, etc. Here is an example:


Telephone
49.99
TEL-8760
1

We want to write a program that will read all the "item" files specified on the command line, determine which ones are in-stock, and then output a new XML file containing the order, which includes the customer information plus the items that will be shipped. This requires the program to read and parse various XML files, extract information from them and then put elements from different files together to create a new XML output. Listing 3 shows one way this can be done using the JDOM API.

Listing 3.

import java.io.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;

public class Order {
        public static void main(String[] args) {
              try {
                    SAXBuilder builder = new SAXBuilder();
                    Document customerdoc = builder.build("customer.xml");
                    Element customer = customerdoc.getRootElement();
                    Element fname = (Element)
                                customer.getChild("name").getChild("first").clone();
                    Element lname = (Element)
                                customer.getChild("name").getChild("last").clone();
                    Element address = (Element)
                                customer.getChild("address").clone();
                    Element city = (Element) customer.getChild("city").clone();
                    Element state = (Element) customer.getChild("state").clone();
                    Element zipcode = (Element) customer.getChild("zipcode").clone();

                    Element order = new Element("order");
                    order.addContent(fname);
                    order.addContent(lname);
                    order.addContent(address);
                    order.addContent(city);
                    order.addContent(state);
                    order.addContent(zipcode);

                    Document orderdoc = new Document(order);
                    orderdoc.setRootElement(order);

                    Document itemdoc;
                    String instock;
                    Element item;
                    for (int x=0; x 

After we parse the customer.xml file, we use the

getRootElement()
method to grab the root element of the document. This is stored in the variable customer. We can then use the
getChild()
method to navigate through the document and retrieve other elements of the file. We are using the
clone()
method to do a deep copy of the extracted elements because we want to then append these to our output file. In other words, we don't want the elements to maintain their original relationships to their parents as we transfer them to the new file. Once we have the various elements from the customer.xml as independent "Element" objects, we create a new Element called "order" which is going to be the root element of our output document. Using the
addContent()
method, we add some elements to the "order" and build our hierarchy using familiar Java constructs.

We then need to loop through the item files and figure out which ones are in-stock and include those in the final order as well. We do that using a for loop. Using the

getAttributeValue()
method, we can extract the value for the attribute "instock." For items that are in-stock, we go through the exercise of adding the appropriate information to the "order" document using the
addContent()
method. This time, we do the extraction and addition in one line. Once we are done, we output the final "order" document which contains elements from various "item" files and the customer.xml file.

If we had to examine a document that had more than one element with the same name, we could use the

getChildren()
method which returns a List containing all the matching elements. Using Java Collection API, we can iterate through the list of elements. Once again, the goal is to use familiar Java constructs (like a List) to simplify XML manipulations.

Creating XML

The objects representing the various parts of an XML document can be constructed independently of each other. These objects can then be tied together to form a hierarchy (nesting relationships). The important thing is that you have control and flexibility over how the various pieces are tied together allowing you to create XML documents from scratch while conforming to various DTDs. We demonstrate this using a servlet. The goals is to collect some information from an HTML form and then produce an XML document based on that information. Listing 4 shows the HTML form:

Listing 4.



Please provide the following information:

Name:

Favorite Food:

Favorite Sport:

Indoor Outdoor

Listing 5 shows the servlet that handles the information provided by the above form:

Listing 5.

import java.io.*;
import java.text.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;


public class createXML extends HttpServlet {

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
        throws IOException, ServletException
    {
        response.setContentType("text/xml");
        PrintWriter out = response.getWriter();

        try {
            Element survey = new Element("survey");
            Element name = new Element("name");
            name.addContent(request.getParameter("name"));
            survey.addContent(name);
            Element food = new Element("food");
            food.addContent(request.getParameter("food"));
            survey.addContent(food);
            Element sport = new Element("sport");
            sport.addContent(request.getParameter("sport"));
            Attribute type = new Attribute("type", 
                   request.getParameter("type"));
            sport.addAttribute(type);
            survey.addContent(sport);       
 
            Document surveydoc = new Document(survey);
           
            XMLOutputter xout = new XMLOutputter(" ", true);
            xout.output(surveydoc, out);
       } catch (Exception e) {
            e.printStackTrace();
       }
    }
    public void doPost(HttpServletRequest request,
                      HttpServletResponse response)
        throws IOException, ServletException
    {
        doGet(request, response);
    }
}

For each field, we create an element and then use the

addContent()
method to insert the text information inside the element. We also create an Attribute and associate it with the "sport" element. Each element is created independently from others. We insert all of them into the root element (survey) using the
addContent()
method and use the constructor for Document to create the actual XML document object. The creation process is very straightforward. Using the other classes in the org.jdom package, we can independently create comments, CDATA sections, processing instructions, etc. and add them to the XML document.

We have tried to show some of the capabilities of JDOM through some simple examples. Hopefully it is clear to you that JDOM takes an intuitive approach to modeling an XML document into a series of Java objects. These objects are then used like any other Java object to manipulate and modify the XML document. Although JDOM does not have the language independence quality attributed to DOM and SAX, it does provide Java programmers with a simple way to write code for reading, writing and manipulating XML documents. Furthermore, by providing its output in XML, DOM tree and SAX event streams, JDOM does provide a bridge in cases where using a specific standard-based API is necessary. JDOM is evolving and future releases could include support for XSLT and XPath.

About the Author

Piroz Mohseni is president of Bita Technologies, which focuses on business improvement through effective usage of technology. His areas of interest include enterprise Java, XML, and e-commerce applications. Contact him at mohseni@bita-tech.com.

Sitemap | Contact Us

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