XML Simple Editor
Có bạn nhở tôi viết 1 bài dùng SAX đọc file xml để tạo menu động. Trong app đó lại dùng SA để hiển thị XML dạng tree, app cho phép đọc file,.. Tốn thời gian 1 chút nhưng tôi làm 1 bài.
Class SAXMenuDemo
package vovanhai.wordpress.com;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* dùng SAX dọc XML sau đó tạo Menu
* @author VoVanHai
*
*/
public class SAXMenuDemo extends JFrame implements ActionListener{
private JMenuBar menubar;
private JEditorPane epContent;
private JTree tree;
private DefaultTreeModel treemodel;
private DefaultMutableTreeNode root;
public SAXMenuDemo() throws Exception{
this.setTitle("http://vovanhai.wordpress.com");
setExtendedState(MAXIMIZED_BOTH);
setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setJMenuBar(menubar=new JMenuBar());
createMenuFromXMLFile("menu.xml");
this.add(new JScrollPane(epContent=new JEditorPane()));
treemodel=new DefaultTreeModel(root=new DefaultMutableTreeNode("Root"));
JPanel pane=new JPanel(new BorderLayout());
pane.add(new JScrollPane(tree=new JTree(treemodel)));
pane.setPreferredSize(new Dimension(300, 300));
this.add(pane,BorderLayout.WEST);
}
private void createMenuFromXMLFile(String xmlFilePath) throws Exception{
SAXParserFactory spf=SAXParserFactory.newInstance();
SAXParser parser=spf.newSAXParser();
parser.parse(xmlFilePath, new MyHandler(this));
}
@Override
public void actionPerformed(ActionEvent e) {
String action=e.getActionCommand();
if(action.equalsIgnoreCase("Open")){
JFileChooser fc=new JFileChooser();
fc.setFileFilter(new FileFilter() {
@Override
public String getDescription() {
return "XML files (*.xml)";
}
@Override
public boolean accept(File f) {
return f.isDirectory()||f.getName().endsWith(".xml");
}
});
if(fc.showOpenDialog(null)==JFileChooser.APPROVE_OPTION){
File file=fc.getSelectedFile();
try {
epContent.read(new FileInputStream(file), null);
buildTree(file);
} catch (Exception e1) {
//e1.printStackTrace();
}
finally{
tree.expandRow(4);
tree.updateUI();
}
}
}
else if(action.equalsIgnoreCase("Save")){
JFileChooser fc=new JFileChooser();
fc.setFileFilter(new FileFilter() {
@Override
public String getDescription() {
return "XML files (*.xml)";
}
@Override
public boolean accept(File f) {
return f.isDirectory()||f.getName().endsWith(".xml");
}
});
if(fc.showSaveDialog(null)==JFileChooser.APPROVE_OPTION){
File file=fc.getSelectedFile();
try {
epContent.write(new FileWriter(file));
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
else if(action.equalsIgnoreCase("Exit")){
System.exit(1);
}
else if(action.equalsIgnoreCase("Cut")){
epContent.cut();
}
else if(action.equalsIgnoreCase("Copy")){
epContent.copy();
}
else if(action.equalsIgnoreCase("Paste")){
epContent.paste();
}
}
private void buildTree(File xmlfile) throws Exception{
SAXParserFactory spf=SAXParserFactory.newInstance();
SAXParser parser=spf.newSAXParser();
XMLReader reader = parser.getXMLReader();
ContentHandler jTreeContentHandler =
new JTreeContentHandler(treemodel, root);
ErrorHandler jTreeErrorHandler = new JTreeErrorHandler();
reader.setContentHandler(jTreeContentHandler);
reader.setErrorHandler(jTreeErrorHandler);
// Parse
InputSource inputSource = new InputSource(xmlfile.getAbsolutePath());
reader.parse(inputSource);
}
class MyHandler extends DefaultHandler{
JMenu parent;
ActionListener frm;
public MyHandler(ActionListener frm) {
this.frm=frm;
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(qName.equals("menu")){
String name=attributes.getValue(0);
parent=new JMenu(name);
menubar.add(parent);
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String name=new String(ch,start,length).trim();
if(parent!=null && !name.trim().equals(""))
addMenu(parent,name,frm);
}
void addMenu(JMenu menu,String text,ActionListener parent){
JMenuItem item=new JMenuItem(text);
menu.add(item);
item.addActionListener(parent);
parent=null;
}
}
public static void main(String[] args) throws Exception{
new SAXMenuDemo().setVisible(true);
}
}
Lớp JTreeContentHandler.java để parse xml file sau đó tạo tree
package vovanhai.wordpress.com;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
class JTreeContentHandler extends DefaultHandler{
private Map<String, String> namespaceMappings;
private DefaultMutableTreeNode current;
public JTreeContentHandler(DefaultTreeModel treeModel,
DefaultMutableTreeNode base) {
this.current = base;
this.namespaceMappings = new HashMap<String, String>();
}
public void processingInstruction(String target, String data)
throws SAXException {
DefaultMutableTreeNode pi =
new DefaultMutableTreeNode("PI (target = '" + target +
"', data = '" + data + "')");
current.add(pi);
}
public void startPrefixMapping(String prefix, String uri) {
namespaceMappings.put(uri, prefix);
}
public void endPrefixMapping(String prefix) {
for (Iterator<String> i = namespaceMappings.keySet().iterator();
i.hasNext(); ) {
String uri = (String)i.next();
String thisPrefix = (String)namespaceMappings.get(uri);
if (prefix.equals(thisPrefix)) {
namespaceMappings.remove(uri);
break;
}
}
}
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts)
throws SAXException {
DefaultMutableTreeNode element =
new DefaultMutableTreeNode("Element: " + qName);
current.add(element);
current = element;
// Determine namespace
if (namespaceURI.length() > 0) {
String prefix =
(String)namespaceMappings.get(namespaceURI);
if (prefix.equals("")) {
prefix = "[None]";
}
DefaultMutableTreeNode namespace =
new DefaultMutableTreeNode("Namespace: prefix = '" +
prefix + "', URI = '" + namespaceURI + "'");
current.add(namespace);
}
// Process attributes
for (int i=0; i<atts.getLength(); i++) {
DefaultMutableTreeNode attribute =
new DefaultMutableTreeNode("Attribute (name = '" +
atts.getLocalName(i) +
"', value = '" +
atts.getValue(i) + "')");
String attURI = atts.getURI(i);
if (attURI.length() > 0) {
String attPrefix =
(String)namespaceMappings.get(namespaceURI);
if (attPrefix.equals("")) {
attPrefix = "[None]";
}
DefaultMutableTreeNode attNamespace =
new DefaultMutableTreeNode("Namespace: prefix = '" +
attPrefix + "', URI = '" + attURI + "'");
attribute.add(attNamespace);
}
current.add(attribute);
}
}
public void endElement(String namespaceURI, String localName,
String qName)
throws SAXException {
current = (DefaultMutableTreeNode)current.getParent();
}
public void characters(char[] ch, int start, int length)
throws SAXException {
String s = new String(ch, start, length);
if(!s.trim().equals("")){
DefaultMutableTreeNode data =
new DefaultMutableTreeNode("Character Data: '" + s + "'");
current.add(data);
}
}
public void skippedEntity(String name) throws SAXException {
DefaultMutableTreeNode skipped =
new DefaultMutableTreeNode("Skipped Entity: '" + name + "'");
current.add(skipped);
}
}
Lớp JTreeErrorHandler.java thông báo lỗi trong quá trình parse xml document
package vovanhai.wordpress.com;
import javax.swing.JOptionPane;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
class JTreeErrorHandler implements ErrorHandler {
public void warning(SAXParseException exception)
throws SAXException {
String s=("**Parsing Warning**\n" +
" Line:" +exception.getLineNumber() + "\n" +
" URI:" +exception.getSystemId() + "\n" +
" Message: " +exception.getMessage());
JOptionPane.showMessageDialog(null, s,"Thông báo",JOptionPane.ERROR_MESSAGE);
}
public void error(SAXParseException exception)
throws SAXException {
String s=("**Parsing Error**\n" +
" Line:" +exception.getLineNumber() + "\n" +
" URI:" +exception.getSystemId() + "\n" +
" Message:" +exception.getMessage());
JOptionPane.showMessageDialog(null, s,"Thông báo",JOptionPane.ERROR_MESSAGE);
}
public void fatalError(SAXParseException exception)
throws SAXException {
String s=("**Parsing Fatal Error**\n" +
" Line:" + exception.getLineNumber() + "\n" +
" URI:" + exception.getSystemId() + "\n" +
" Message:" +exception.getMessage());
JOptionPane.showMessageDialog(null, s,"Thông báo",JOptionPane.ERROR_MESSAGE);
}
}
File menu.xml là file có cấu trúc menu. Bạn thêm 1 element menu là có thêm 1 menu, 1 item element là có thêm sub menu.
<?xml version="1.0" encoding="UTF-8"?> <menus> <menu name="File"> <item>Open</item> <item>Save</item> <item>Exit</item> </menu> <menu name="Edit"> <item>Cut</item> <item>Copy</item> <item>Paste</item> </menu> </menus>
OK. Chạy! Kết quả như sau:

Chúc thành công
Huynh Thi Diu said
Cám ơn thầy nhiều, nhờ thầy mà em đã hiểu đc nhiều vấn đề về SAX và DOM
Chúc Thầy nhiều sức khỏe và hướng dẫn thêm cho em cũng như các bạn yêu java!