Tutorial 1: A Simple Menu Loader

Introduction

In this tutorial, I will show you how to use CookXml to create a tag library that loads XML document (menubar1.xml) like the following into a Swing JMenuBar.

<menubar>
	<menu text="File">
		<menu text="Open">
			<menuitem text="XML"/>
			<menuitem text="Java"/>
		</menu>
		<menuitem text="Exit"/>
	</menu>
	<menu text="Edit">
		<menuitem text="Cut"/>
		<menuitem text="Copy"/>
		<menuitem text="Paste"/>
	</menu>
	<menu text="Help">
		<menuitem text="About"/>
	</menu>
</menubar>

Notice that I did not provide an XML schema, since JMenuBar, JMenu and JMenuItem classes themselves already defined their relationships. For instance, there is no way to add a JMenu as a child of JMenuItem.

This tutorial does not require libraries other than the CookXml Core and Common library (cookxml package).

Step 1: Create a TagLibrary

The very first step of of using CookXml is to create a tag library that will hold all the definitions. There are two choices: TagLibrary or InhertiableTagLibrary. InheritableTagLibrary is more powerful than TagLibrary, but in our simple example, TagLibrary is suffice.

TagLibrary tagLibrary = new TagLibrary ();

Step 2: Tag Creators

Creators are object factories which tell CookXml how to manufacture an object.

We will map <menubar> to JMenuBar, <menu> to JMenu and <menuitem> to JMenuItem. These three classes all have default constructors, so we can use DefaultCreator to generate creators for us using Java Reflection API.

It should be noted that CookXml does not require Java Reflection API to work, but using reflection saves us from doing many tedious works.

tagLibrary.setCreator ("menubar", DefaultCreator.getCreator (JMenuBar.class));
tagLibrary.setCreator ("menu", DefaultCreator.getCreator (JMenu.class));
tagLibrary.setCreator ("menuitem", DefaultCreator.getCreator (JMenuItem.class));

Step 3: Setters

Setters are used to modify objects based on attributes. In our cases, both <menu> and <menuitem> have text attribute. If DefaultSetter is used, then CookXml looks for either an accessible text variable or a public setText (parameter) function through Java reflection. Conveniently, both JMenu and JMenuItem has setText function, so we can use the DefaultSetter for both.

tagLibrary.setSetter ("menu", "text", DefaultSetter.getInstance ());
tagLibrary.setSetter ("menuitem", "text", DefaultSetter.getInstance ());

Of course, if we could not use DefaultSetter, the procedure would be slightly more complicated (still a one-line code), so it is usually a good idea to design XML attributes such that they directly correspond to Java variables/functions.

Often times, it is not necessary to specify DefaultSetter explicitly for all attributes it can handles. One can tell CookXml to use it by default:

tagLibrary.setSetter (null, null, DefaultSetter.getInstance ());

Step 4: Adders

Adders are used to add an object created by a child tag element to the object created by the parent tag element. In this case, we need to be able to add objects correspond to <menu> to object <menubar>, <menu> to <menu> and <menuitem> to <menu>.

CookXml provides DefaultAdder which can look for add (parameter) function of the parent object. It first looks up the add function that has the parameter class as the child object type. If that fails, then it tries to lookup other add functions that can handle the child object. This behavior is quite similar to that of Java compiler.

In this case, both JMenuBar and JMenu classes have corresponding add functions which can be found by DefaultAdder. So we will use it.

tagLibrary.setAdder ("menubar", DefaultAdder.getInstance ());
tagLibrary.setAdder ("menu", DefaultAdder.getInstance ());
tagLibrary.setAdder ("menuitem", DefaultAdder.getInstance ());

Again, we can avoid the repetive specification by telling CookXml to use DefaultAdder as default.

tagLibrary.setAdder (null, DefaultAdder.getInstance ());

At this point, we have finished contructing the tag library needed for parsing the XML.

Step 5: Testing

To create a new instance of CookXml object, one need a DocumentBuilder for parsing XML documents and a tag library. CookXml does not validate XML by itself. If you have DTD file, you can choose to use a validating DocumentBuilder instead. The third parameters tells CookXml how to lookup variables, which will be explained in other tutorials.

JMenuBar menuBar;

try
{
	// the DocumentBuilder used to parse the XML Document
	DocumentBuilder builder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
	CookXml cookXml = new CookXml (builder, s_tagLibrary, (Object)null);
	menuBar = (JMenuBar)cookXml.xmlDecode ("menubar1.xml");
}
catch (Exception ex)
{
	ex.printStackTrace ();
	return;
}

Resources