Võ Văn Hải's blog

Chỉ có một điều tuyệt đối đó là mọi thứ đều tương đối…

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("https://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:
https://vovanhai.files.wordpress.com/2011/03/saxtree.png
Chúc thành công

One Response to “XML Simple Editor”

  1. 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!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 2,192 other followers

%d bloggers like this: