.useful Java library

About
License

Documentation

Why dotuseful?
Dynamic Tree Tutorial
XML Tree Tutorial
API Reference

 

Articles

Post-MVC

 

Download
Forums
.useful Team
Contribute

Hosted by

SourceForge.net Logo

Tutorial - Automated DOM Tree

//in development

Well, let's build an example which uses Automated Tree Model and Nodes. What was the reason I developed these classes? I used them in contact list representation of multi-system Instant Messaging client. I wanted to have possibility to rule node contents directly from the node itself. As a node contents I consider the node itself and its children. I found the design of my application become much more easier and decopulated if I follow this rule. Now I'm going to apply AutomatedTree classes by building a visual tree representation of XML documents.

Let's define requirements for our AutomatedXMLTree. We will have a frame with a tree, a text input field for a name of XML source, and a button which we will use to load the source and present it in a tree. We will care as little as possible on aspects which are not related to AutomatedTree classes such as errors.

After a brief search for XML introduction with Java we can find this article
http://java.sun.com/developer/TechTips/2000/tt0627.html
which introduces XML and 2 APIs – SAX API and DOM API. After a brief review we can see that SAX uses events for notification of XML markup elements while DOM can give us a tree-like structure of XML document. This API does not require you to install J2EE SDK as it comes with Java 2 Standard Edition. So DOM API is a logical choice for our example.

Let's do some analysis on how we are going to build AutomatedXMLTree . We need a Model of XML source we need to show. We need a View+Controller of our model – a visual tree. At this point we do not need some extensive Controller for our tree as we are not going to modify it. We need AppController for our application which will take user input, create a new tree Model and represent it in View.

Let's start by creating AutomatedXMLTree class which extends JFrame and contains a JTree , a JTextField and a JButton.

  
package org.dotuseful.ui.tree;

import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;

public class AutomatedXMLTree extends JFrame {
	protected static final String APP_NAME = "Automated XML Tree";

	protected static final int X_SIZE = 400;

	protected static final int Y_SIZE = 400;

	protected JTree m_tree;

	public AutomatedXMLTree() {
		super(APP_NAME);
		setSize(X_SIZE, Y_SIZE);
		getContentPane().setLayout(new BorderLayout());
		JPanel cp = createControlPanel();
		getContentPane().add(cp, BorderLayout.SOUTH);
		m_tree = new JTree();
		m_tree.setEditable(false);
		JScrollPane s = new JScrollPane(m_tree);
		getContentPane().add(s, BorderLayout.CENTER);
	}

	protected JPanel createControlPanel() {
		JPanel cp = new JPanel();
		JTextField fNameTextField = new JTextField();
		fNameTextField.setColumns(20);
		cp.add(fNameTextField);
		JButton bt = new JButton("Open");
		bt.setToolTipText("Open XML Source");
		cp.add(bt);
		return cp;
	}

	public static void main(String[] args) {
		AutomatedXMLTree frame = new AutomatedXMLTree();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}

Now we need to add a reference to a Model of XML source we need to show. What class will we use as XMLModel ? DOM parser javax.xml.parsers.DocumentBuilder.parse(...) returns org.w3c.dom.Document instance which seems to be suitable.

Now we can add AppController functionality to our JButton . As a button pressed, we need to throw off old XMLModel and old view, create a new XMLModel with a given source, and create a new view assigned to new model.

Actually we will not throw away an old view, which is JTree , but will give to JTree a new TreeModel which is associated with new XMLModel .


package org.dotuseful.ui.tree;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

public class AutomatedXMLTree extends JFrame {
	protected static final String APP_NAME = "Automated XML Tree";

	protected static final int X_SIZE = 400;

	protected static final int Y_SIZE = 400;

	protected Document xmlModel;

	protected JTree xmlTree;

	protected JTextField fNameTextField;

	public AutomatedXMLTree() {
		super(APP_NAME);
		setSize(X_SIZE, Y_SIZE);
		getContentPane().setLayout(new BorderLayout());
		JPanel cp = createControlPanel();
		getContentPane().add(cp, BorderLayout.SOUTH);
		xmlTree = new JTree();
		xmlTree.setEditable(false);
		JScrollPane s = new JScrollPane(xmlTree);
		getContentPane().add(s, BorderLayout.CENTER);
	}

	protected JPanel createControlPanel() {
		JPanel cp = new JPanel();
		fNameTextField = new JTextField();
		fNameTextField.setColumns(20);
		cp.add(fNameTextField);
		JButton bt = new JButton("Open");
		bt.setToolTipText("Open file");
		ActionListener lst = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				openDocument();
			}
		};
		bt.addActionListener(lst);
		cp.add(bt);
		return cp;
	}

	protected void openDocument() {
		try {
			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
			xmlModel = docBuilder.parse(fNameTextField.getText());
			((DefaultTreeModel) (xmlTree.getModel()))
					.setRoot(new DefaultMutableTreeNode(xmlModel));
			setTitle(APP_NAME + " - [" + fNameTextField.getText() + "]");
		} catch (Exception ex) {
			ex.printStackTrace();
			JOptionPane.showMessageDialog(this,
					"Error reading or parsing XML file", APP_NAME,
					JOptionPane.WARNING_MESSAGE);
		} finally {
			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		}
	}

	public static void main(String[] args) {
		AutomatedXMLTree frame = new AutomatedXMLTree();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}

Wow! We've got some node. Now we need to build a visual TreeModel from our XMLModel. Here is where my AutomatedTree classes come to play.

package org.dotuseful.ui.tree;

import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XMLTreeNode extends AutomatedTreeNode {

	/**
	 * @param xmlNode
	 */
	public XMLTreeNode(Node xmlNode) {
		super(xmlNode);
		createChildren();
	}

	/**
	 * Creates visual child nodes + attributes
	 */
	protected void createChildren() {
		if (getXMLNode().hasAttributes()) {
			createAttributes();
		}
		createChildNodes();
	}

	/**
	 * Creates children
	 */
	protected void createChildNodes() {
		Node xmlNode = getXMLNode();
		NodeList childXMLNodes = xmlNode.getChildNodes();
		for (int i = 0; i < childXMLNodes.getLength(); i++) {
			add(new XMLTreeNode(childXMLNodes.item(i)));
		}
	}

	/**
	 * Creates attribute nodes
	 */
	protected void createAttributes() {
		Node xmlNode = getXMLNode();
		NamedNodeMap attributes = xmlNode.getAttributes();
		for (int i = 0; i < attributes.getLength(); i++) {
			add(new XMLTreeNode(attributes.item(i)));
		}
	}

	public Node getXMLNode() {
		return (Node) getUserObject();
	}

	public String toString() {
		return getXMLNode().getNodeName();
	}
}

Now we need to change our AutomatedXMLTree frame to use AutomatedTreeModel as a model for JTree and XMLTreeNode as its root.


package org.dotuseful.ui.tree;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeModel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

public class AutomatedXMLTree extends JFrame {
	protected static final String APP_NAME = "Automated XML Tree";

	protected static final int X_SIZE = 400;

	protected static final int Y_SIZE = 400;

	protected Document xmlModel;

	protected JTree xmlTree;

	protected JTextField fNameTextField;

	public AutomatedXMLTree() {
		super(APP_NAME);
		setSize(X_SIZE, Y_SIZE);
		getContentPane().setLayout(new BorderLayout());
		JPanel cp = createControlPanel();
		getContentPane().add(cp, BorderLayout.SOUTH);
		xmlTree = new JTree(new AutomatedTreeModel(null));
		xmlTree.setEditable(false);
		JScrollPane s = new JScrollPane(xmlTree);
		getContentPane().add(s, BorderLayout.CENTER);
	}

	protected JPanel createControlPanel() {
		JPanel cp = new JPanel();
		fNameTextField = new JTextField();
		fNameTextField.setColumns(20);
		cp.add(fNameTextField);
		JButton bt = new JButton("Open");
		bt.setToolTipText("Open file");
		ActionListener lst = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				openDocument();
			}
		};
		bt.addActionListener(lst);
		cp.add(bt);
		return cp;
	}

	protected void openDocument() {
		try {
			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
			xmlModel = docBuilder.parse(fNameTextField.getText());
			((DefaultTreeModel) (xmlTree.getModel())).setRoot(new XMLTreeNode(
					xmlModel));
			setTitle(APP_NAME + " - [" + fNameTextField.getText() + "]");
		} catch (Exception ex) {
			ex.printStackTrace();
			JOptionPane.showMessageDialog(this,
					"Error reading or parsing XML file", APP_NAME,
					JOptionPane.WARNING_MESSAGE);
		} finally {
			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		}
	}

	public static void main(String[] args) {
		AutomatedXMLTree frame = new AutomatedXMLTree();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}

Congratulations – you've finished AutomatedXMLTree sample!

You can even parse HTML files

Now wait!

Curious developer can say: "I could do the same using DefaultTreeModel and DefaultMutableTreeNode!". Right! Now I'll show you what you can't.

Let's suppose we need our tree to be dynamic. We could have our XML source changed, and we want a tree to reflect these changes. We would even create an XML editor based on our viewer in the future.

 

Have thoughts? We want to hear from you! Contact us on our forums.