1. 程式人生 > >sax解析實現xml增刪改

sax解析實現xml增刪改

需求:

     在jsp頁面上展示樹形結構,當選中某個節點時,可以新增該節點的子節點、刪除該節點、修改該節點資訊。

     操作節點的時候,既操作資料庫,也操作xml檔案。先操作資料庫,後操作xml檔案。

     如果操作資料庫失敗,則不再操作xml檔案。

說明:

      1. menuNo 是唯一的;

      2. 節點層次只有一層,但是各個節點之間有關聯關係。如:menuNo=1 的子節點以“1-”(不包括雙引號)

           開頭;

      3. 在新增節點時,節點編號menuNo自動生成(查詢資料庫中menuNo的最大值,在此基礎上加1);

      4. 這裡只寫對xml檔案的操作,不寫資料庫操作。

環境說明:

    jdk-6u21;

jar 包:

     dom4j-1.6.1.jar;

     jaxen-1.1.4.jar;

     log4j-1.2.16.jar;

     slf4j-api-1.4.3.jar;

     slf4j-log4j12-1.4.0.jar

XML 檔案:

<?xml version="1.0" encoding="UTF-8"?>

<root>
  <menu id="8a8080fd45d529340145d5294acf0000">
    <menuId>8a8080fd45d529340145d5294acf0000</menuId>
    <menuNo>1</menuNo>
    <parentNo>123</parentNo>
    <menuName>首頁</menuName>
    <menuUrl>/home</menuUrl>
    <menuLevel>1</menuLevel>
    <isLeaf>0</isLeaf>
    <expanded>1</expanded>
    <loaded>1</loaded>
  </menu>
  <menu id="8a8080fd45d52b520145d52b64c30000">
    <menuId>8a8080fd45d52b520145d52b64c30000</menuId>
    <menuNo>1-1</menuNo>
    <parentNo>1</parentNo>
    <menuName>首頁1</menuName>
    <menuUrl>index/index/homePage</menuUrl>
    <menuLevel>2</menuLevel>
    <isLeaf>1</isLeaf>
    <expanded>1</expanded>
    <loaded>1</loaded>
  </menu>
  <menu id="92e0b82fae0f4bbbaf7f478031d59b1f">
    <menuId>92e0b82fae0f4bbbaf7f478031d59b1f</menuId>
    <menuNo>1-2</menuNo>
    <parentNo>1</parentNo>
    <menuName>首頁2</menuName>
    <menuUrl>index/index1</menuUrl>
    <menuLevel>2</menuLevel>
    <isLeaf>1</isLeaf>
    <expanded>1</expanded>
    <loaded>1</loaded>
  </menu>
  <menu id="8a8080fd45dea7320145dea755cd0000">
    <menuId>8a8080fd45dea7320145dea755cd0000</menuId>
    <menuNo>2</menuNo>
    <parentNo/>
    <menuName>系統管理</menuName>
    <menuUrl/>
    <menuLevel>1</menuLevel>
    <isLeaf>0</isLeaf>
    <expanded>1</expanded>
    <loaded>1</loaded>
  </menu>
  <menu id="8a8080fd45dea92f0145dea942bf0000">
    <menuId>8a8080fd45dea92f0145dea942bf0000</menuId>
    <menuNo>2-1</menuNo>
    <parentNo>2</parentNo>
    <menuName>選單配置管理</menuName>
    <menuUrl>hw/menu</menuUrl>
    <menuLevel>2</menuLevel>
    <isLeaf>1</isLeaf>
    <expanded>1</expanded>
    <loaded>1</loaded>
  </menu>
</root>

其中,“首頁1” 和 “首頁2” 是 “首頁” 的子節點;“選單配置管理” 是 “系統管理” 的子節點;

需要用一個 JavaBean 來表示選單節點:

HwMenu.java
public class HwMenu {

	private String menuId;
	// 選單編號 (Unique Key)
	private String menuNo;
	// 選單名稱
	private String menuName;
	// 菜單鏈接
	private String menuUrl;
	// 選單等級
	private String menuLevel;
	// 父編號 (對應 menuNo)
	private String parentNo;
	// 是否子節點. 0 : false , 1 : true
	private Integer isLeaf;
	// 是否展開. 0 : false , 1 : true
	private Integer expanded;
	// 是否載入. 0 : false , 1 : true
	private Integer loaded;

	// 省略getter/setter
}

xml節點處理類:

MenuTree.java

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MenuTree {

	private static final Logger log = LoggerFactory.getLogger(MenuTree.class);

	private static final String XML_FILE = "xml/menu.xml";

	/**
	 * @Title: addNode
	 * @deprecated: 將節點menu新增到xml檔案中
	 * @param menu
	 *            : 節點資訊
	 * @throws Exception
	 * @author 
	 * @date 2014-5-9
	 */
	public void addNode(HwMenu menu) throws Exception {

		XMLWriter xmlwriter = null;
		InputStream is = null;
		OutputStream out = null;

		try {
			SAXReader sax = new SAXReader();

			// 建立一個 menu 元素
			Element elt = DocumentHelper.createElement("menu");
			// 主鍵id
			Element menuId = DocumentHelper.createElement("menuId");
			// 選單編號
			Element menuNo = DocumentHelper.createElement("menuNo");
			// 父編號
			Element parentNo = DocumentHelper.createElement("parentNo");
			// 選單名稱
			Element menuName = DocumentHelper.createElement("menuName");
			// 菜單鏈接
			Element menuUrl = DocumentHelper.createElement("menuUrl");
			// 選單等級
			Element menuLevel = DocumentHelper.createElement("menuLevel");
			// 是否子節點
			Element isLeaf = DocumentHelper.createElement("isLeaf");
			// 是否展開
			Element expanded = DocumentHelper.createElement("expanded");
			// 是否載入
			Element loaded = DocumentHelper.createElement("loaded");

			menuId.setText(menu.getMenuId());
			menuNo.setText(menu.getMenuNo());
			parentNo.setText(menu.getParentNo());
			menuName.setText(menu.getMenuName());
			menuUrl.setText(menu.getMenuUrl());
			menuLevel.setText(menu.getMenuLevel());
			// 是否子節點. 0 : false , 1 : true
			isLeaf.setText(menu.getIsLeaf() + "");
			// 是否展開. 0 : false , 1 : true
			expanded.setText(menu.getExpanded() + "");
			// 是否載入. 0 : false , 1 : true
			loaded.setText(menu.getLoaded() + "");

			is = Thread.currentThread().getContextClassLoader()
					.getResourceAsStream(XML_FILE);

			Document doc = sax.read(is);

			// 根節點
			Element root = doc.getRootElement();

			// 將子元素新增到 menu 元素中
			elt.add(menuId);
			elt.add(menuNo);
			elt.add(parentNo);
			elt.add(menuName);
			elt.add(menuUrl);
			elt.add(menuLevel);
			elt.add(isLeaf);
			elt.add(expanded);
			elt.add(loaded);

			// 為 menu 新增 id 屬性
			elt.addAttribute("id", menu.getMenuId());

			// 將menu元素新增到根節點下
			root.add(elt);

			// 輸出格式
			OutputFormat outformat = new OutputFormat();
			// 指定XML編碼
			outformat.setEncoding("UTF-8");
			outformat.setNewlines(true);
			outformat.setIndent(true);
			outformat.setTrimText(true);

			String rootPath = System.getProperty("user.dir");

			out = new FileOutputStream(rootPath + "/src-config/" + XML_FILE);

			xmlwriter = new XMLWriter(out, outformat);

			xmlwriter.write(doc);

		} catch (DocumentException e) {
			log.error("Add Node fail:" + e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error("Add Node fail:" + e.getMessage(), e);
			throw e;
		} finally {
			close(xmlwriter, out, is);
		}
	}

	/**
	 * @Title: modifyNode
	 * @deprecated: 修改節點元素值
	 * @param menu
	 *            元素值
	 * @author 
	 * @date 2014-5-12
	 */
	@SuppressWarnings("rawtypes")
	public void modifyNode(HwMenu menu) throws Exception {

		InputStream is = null;
		OutputStream out = null;
		XMLWriter xmlwriter = null;

		Document doc = null;

		try {
			SAXReader sax = new SAXReader();

			is = Thread.currentThread().getContextClassLoader()
					.getResourceAsStream(XML_FILE);

			doc = sax.read(is);

			// 根節點
			Element root = doc.getRootElement();

			// 取得某節點下名為"menu"的所有位元組點
			List nodes = root.elements("menu");

			// xml元素
			Element element = null;

			for (Object obj : nodes) {
				element = (Element) obj;
				// 修改指定節點下的子節點的值
				if (menu.getMenuId().equals(element.attributeValue("id"))) {
					element.element("menuId").setText(menu.getMenuId());
					element.element("menuNo").setText(menu.getMenuNo());
					element.element("parentNo").setText(menu.getParentNo());
					element.element("menuName").setText(menu.getMenuName());
					element.element("menuUrl").setText(menu.getMenuUrl());
					element.element("menuLevel").setText(menu.getMenuLevel());
					element.element("isLeaf").setText(menu.getIsLeaf() + "");
					element.element("expanded")
							.setText(menu.getExpanded() + "");
					element.element("loaded").setText(menu.getLoaded() + "");
				}
			}

			// 輸出格式
			OutputFormat outformat = new OutputFormat();
			// 指定XML編碼
			outformat.setEncoding("UTF-8");
			outformat.setNewlines(true);
			outformat.setIndent(true);
			outformat.setTrimText(true);

			String rootPath = System.getProperty("user.dir");

			out = new FileOutputStream(rootPath + "/src-config/" + XML_FILE);

			xmlwriter = new XMLWriter(out, outformat);

			xmlwriter.write(doc);

		} catch (DocumentException e) {
			log.error("Modify Node fail:" + e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error("Modify Node fail:" + e.getMessage(), e);
			throw e;
		} finally {
			close(xmlwriter, out, is);
		}
	}

	@SuppressWarnings("rawtypes")
	public void removeNode(String nodeId) throws Exception {

		InputStream is = null;
		OutputStream out = null;
		XMLWriter xmlwriter = null;

		Document doc = null;

		try {
			SAXReader sax = new SAXReader();

			is = Thread.currentThread().getContextClassLoader()
					.getResourceAsStream(XML_FILE);

			doc = sax.read(is);

			// 根節點
			Element root = doc.getRootElement();

			// 取得某節點下名為"menu"的所有位元組點
			List nodes = root.elements("menu");

			// xml元素
			Element element = null;
			Map<String, String> map = new ConcurrentHashMap<String, String>();

			for (Object obj : nodes) {
				element = (Element) obj;
				// 選單編號
				String menuNo = null;
				// 刪除指定節點下的子節點的值
				if (nodeId.equals(element.attributeValue("id"))) {

					menuNo = element.element("menuNo").getTextTrim();

					map.put("p_menuNo", menuNo);
					// 刪除nodeId對應的選單節點
					element.detach();
				}

				// 節點編號
				menuNo = element.element("menuNo").getTextTrim();

				if (null != map.get("p_menuNo")
						&& !"".equals(map.get("p_menuNo"))) {

					if (null != menuNo
							&& menuNo.startsWith(map.get("p_menuNo")
									.concat("-"))) {
						/* menuNo是 p_menuNo 的子節點 */
						// 刪除子節點
						element.detach();
					}
				}
			}

			// 輸出格式
			OutputFormat outformat = new OutputFormat();
			// 指定XML編碼
			outformat.setEncoding("UTF-8");
			outformat.setNewlines(true);
			outformat.setIndent(true);
			outformat.setTrimText(true);

			String rootPath = System.getProperty("user.dir");

			out = new FileOutputStream(rootPath + "/src-config/" + XML_FILE);

			xmlwriter = new XMLWriter(out, outformat);

			xmlwriter.write(doc);

		} catch (DocumentException e) {
			log.error("Modify Node fail:" + e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error("Modify Node fail:" + e.getMessage(), e);
			throw e;
		} finally {
			close(xmlwriter, out, is);
		}
	}

	private void close(XMLWriter xmlwriter, OutputStream out, InputStream is) {

		if (null != xmlwriter) {
			try {
				xmlwriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			xmlwriter = null;
		}

		if (null != out) {
			try {
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			out = null;
		}

		if (null != is) {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			is = null;
		}
	}
}

如果是放在 web 工程中,則程式碼:
String rootPath = System.getProperty("user.dir");

需要改成
HttpServletRequest req = ......

String rootPath = req.getSession().getServletContext().getRealPath("\\");

測試類(Junit 4):

MenuTreeTest.java

import org.junit.Test;

public class MenuTreeTest {

	@Test
	public void testAddNode() {

		HwMenu menu = new HwMenu();

		menu.setMenuId("8a8080fd45dea92f0145dea942bf0000");
		menu.setMenuNo("2-1");
		menu.setParentNo("2");
		menu.setMenuName("選單配置管理");
		menu.setMenuUrl("hw/menu");
		menu.setMenuLevel("2");
		// 是否子節點. 0 : false , 1 : true
		menu.setIsLeaf(1);
		// 是否展開. 0 : false , 1 : true
		menu.setExpanded(1);
		// 是否載入. 0 : false , 1 : true
		menu.setLoaded(1);

		try {
			new MenuTree().addNode(menu);

			System.out.println("新增成功");

		} catch (Exception e) {
			System.out.println("新增失敗");
			e.printStackTrace();
		}
	}

	@Test
	public void testModifyNode() {

		HwMenu menu = new HwMenu();

		menu.setMenuId("8a8080fd45d529340145d5294acf0000");
		menu.setMenuNo("1");
		menu.setParentNo("123");
		menu.setMenuName("首頁");
		menu.setMenuUrl("/home");
		menu.setMenuLevel("1");
		// 是否子節點. 0 : false , 1 : true
		menu.setIsLeaf(0);
		// 是否展開. 0 : false , 1 : true
		menu.setExpanded(1);
		// 是否載入. 0 : false , 1 : true
		menu.setLoaded(1);

		try {
			new MenuTree().modifyNode(menu);

			System.out.println("更新成功");

		} catch (Exception e) {
			System.out.println("更新失敗");
			e.printStackTrace();
		}
	}

	@Test
	public void testRemoveNode() {

		String nodeId = "8a8080fd45dea92f0145dea942bf0000";

		try {
			new MenuTree().removeNode(nodeId);

			System.out.println("刪除成功");

		} catch (Exception e) {
			System.out.println("刪除失敗");
			e.printStackTrace();
		}
	}

}