I'm developing a JavaSE-1.7 Swing application that displays XML files as a JTree
. This will be the base for further work, e.g. filtering nodes.
My questions, as a beginner in Java & Swing & MVC:
- Design: How would you refactor this into Model/View/Controller?
(Doing the doc/tree model stuff inside of the GUI thread isn't best practice, I think.) - Performance: How can I speed up
expandAllNodes()
? It eats up ~85% of total time with my 0.5MB target file. - What else could be improved?
Below is my working example:
package xml;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.io.File;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Uses Ibbtek's code from <http://ibbtek.altervista.org/XML2JTree> under MIT
* license.
*/
public class XmlToJtree {
private File file;
private Document document;
private DefaultTreeModel treeModel;
private JTree treeView;
/**
* Constructor.
*
* @param filePath
*/
public XmlToJtree(String path) {
if (path != null) {
file = new File(path);
}
if (file != null && file.canRead()) {
document = parseDomFromXml(file);
}
if (document != null) {
treeModel = new DefaultTreeModel(buildTreeNode(document));
}
if (treeModel != null) {
treeView = new JTree(treeModel);
}
}
/**
* Expand all tree nodes.
*/
public void expandAllNodes() {
if (treeView != null) {
for (int i = 0; i < treeView.getRowCount(); i++) {
treeView.expandRow(i);
}
}
}
/**
* Show window.
*
* @param title
* @param width
* @param height
*/
public void show(String title, int width, int height) {
if (treeView != null) {
JFrame frame = new JFrame(title);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(new JScrollPane(treeView));
frame.add(new JPanel(new GridLayout(1, 1)), BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
/**
* Recursively build tree node from document node. Add attributes as leaves
*
* @param docNode
* @return A default mutable tree node.
*/
private DefaultMutableTreeNode buildTreeNode(Node docNode) {
DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(
docNode.getNodeName());
if (docNode.hasAttributes()) {
NamedNodeMap attributes = docNode.getAttributes();
for (int j = 0; j < attributes.getLength(); j++) {
String attr = attributes.item(j).toString();
treeNode.add(new DefaultMutableTreeNode(attr));
}
}
if (docNode.hasChildNodes()) {
NodeList childNodes = docNode.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
short childNodeType = childNode.getNodeType();
if (childNodeType == Node.ELEMENT_NODE) {
treeNode.add(buildTreeNode(childNode));
} else if (childNodeType == Node.TEXT_NODE) {
String text = childNode.getTextContent().trim();
if (!text.equals("")) {
treeNode.add(new DefaultMutableTreeNode(text));
}
} else if (childNodeType == Node.COMMENT_NODE) {
String comment = childNode.getNodeValue().trim();
treeNode.add(new DefaultMutableTreeNode(comment));
}
}
}
return treeNode;
}
/**
* Parse an XML file into document object model.
*
* @param filePath
* @return A DOM document.
*/
private Document parseDomFromXml(File file) {
Document document = null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
document = dbf.newDocumentBuilder().parse(file);
document.normalizeDocument();
} catch (IOException | ParserConfigurationException | SAXException e) {
e.printStackTrace();
}
return document;
}
/**
* Run the program.
*
* @param args
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
XmlToJtree x2j = new XmlToJtree("simple.xml");
x2j.expandAllNodes();
x2j.show(x2j.file.getName(), 400, 600);
}
});
}
}
Sample XML "simple.xml":
<?xml version="1.0" encoding="utf-8"?>
<!-- created by ferkulat -->
<MYXML xmlns="namespace">
<Header id="header"></Header>
<Product id="product">
<Description id="description">Some text</Description>
<Ref id="ref"></Ref>
<Data id="data">
<Ref id="ref"></Ref>
</Data>
<Form id="form"></Form>
</Product>
</MYXML>
And this is the result: