Mega Code Archive
This program displays an XML document as a tree
/*
This program is a part of the companion code for Core Java 8th ed.
(http://horstmann.com/corejava)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.tree.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
/**
* This program displays an XML document as a tree.
* @version 1.11 2007-06-24
* @author Cay Horstmann
*/
public class DOMTreeTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new DOMTreeFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
/**
* This frame contains a tree that displays the contents of an XML document.
*/
class DOMTreeFrame extends JFrame
{
public DOMTreeFrame()
{
setTitle("DOMTreeTest");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
JMenu fileMenu = new JMenu("File");
JMenuItem openItem = new JMenuItem("Open");
openItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
openFile();
}
});
fileMenu.add(openItem);
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
System.exit(0);
}
});
fileMenu.add(exitItem);
JMenuBar menuBar = new JMenuBar();
menuBar.add(fileMenu);
setJMenuBar(menuBar);
}
/**
* Open a file and load the document.
*/
public void openFile()
{
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("."));
chooser.setFileFilter(new javax.swing.filechooser.FileFilter()
{
public boolean accept(File f)
{
return f.isDirectory() || f.getName().toLowerCase().endsWith(".xml");
}
public String getDescription()
{
return "XML files";
}
});
int r = chooser.showOpenDialog(this);
if (r != JFileChooser.APPROVE_OPTION) return;
final File file = chooser.getSelectedFile();
new SwingWorker()
{
protected Document doInBackground() throws Exception
{
if (builder == null)
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
builder = factory.newDocumentBuilder();
}
return builder.parse(file);
}
protected void done()
{
try
{
Document doc = get();
JTree tree = new JTree(new DOMTreeModel(doc));
tree.setCellRenderer(new DOMTreeCellRenderer());
setContentPane(new JScrollPane(tree));
validate();
}
catch (Exception e)
{
JOptionPane.showMessageDialog(DOMTreeFrame.this, e);
}
}
}.execute();
}
private DocumentBuilder builder;
private static final int DEFAULT_WIDTH = 400;
private static final int DEFAULT_HEIGHT = 400;
}
/**
* This tree model describes the tree structure of an XML document.
*/
class DOMTreeModel implements TreeModel
{
/**
* Constructs a document tree model.
* @param doc the document
*/
public DOMTreeModel(Document doc)
{
this.doc = doc;
}
public Object getRoot()
{
return doc.getDocumentElement();
}
public int getChildCount(Object parent)
{
Node node = (Node) parent;
NodeList list = node.getChildNodes();
return list.getLength();
}
public Object getChild(Object parent, int index)
{
Node node = (Node) parent;
NodeList list = node.getChildNodes();
return list.item(index);
}
public int getIndexOfChild(Object parent, Object child)
{
Node node = (Node) parent;
NodeList list = node.getChildNodes();
for (int i = 0; i < list.getLength(); i++)
if (getChild(node, i) == child) return i;
return -1;
}
public boolean isLeaf(Object node)
{
return getChildCount(node) == 0;
}
public void valueForPathChanged(TreePath path, Object newValue)
{
}
public void addTreeModelListener(TreeModelListener l)
{
}
public void removeTreeModelListener(TreeModelListener l)
{
}
private Document doc;
}
/**
* This class renders an XML node.
*/
class DOMTreeCellRenderer extends DefaultTreeCellRenderer
{
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected,
boolean expanded, boolean leaf, int row, boolean hasFocus)
{
Node node = (Node) value;
if (node instanceof Element) return elementPanel((Element) node);
super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
if (node instanceof CharacterData) setText(characterString((CharacterData) node));
else setText(node.getClass() + ": " + node.toString());
return this;
}
public static JPanel elementPanel(Element e)
{
JPanel panel = new JPanel();
panel.add(new JLabel("Element: " + e.getTagName()));
final NamedNodeMap map = e.getAttributes();
panel.add(new JTable(new AbstractTableModel()
{
public int getRowCount()
{
return map.getLength();
}
public int getColumnCount()
{
return 2;
}
public Object getValueAt(int r, int c)
{
return c == 0 ? map.item(r).getNodeName() : map.item(r).getNodeValue();
}
}));
return panel;
}
public static String characterString(CharacterData node)
{
StringBuilder builder = new StringBuilder(node.getData());
for (int i = 0; i < builder.length(); i++)
{
if (builder.charAt(i) == '\r')
{
builder.replace(i, i + 1, "\\r");
i++;
}
else if (builder.charAt(i) == '\n')
{
builder.replace(i, i + 1, "\\n");
i++;
}
else if (builder.charAt(i) == '\t')
{
builder.replace(i, i + 1, "\\t");
i++;
}
}
if (node instanceof CDATASection) builder.insert(0, "CDATASection: ");
else if (node instanceof Text) builder.insert(0, "Text: ");
else if (node instanceof Comment) builder.insert(0, "Comment: ");
return builder.toString();
}
}