You are on page 1of 7

Sign In | Register

NEWS

Programming XML in Java, Part 1


Create Java apps with SAX appeal
1
By Mark Johnson
JavaWorld | Mar 13, 2000 12:00 AM PT

Page 2 of 4
This class's operation is very simple. The characters() method prints character content if it's inside a
<TITLE>. The private boolean eld _isTitle keeps track of whether the parser is in the process of parsing a
<TITLE>. The startElement() method sets _isTitle to true when a <TITLE> is encountered, and
endElement() sets it to false when </TITLE> is encountered.
To extract <TITLE> content from <POEM> XML, simply create a <Parser> (I'll show you how to do this in the
sample code below), call the Parser's setDocumentHandler() method with an instance of TitleFinder, and
tell the Parser to parse XML. The parser will print anything it nds inside a <TITLE> tag.
The TitleFinder class only overrides three methods: characters(), startElement(), and endElement(). The
other methods of the DocumentHandler are implemented by the HandlerBase superclass, and those methods
do precisely nothing -- just what you would have done if you'd implemented the interface yourself. A
convenience class like HandlerBase isn't necessary, but it simpli es the writing of handlers because you
don't need to spend a lot of time writing idle methods.
As an aside, sometimes in Sun documentation you'll see javadocs with method descriptions like "deny
knowledge of child nodes." Such a description has nothing to do with paternity suits or Mission: Impossible;
instead, it is a dead giveaway that you're looking at a do-nothing convenience class. Such classes often have
the words Base, Support, or Adapter in their names.
A convenience class like HandlerBase does the job, but still isn't quite smart enough. It doesn't limit you to
a <TITLE> element inside a <POEM>; it would print the titles of HTML les, too, for example. And any tags
inside a <TITLE>, such as <B> tags for bolding, would be lost. Since SAX is a simpli ed interface, it's left up
to the application developer to handle things like tag context.
Now you've seen a useless, simple example of SAX. Let's get into something more functional and
interesting: an XML language for specifying AWT menus.

An applied example: AWT menus as XML


Recently I needed to write a menu system for a Java program I was developing. Writing menus in Java 1.1 is
really quite easy. The top-level object in a menu structure is either a MenuBar or a PopupMenu object. A
MenuBar contains sub-Menu objects, while PopupMenu and Menu objects can contain Menus, MenuItems, and
CheckboxMenuItems. Typically, objects of this type are constructed manually in Java code, and built into a
menu tree via calls to the add() methods of the parent object.
Listing 3 shows the Java code that creates the menu shown in Figure 1.
MenuBarmenubarTop=newMenuBar();
MenumenuFile=newMenu("File");
MenumenuEdit=newMenu("Edit");

menubarTop.add(menuFile);
menubarTop.add(menuEdit);

menuFile.add(newMenuItem("Open"));
menuFile.add(newMenuItem("Close"));
menuFile.add(newMenuItem("Andsoon..."));
menuEdit.add(newMenuItem("Cut"));
menuEdit.add(newMenuItem("Paste"));
menuEdit.add(newMenuItem("Delete"));

Frameframe=newFrame("ManualMenuDemo");
frame.addWindowListener(newWindowAdapter(){
publicvoidwindowClosing(WindowEvente){
System.exit(0);
}
});
frame.setMenuBar(menubarTop);
frame.pack();
frame.show();
Listing 3. Creating a simple menu
Figure 1 below shows the simple menu that was handcoded in Java from Listing 3.

Figure 1. The resulting menu of Listing 3

Figure 1. The resulting menu of Listing 3


(below)

Simple enough, right? Well, not for me. Remember, I'm a lazy programmer, and I don't like having to write
all of this code to create these menus. And I haven't even begun to write all of the ActionListener and
ItemListener classes I need to actually make these menus operate. No, I want something easier.
I'd much rather have a menu speci cation language that lets me specify the menu structurally, and noti es
my program through a single interface when user events occur. I also want to be able to recon gure my
menus without having to rewrite any code. I want to create menu structures for naive or expert users simply
by changing the menu speci cation, and possibly rename the menu items without changing any code. I
want lots of functionality, and I don't want to have to work for it.
Since I'm lazy, I'll choose an off-the-shelf SAX XML parser to do my work for me. I'll specify the le format
as an XML le. Then I'll create a class called SaxMenuLoader that uses a SAX XML parser to create menu
structures de ned by XML, stores the menus in a Hashtable, and then returns the menus when I ask for
them by name.
This SaxMenuLoader will also listen for ActionEvents and ItemEvents from the menu items it creates, and
will call appropriate handler methods to handle the actions. Once I've written this SaxMenuLoader, all I need
to do in the future is create a SaxMenuLoader instance and tell it to load my XML menu speci cation; then I
can ask it by name for the MenuBars and PopupMenus de ned in the XML. (Well, I'll also have to write and
name the handlers, but that's application functionality. This system can't do everything for me. Yet.)

Menu XML
For this example, I've created a little language I'll call Menu XML. Depending on your application, you may
want to implement a standard XML dialect, de ned in a document type de nition (DTD) by a standards
organization or some other group. In this case, I'm just using XML for controlling the con guration of my
application, so I don't care if the XML is standardized.
I'll introduce Menu XML with an example, which appears in Listing 4. (See Resources for an HTML le for
Menu XML.)

001<?xmlversion="1.0"?>
002
003<Menus>
004
005<!Themenubaratthetopoftheframe>
006<MenuBarNAME="TopMenu">
007
008<MenuNAME="File"HANDLER="FileHandler">
009<MenuItemNAME="FileOpen"LABEL="Open..."/>
010<MenuItemNAME="FileSave"LABEL="Save"/>
011<MenuItemNAME="FileSaveAs"LABEL="SaveAs..."/>
012<MenuItemNAME="FileExit"LABEL="Exit"/>
013</Menu>
014
015<MenuNAME="Edit"HANDLER="EditHandler">
016<MenuItemNAME="EditUndo"LABEL="Undo"/>
017<MenuItemNAME="EditCut"LABEL="Cut"/>
018<MenuItemNAME="EditPaste"LABEL="Paste"/>
019<MenuItemNAME="EditDelete"LABEL="Delete"/>
020<CheckboxMenuItemNAME="EditReadOnly"LABEL="DisableButton1"
021HANDLER="Button1Enabler"/>
022</Menu>
023
024<MenuNAME="Help"HANDLER="HelpHandler">
025<MenuItemNAME="HelpAbout"LABEL="About"/>
026<MenuItemNAME="HelpTutorial"LABEL="Tutorial"/>
027</Menu>
028
029</MenuBar>
030
031<PopupMenuNAME="Pop1"HANDLER="PopupHandler">
032<MenuNAME="SubMenu1"HANDLER="SubMenu1Handler">
033<MenuItemNAME="Item1"COMMAND="ItemOne"/>
034<MenuItemNAME="Item2"COMMAND="ItemTwo"/>
035</Menu>
036<MenuItemNAME="Item3"COMMAND="ItemThree"/>
037<MenuItemNAME="Item4"COMMAND="ItemFour"/>
038<MenuItemNAME="Item5"COMMAND="ItemFive"
039HANDLER="com.javaworld.feb2000.sax.DynamicMenuItemHandler"/>
040</PopupMenu>
041
042</Menus>

Listing 4. Sample Menu XML to be processed by sample code


This language has just a few tags and attributes:
<Menus>: This is the document element for this language. The <menus> tag simply groups all of the

menus below it.


<MenuBarNAME="name">: The <MenuBar> tag de nes a new java.awt.MenuBar object. When parsing is

completed, the menu bar will be accessible by the given name.


<PopupMenuNAME="name">: The <PopupMenu> tag de nes a new java.awt.PopupMenu object. When

parsing is completed, the popup menu will be accessible by the given name.
<MenuItemNAME="name"[LABEL="label"][COMMAND="command"]>: This tag de nes a
java.awt.MenuItem. The item's label defaults to its name, but can be set with the LABEL attribute. The

default actionCommand for the item is also the item's name, but may be set with the COMMAND attribute.
<CheckboxMenuItemNAME="name"[LABEL="label"][COMMAND="command"]>: This tag de nes a
java.awt.CheckboxMenuItem. It's just like a MenuItem, except that the menu item checks and unchecks

when selected, instead of executing an action.


Any of these tags may optionally take an attribute HANDLER="handlerName", which indicates the name of the
handler for that object and all of its children (unless one of its children overrides the current handler by
de ning its own handler). The handler name indicates what object and method are to be called when the
menu item is activated. The mechanism for associated handler names with their handler objects is
explained in the implementation discussion below.
The containment relationship among the tags directly re ects the containment relationship of the resulting
objects. So, for example, the PopupMenu called Pop1 de ned in Listing 4, line 31, contains a single Menu and
three MenuItems. As the SaxMenuLoader class parses the XML le, it creates appropriate Java menu objects
and connects them to re ect the XML structure. Let's look at the code for SaxMenuLoader.

Load Menu XML with SAX: The SaxMenuLoader class


The following is a list of SaxMenuLoader's responsibilities:
Parses the Menu XML le using a SAX parser.
Builds the menu tree.
Acts as a repository for the MenuBar and PopupMenu items de ned in the Menu XML.
Maintains a repository of event handler objects that are called when the user selects menu items. An
event handler object is any object that implements interfaceMenuItemHandler, de ned by this package
to unify action and item events from menu items. Any object that implements this interface can receive
events from MenuItems de ned in Menu XML. (I'll cover the MenuItemHandler in more detail shortly.)
Acts as an ActionListener and ItemListener for all menu items.
Dispatches ActionEvents and ItemEvents to the appropriate handlers for the menu items.

Use SaxMenuLoader

The MenuDemo class takes two arguments: the name of the Menu XML le to parse, and the name of the
MenuBar to place in the application. MenuDemo.main() simply creates a MenuDemo instance, and calls that
instance's runDemo() method. The method MenuDemo.runDemo(), shown in Listing 5, demonstrates how to
use the SaxMenuLoader in use. (See Resources for an HTML le of SaxMenuLoader and MenuDemo.)
094publicvoidrunDemo(String[]args){
095SaxMenuLoadersml=newSaxMenuLoader();
096
097//BindnamesofhandlerstotheMenuItemHandlerstheyrepresent
098sml.registerMenuItemHandler("FileHandler",this);
099sml.registerMenuItemHandler("EditHandler",this);
100sml.registerMenuItemHandler("HelpHandler",this);
101sml.registerMenuItemHandler("PopupHandler",this);
102sml.registerMenuItemHandler("SubMenu1Handler",this);
103sml.registerMenuItemHandler("Button1Enabler",this);
104
105//Parsethefile
106sml.loadMenus(args[0]);
107
108//Ifmenuloadsucceeded,showthemenuinaframe
109MenuBarmenubarTop=sml.menubarFind(args[1]);
110if(menubarTop!=null){
111Frameframe=newFrame("Menudemo1");
112frame.addWindowListener(newWindowAdapter(){
113publicvoidwindowClosing(WindowEvente){
114System.exit(0);
115}
116});
117frame.setMenuBar(menubarTop);
118_b1=newButton("Button");
119_b1.addMouseListener(newMenuPopper(_b1,sml,"Pop1"));
120frame.add(_b1);
121frame.pack();
122frame.show();
123}else{
124System.out.println(args[1]+":nosuchmenu");
125}
126}

Listing 5. Using the SaxMenuLoader in the MenuDemo class


In Listing 5, line 95 creates the SaxMenuLoader. Then, lines 98 through 103 register the MenuDemo instance
(this) as the MenuItemHandler for all of the handler names referenced in the Menu XML le. Since MenuDemo
implements MenuItemHandler, it can receive callbacks from the menu items created in the Menu XML. These

registrations are what associate the symbolic menu item handler names with the application objects that
actually do the work. Line 106 tells the SaxMenuLoader to load the le, and line 109 gets the menu named
MenuTop from the SaxMenuLoader.
The rest of the code is straightforward AWT, except for line 119, which uses a MenuPopper object to
associate a Button object with a pop-up menu. MenuPopper is a convenience class I wrote that looks up a
named pop-up menu from a given SaxMenuLoader, and associates the pop-up menu with the given AWT
component. A MenuPopper is also a MouseListener, so that when the user clicks the center or left mouse
button on the MenuPopper's component, the MenuPopper shows the pop-up menu on top of that component.
This is all the code necessary to get menus from a Menu XML le. You might have noticed that this is about
as many lines of code as it took to create a small menu manually. But this technique provides much more
power. You can recon gure the menus without recompiling or redistributing any class les. What's more,
you can extend the application with new menu items and handlers for those items without recompiling. (I'll
discuss how to dynamically extend a running application with dynamic menu item handlers in the "Dynamic
Menu Item Handlers" section later in the article.) From now on, creating extensible application menus is a
lazy person's job!
So far, I've shown you how to use the SaxMenuLoader. Now let's take a look at how it works.

View 1 Comment
Copyright 1994 - 2016 JavaWorld, Inc. All rights reserved.

You might also like