2
\$\begingroup\$

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:

  1. 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.)
  2. Performance: How can I speed up expandAllNodes()? It eats up ~85% of total time with my 0.5MB target file.
  3. 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:

result

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.