JDOM


Table of Contents

1. Introduction
2. Installation
3. JDOM Basics
3.1. Getting XML Input with JDOM
3.2. Creating and Outputting XML with JDOM
4. References

JDOM is a Java API that provides the user with the ability to create and manipulate XML documents. JDOM provides Java specific XML functionality.

It is assumed that you know how to setup environment variables and install software on your operating system, for a comprehensive guide to doing so for Windows see Configuring A Windows Working Environment, for Unix see Configuring A Unix Working Environment Follow these instructions to install JDOM:

  1. Download and unzip the latest binary distribution of JDOM from http://www.jdom.org/dist/binary/.

  2. Add /path/to/wherever-you-unzipped-jdom/build/jdom.jar to your CLASSPATH environment variable.

The JDOM API is now ready to use. The API docs are situated at /path/to/wherever-you-unzipped-jdom/build/apidocs/, these are the canonical resource for programming with JDOM much as the Java API is the canonical resource for programming with Java in general.

Since JDOM is an inherently specialist tool there are not really any “basics” because most people who use JDOM will be doing so for a specific reason. We will introduce JDOM with two basic examples so that you can get an idea of how to use JDOM. A basic understanding of Java Objects, classes and inheritance is assumed.

Getting XML input with JDOM is extremely simple to do, the following example will illustrate this:

1

import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import java.io.IOException;
          

The JDOM and Java classes required are imported.

2

      if(args.length == 0) {
         System.out.println("USAGE: JDump URIofXMLDoc");
         System.exit(0);
      }
          

The number of command line arguments is checked, if it is zero, a message is produced summarizing usage.

3

      SAXBuilder builder = new SAXBuilder();
          

A new builder is created to build a JDOM tree. In this case, a SAXBuilder has been used, which builds a JDOM tree with SAX: http://www.saxproject.org/. The other builder available is DOMBuilder which builds a JDOM tree using DOM. It should preferably be used for building from a pre-existing DOM tree because otherwise a DOM tree will be built from the XML file first which is inefficient, SAX should be used instead. JDOM will use the default validating parser, there is another constructor available for specifying a validating parser to use.

4

      try {
        Document doc = builder.build(args[0]);
        XMLOutputter output = new XMLOutputter("  ", true);
        output.output(doc, System.out);
      } 
          

First of all a new Document is created, which is a JDOM tree representation of an XML tree. builder.build(args[0]) builds a new Document based on the first command line argument, the method used is:

build(java.net.URL URL) 
           This builds a document from the supplied URL.
          

The URL supplied can be a filename. There are many other build methods that build Documents based on other forms of input, the JDOM API lists them all.

        XMLOutputter output = new XMLOutputter("  ", true);
        output.output(doc, System.out);
          

If the document is valid, no exception will be thrown and the desired action is to dump the document to stdout; an XMLOutputter Object is created with two parameters, the first specifies the desired indentation width the nested elements should have when output and the second specifies that newlines should be produced where appropriate. output is then called with two parameters, the first specifying the Document to output and the second specifying where to output the Document, in this case, System.out.

5

      catch(JDOMException e) {
         System.out.println(e.getMessage());
      }
      catch(IOException e) {
         System.out.println(e.getMessage());   
      }
          

Two errors may be thrown by the last try statement, the first is a JDOMException, this is thrown by the SAXBuilder Object if it either fails to parse the document correctly or the document does not exist, in either case the error message generated by the object is printed. The second is an IOException this is thrown by the XMLOutputter Object if it encounters errors outputting the file, if this happens the error message generated by the object is printed.

That's it! It is very simple to do and very intuitive.

The following example may look daunting if you are a Java beginner but study it hard and read the comments and you should be able to understand it. The code generates valid XHTML files, it tries to center the table using two different CSS methods, one of which is deprecated. At the moment there is not a single multi-supported way of centering a table using only CSS, if you know, please tell me. Copy the following code into your favorite text editor, study it a little and try to work out what is going on:

Example 2. XHTML Profile Generator

// import the JDOM and io stuff we need1
import org.jdom.*;
import org.jdom.output.XMLOutputter;
import java.io.*;
// generates an xhtml 'profile' document based on user input
public class xhtmlgen {
   private static BufferedReader reader;
   public static void main(String[] args) {
      // setup reader for getting user input
      reader = new BufferedReader(
         new InputStreamReader(System.in)
      );

      // create new XML document, set DocType and set root element
      Document profile = new Document();2
      DocType type     = new DocType("html", "-//W3C//DTD XHTML 1.0 Transitional//EN", 
                                     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
      profile.setDocType(type);
      Element html     = new Element("html");
      profile.setRootElement(html);

      // get the persons name
      System.out.println("Hi there, welcome to ProfileGen 1.0");3
      String name = getUserInput("What is your name?"); 

      // create head element, title (set by name) and meta (predefined) and styles (predefined)
      Element head     = new Element("head");4
      head.addContent  ( new Element("title").setText(name+"'s Profile"));
      Element meta     = new Element("meta");
      meta.setAttribute( new Attribute("http-equiv", "Content-Type"));
      meta.setAttribute( new Attribute("content", "text/html; charset=utf-8"));
      head.addContent(meta);
      Element style    = new Element("style");
      style.setAttribute( new Attribute("type", "text/css"));
      style.setText("h1 { text-align: center; } " +
                    "div.centered {text-align: center;} " +
                    "div.centered table {margin: 0 auto; text-align: left;}"); 

      head.addContent(style);
      html.addContent(head);

      // create body
      Element body     = new Element("body");
      Element h1       = new Element("h1");
      h1.setAttribute(   new Attribute("align", "center"));
      h1.setText(name+"'s Profile");
      body.addContent(h1);
      body.addContent(   new Element("hr"));

      // create table and add profile items to it
      Element table       = new Element("table");
      table.addContent(createTableEntry("Name", name));5
      table.addContent(createDefinedTableEntry("Age","How old are you?")); 
      table.addContent(createDefinedTableEntry("Sex","What is your sex? (M/F)")); 
      table.addContent(createDefinedTableEntry("Country Of Origin","What is your country of origin?")); 
      table.addContent(createDefinedTableEntry("Occupation","What is your occupation?")); 
      table.addContent(createDefinedTableEntry("Email","What is your email address?")); 

      // let the user add arbitrary elements to the list
      String identifier=null;
      String description=getUserInput("Would you like to add extra items? (y/n)");
      while(!description.equals("n")) {
         table.addContent(createCustomTableEntry()); 
         description=getUserInput("Add another? (y/n)");
      }

      // add the table element (centered by div) to the body element and add final horizontal line
      Element div = new Element("div");
      div.setAttribute("class", "centered"); // css mess
      div.addContent(table);
      body.addContent(div);
      body.addContent(new Element("hr"));
      
      // add the body element to the html (root) element
      html.addContent(body);
      
      // initialize FileWriter, filename created from persons name
      FileWriter writer = null;
      try {
      writer = new FileWriter(name+"_Profile.html");6
      } catch(Exception e) {}

      // initialize JDOM XMLOutputter with 2 spaces indent and newlines on
      XMLOutputter prettyOutput = new XMLOutputter("  ", true);7

      // output the document to the file (via writer) and close writer 
      try {
         prettyOutput.output(profile, writer);
         writer.close();
      } catch(Exception e) {}
   }

   // creates a html table entry element which embodies identifier and description
   private static Element createTableEntry(String identifier, String description) {
     Element tr     = new Element("tr");
     Element td1    = new Element("td");
     Element td2    = new Element("td");
     Element strong = new Element("strong");8
     strong.setText(identifier+": ");
     td1.addContent(strong);
     td2.setText(description);
     tr.addContent(td1);
     tr.addContent(td2);
     return tr;
   }

   // creates a html table entry element based on identifier and user input prompted by prompt
   private static Element createDefinedTableEntry(String identifier, String prompt) {
     return createTableEntry(identifier, getUserInput(prompt));
   }

   // creates a custom html table entry element defined by the user
   private static Element createCustomTableEntry() { 
      String identifier = getUserInput("Please enter the profile identifier e.g Name");
      String description= getUserInput("Please enter the answer to the identifier, e.g Peter");
      return createTableEntry(identifier, description);
   }

   // gets user input response to supplied prompt
   private static String getUserInput(String prompt) {
      String userinput = "";
      while(userinput.equals("")) {
         System.out.println(prompt);
         try { 
            userinput = reader.readLine(); 
         } catch(IOException e) { System.err.println(e); }
      }
      return userinput;
   }
}      
        
1

// import the JDOM and io stuff we need
import org.jdom.*;
import org.jdom.output.XMLOutputter;
import java.io.*;
          

The program begins by importing the jdom components that we are going to use.

2

      // create new xml document, set DocType and set root element
      Document profile = new Document();
      DocType type     = new DocType("html", "-//W3C//DTD XHTML 1.0 Transitional//EN", 
                                     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
      profile.setDocType(type);
      Element html     = new Element("html");
      profile.setRootElement(html);
          

Here we see how we can create the XML document, it is constructed using the Jdom document class. The no parameter constructor has been used here so we can illustrate more features but it is possible to construct a document and specify the root element and DocType in one line. We have named our document profile.

      DocType type     = new DocType("html", "-//W3C//DTD XHTML 1.0 Transitional//EN", 
                                     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
      profile.setDocType(type);          
          

DocType is an Object that represents a document type declaration, since we are creating an XHTML document (which is also an XML document) we specify the XHTML root element, PUBLIC and SYSTEM identifiers we would like to use by using the constructor:

  DocType(java.lang.String elementName, java.lang.String publicID, java.lang.String systemID) 
           This will create the DocType with the specified element name and a reference to an external DTD.         
          

Now that our document prologue is sorted we create a new element and set it as the root element of our document, our root element is html like in any other XHTML document.

      Element html     = new Element("html");
      profile.setRootElement(html);          
          

We have now actually created within Java the following XML document.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
          

Well actually, the XML encoding is not determined until we output the document because we can specify a specific encoding (UTF-8 is the default). But that is trivial, see how easy it is to create an XML document using JDOM! It is very intuitive. Obviously this document is not complete, nor is it valid XHTML at the moment because there are elements missing from the inside.

The Java code to do this used above is just a single example, there are many other ways to do this and this is not some standard way or anything like that, use whatever way suits your coding style.

3

      // get the persons name
      System.out.println("Hi there, welcome to ProfileGen 1.0");
      String name = getUserInput("What is your name?"); 
          

We get the persons name here first so that we can create the page title and header based on it. It must be noted that this is not entirely necessary, we could create the title elements first and then go back and modify them later, this is why JDOM is so powerful. If we assume that we have created a head element that contained a title that we wanted to change later we could change it in one line, like this:

html.getChild("head").getChild("title").setText("new text for title");
          
4

      // create head element, title (set by name) and meta (predefined) and styles (predefined)
      Element head     = new Element("head");
      head.addContent  ( new Element("title").setText(name+"'s Profile"));
      Element meta     = new Element("meta");
      meta.setAttribute( new Attribute("http-equiv", "Content-Type"));
      meta.setAttribute( new Attribute("content", "text/html; charset=utf-8"));
      head.addContent(meta);
      Element style    = new Element("style");
      style.setAttribute( new Attribute("type", "text/css"));
      style.setText("h1 { text-align: center; } " +
                    "div.centered {text-align: center;} " +
                    "div.centered table {margin: 0 auto; text-align: left;}"); 

      head.addContent(style);
      html.addContent(head);
          

We can see the creation of a new element called head which is our XHTML head element, note that we did not have to call it head, we could have called it blah if we had wanted to but in this example we called it head, the text in the constructor we do want to call head because that is the actual text that will be used in the tag. There are also constructors for creating elements with namespaces.

      head.addContent  ( new Element("title").setText(name+"'s Profile"));
          

Here we add a title element to the head element and set the title to the value of the persons name plus "'s Profile", this is all done in one line.

      Element meta     = new Element("meta");
      meta.setAttribute( new Attribute("http-equiv", "Content-Type"));
      meta.setAttribute( new Attribute("content", "text/html; charset=utf-8"));
          

We would also like a meta element to reside within the head element so we create one and set it' attributes, using the intuitive method: setAttribute(java.lang.String name, java.lang.String value).

The meta element is then added to the head element. We then create a style element because we want to try and be XHTML compliant and avoid using align="center", however, for various reasons this is a mess, this has nothing to do with JDOM. So then we add our messy style element to the head element and since this is now complete we add the head element to the (root) html element.

5

      // create table and add profile items to it
      Element table       = new Element("table");
      table.addContent(createTableEntry("Name", name));
      table.addContent(createDefinedTableEntry("Age","How old are you?")); 
      table.addContent(createDefinedTableEntry("Sex","What is your sex? (M/F)")); 
      table.addContent(createDefinedTableEntry("Country Of Origin","What is your country of origin?")); 
      table.addContent(createDefinedTableEntry("Occupation","What is your occupation?")); 
      table.addContent(createDefinedTableEntry("Email","What is your email address?")); 
          

The program makes a table which it adds to the document that contains details about a person, these details are provided by the user prompted by questions at the command line. It is pretty straightforward, we create a new table element and then add lots of entries to it by calling some methods defined in the class. We use the standard addContent method (addContent(Element element)) of the element class to add the elements returned by the method calls.

6

      // initialize FileWriter, filename created from persons name
      FileWriter writer = null;
      try {
         writer = new FileWriter(name+"_Profile.html");
      } catch(Exception e) {}
          

We can write our document to a java.io.OutputStream or a java.io.Writer, we want to output to a java.io.Writer so we create it here, the name we give to the file that will be output to is made up of the persons name and the postfix shown.

7

      // initialize JDOM XMLOutputter with 2 spaces indent and newlines on
      XMLOutputter prettyOutput = new XMLOutputter("  ", true);
          

In the words of the JDOM API “XMLOutputter takes a JDOM tree and formats it to a stream as XML.” XMLOutputter has a number of useful formatting parameters that can be set; whether elements should be expanded (<hr/> would become <hr></hr> (which is not valid)), whether nested elements are separated by newlines and so on. We have constructed an XMLOutputter object using the following constructor:

XMLOutputter(java.lang.String indent, boolean newlines) 
           This will create an XMLOutputter with the given indent that prints newlines only if newlines is true; all whitespace from the element text content is included as well.
          

The above text is ripped straight out of the JDOM API, it is self explanatory and you can see that we have created our XMLOutputter so that it prints newlines and indents nested elements with two spaces.

      // output the document to the file (via writer) and close writer 
      try {
         prettyOutput.output(profile, writer);
         writer.close();
      } catch(Exception e) {}
          

Once are document is finished we want to output it to the file we created so we use the XMLOutputter output method: output(Document doc, java.io.Writer out) to output our document to the FileWriter we created. The writer is then closed and we are done.

8

   // creates a html table entry element which embodies identifier and description
   private static Element createTableEntry(String identifier, String description) {
     Element tr     = new Element("tr");
     Element td1    = new Element("td");
     Element td2    = new Element("td");
     Element strong = new Element("strong");
     strong.setText(identifier+": ");
     td1.addContent(strong);
     td2.setText(description);
     tr.addContent(td1);
     tr.addContent(td2);
     return tr;
   }
          

This is one of the methods that is called from the main part of the Java file, it returns an Element object and in this case it takes two strings; an identifier and a description and creates a table entry based on them where the identifier is wrapped in a strong element.

So, as you can see creating XML documents with JDOM is very simple and intuitive.

[Note]Note

We have only touched on the features available using JDOM. JDOM has numerous methods for navigating the JDOM tree such as getRootElement() which gets the root element of a Document, getChildren() which returns a (live, aka modifiable)List of all the child elements nested directly(one level deep) within an Element and getNameSpace() which will return the Element's namespace. There are loads more, with a bit of recursion JDOM tree navigation and manipulation can be done easily and efficiently. The details are all there in the JDOM API