Jato: The new kid on the open source block, Part 3

Translate XML documents into Java objects

Welcome back for Part 3 in this series on Jato, the open source, increasingly capable, XML/Java translator. In Part 1, I introduced Jato and how to perform XML-to-Java and Java-to-XML transformations. Since then Jato has experienced a complete redesign, a number of enhancements, and the addition of an interactive debugger. Part 2 focused on generating XML documents from complex Java object structures through an application that generated an XML document containing file system information. Part 2 further discussed macro writing, XML element and attribute creation, debug statements utilization, Java methods invocation, and Jato function writing.

Read the whole "Jato: The New Kid on the Open Source Block" series:

In Part 3, we turn our attention to XML-to-Java transformations and the conditional tags <Jato:if> and <Jato:else>, as well as Jato expressions, recursive XML traversal, constructors invocation, JavaBeans property settings, conditional parameter lists, and a little Swing.

Note: You may find the Jato Syntax Reference Guide useful for obtaining more detailed information on all the tags presented in this article.

Sounds exciting, so let's get started.

The new assignment

In Part 2 we transformed the hierarchical file-structure information contained in a File object into an XML document called site.xml. A partial listing of site.xml is shown is Listing 1:

Listing 1. Partial listing of site.xml

<?xml version="1.0" encoding="UTF-8"?>
<root path="E:\jato\examples">
   <dir name="examples" modified="1/15/01 10:11 PM" permissions="rw">
      <dir name="simple" modified="1/16/01 9:44 PM" permissions="rw">
         <file size="2745" modified="3/16/01 4:49 PM" permissions="rw">
         <file size="2745" modified="3/16/01 4:49 PM" permissions="rw">
   <file size="0" modified="3/17/01 10:38 AM" permissions="rw">

In our new assignment, we must create a Jato script that transforms site.xml into a Swing user interface. The finished application is shown in Figure 1.

Figure 1. JatoTree finished appearance

The user interface makes heavy use of the JTreeTable class source code provided in "Creating TreeTables: Part 2," Scott Violet and Kathy Walrath (java.sun.com).

Before jumping into the Jato script that transforms site.xml, let's lightly explore Jato expressions, a feature required to get an A on our assignment.

Jato expressions

Jato introduced expressions with the release of Beta 2 in March 2001. Expressions provide a compact syntax for obtaining current interpreter state information and evaluating logic that would require a large amount of Jato script. Jato uses expressions to perform conditional checks for <Jato:if> and <Jato:elseif> tags, generate debug statements, set the current object, manipulate the current input and output XML elements, construct variable names, and cause surly programmers to perform random acts of kindness. In this aritcle, I'll quickly introduce expressions, while a future article will deal with this subject in detail.

As an introduction to Jato expressions, consider the following debug statement:

    "Current system time: " ~ class.System.currentTimeMillis()

This statement will print the following message to the console:

Jato Debug: Current system time: 985279624868

Ah, the funky and useful things Jato expressions can accomplish. In this case, the expression engine parses this expression as:

  • Operator: The concatenation operator ('~').
  • Left operand: Literal string ("Current system time: ").
  • Right operand: A chained functional expression:
    • class: Instructs the expression engine to evaluate the expression between the two dots to obtain a class name. Fully qualified names are not required if the class resides in an imported package. The expression engine then invokes the method specified after the second dot. Parameters may be passed by placing comma-separated expressions between the parenthesis.
    • System: Specifies the simple class name for java.lang.System as an unquoted literal string, but the engine lets developers write complex expressions that invoke a method on the current object or read an XML attribute. The expression engine allows single, double, and unquoted literals.
    • currentTimeMillis(): Invokes the static method currentTimeMillis() on the System class passing zero parameters.

Using the return value from one expression to invoke another expression is called functional chaining -- similar to method chaining in Java. For instance, Java allows the following statement to determine the index of the first occurrence of the string "numb":

int index = new String("Comfortably Numb").toLowerCase().indexOf("numb");

This statement creates a String instance, converts it to lowercase, and then determines the index of the word "numb". The return value from the previous method invokes the next method. The same line of Java code could be spread over multiple lines as:

String title = new String("Comfortably Numb");
title = title.toLowerCase();
int index = title.indexOf("numb");

Unlike Java, where method chaining equals a luxury but not a necessity, Jato often requires function chaining to accomplish a given task. If you are a little confused by the current example, the examples in the following sections will provide additional expression examples.

Establish a script structure

To design and write the script, you must understand how to create JTreeTable components. The JTreeTable is a multiple column tree component that combines a JTree and JTable. The component uses a TreeTableModel as the data model; we will employ a concrete implementation called the FileSystemModel. The FileSystemModel maintains a list of FileNode objects, which is an abstract base class that defines methods for obtaining a file name, type, size, and last modified date. The code in Listing 2 creates a JTreeTable with a root and two descendants. Figure 2 shows the appearance of the JTreeTable when configured using Listing 2:

Listing 2. Example JTreeTable creation

import tree.*;   //the JTreeTable package
//create a root node and add file nodes
DirNode root = new DirNode();
//create a directory node and add to root
DirNode node1;
node1 = new DirNode("level 1", "rw");

//create a content node (leaf) and add to node 1
ContentNode node2;
node2 = new ContentNode("level 2", "rw");
node2.modifiedOn(new Date());
//use the root node and use it to create the data model and tree
JTreeTable treeTable = new JTreeTable(new FileSystemModel(root));
Figure 2. Appearance of JTreeTable

Notice that all JTreeTable classes reside in the tree package. The code fragment in Listing 2 uses two concrete implementations of the FileNode class:

  • DirNode: Represents a directory that can contain other directory and file nodes. The DirNode provides the following constructors:
    • public DirNode() //used to create root nodes.
    • public DirNode(String name, String perms).
  • ContentNode: Represents a data file and is always a leaf node. ContentNode defines a single constructor: public ContentNode(String name, String perms).

The code fragment makes use of two methods defined in the FileNode parent class:

  • public void setSize(int size): Implemented in the ContentNode class to set the byte size. The DirNode class ignores the method and calculates a size by summing the sizes of its child nodes.
  • public void modifiedOn(Date mod): Sets the file system object's last modified date. Notice it requires a java.util.Date instance.

Putting it all together, our script needs to perform the following:

  • Create a root DirNode
  • Iterate each element in site.xml
  • Instantiate a DirNode instance for each <dir> tag and add it to the parent DirNode:
    • Instantiate a ContentNode instance for each <file> tag and add it to the parent DirNode
    • Create a Date object using the value specified in the modified attribute and invoke the node's modifiedOn() method
    • For each <file> element, we also need to invoke the setSize() method passing size attribute's value
  • Create a FileSystemModel using the root node and instantiate the tree

The code in Listing 3 establishes the structure for the Jato script:

Listing 3. Template for script to create JTreeTable

1.  <Jato:jato-defs xmlns:Jato='http://www.jdom.org/jato'>
2.     <Jato:import>java.util.Date</Jato:import>
3.     <Jato:import>tree.*</Jato:import>
5.     <Jato:object type='DirNode' publish='root'>
6.        <Jato:inline macro='dir'/>
7.        <Jato:inline macro='file'/>
8.     </Jato:object>
10.    <Jato:macros>
11.       <Jato:macro name='dir'>
12.          <Jato:on-elt name='dir'>
13.             <Jato:debug print-elt-in='true'>Create dir node</Jato:debug>
15.             <!-- process child elements using recursive macro calls -->
16.             <Jato:inline macro='dir'/>
17.             <Jato:inline macro='file'/>
18.          </Jato:on-elt>
19.       </Jato:macro>
21.       <Jato:macro name='file'>
22.          <Jato:on-elt name='file'>
23.             <Jato:debug print-elt-in='true'>Create file node</Jato:debug>
24.          </Jato:on-elt>
25.       </Jato:macro>
26.    </Jato:macros>
27. </Jato:jato-defs>

The template performs the following actions:

  • Lines 2 and 3: Imports the Date class and all the JTableTree classes in the tree package.
  • Line 5: The <Jato:object> tag creates Java objects. In this case, the type attribute specifies the DirNode class using the default constructor. The publish attribute instructs the Jato interpreter to invoke the helper's publish() method and pass the directory node and the identifying key value of 'root'.
  • Line 6: Invokes the 'dir' macro, which will process the root's <dir> child elements.
  • Line 7: Invokes the 'file' macro, which will process the root's <file> child elements. The directory nodes will be created and added to the tree before the file nodes since the 'dir' macro call appears before the 'file' macro. This will cause the JTreeTable to display the directory nodes before the file nodes.
  • Line 11: Declares the start of the 'dir' macro.
  • Line 12: The <Jato:on-elt> tag iterates over the child elements of the current input XML elements, looking for tags named <dir>. For each match, the child element becomes the current input XML element and the script inside the <Jato:on-elt> tag is interpreted. When Jato initially calls this macro, the root directory node will be the current object.
  • Line 16: Recursively invokes the 'dir' macro. This will cause the <dir> elements contained in the current input XML element to be processed. The recursion will cease when the <Jato:on-elt> tag does not find a match. This recursive structure implements a depth-first search.
  • Line 17: Calls the 'file' macro to process any <file> child tags of the current input XML element.
  • Line 21: Declares the start of the 'file' macro.
  • Line 22: Searches the current input XML element for <file> nodes.

With the script structure established, we are ready to instantiate objects and invoke a few methods.

The <Jato:invoke>, <Jato:constructor>, and <Jato:param> tags

Because the 'dir' and 'file' macros perform very similar steps, in this section we will concentrate on the 'dir' macro, while the 'file' macro will be presented later. When implementing a script, keep in mind the objects with which a tag interacts to implement its behavior. Jato provides three reference objects for use by all script tags and expressions:

  • Current object: The Java object currently under manipulation. This reference is changed by many Jato tags, including <Jato:object>, <Jato:translate>, and <Jato:invoke>. A tag establishes the current object reference for its enclosed script. Of course, one of its enclosed script tags can set a different reference for its enclosed script tags.
  • Current input element: The XML element from the input document currently being processed by the interpreter. The <Jato:on-elt> and <Jato:translate> tags change this reference for their enclosing scripts.
  • Current output element: The XML element to which newly created XML elements and attributes will be added.

Implementing the 'dir' macro requires three tags:

1 2 3 Page 1
Page 1 of 3