java-web 之 第二講 -- dom4j 解析 XML 文件

dom4j 之 XML 解析

1:dom4j 簡介

	   解析XML 文檔的開放源代碼XML 框架,支持 XML,XPath,XSLT, 出現前景是早期的 dom4j 分離出來後創建的,相對比 dom4j 靈活,也使用SAX 解析器來分析文檔。
dom4j API 介紹
     繼承關係圖:
1XMl 文檔的創建
DocumentHelper-- 靜態方法
public class Test3 {
/**
*dom4j 創建 XML 文件
 */
public static void main(String[] args) {
// 創建根元素節點 然後創建文檔對象
Element elRoot = DocumentHelper.createElement("student");
Document doc = DocumentHelper.createDocument(elRoot);
// 添加屬性   先添加根節點的屬性
elRoot.addAttribute("sn", "1");
//添加子元素和元素內容
Element elName = elRoot.addElement("name");
Element elAge = elRoot.addElement("age");
elName.setText("郭新傑");
elAge.setText("28");

//輸出文檔 到文件
try {
OutputFormat format = OutputFormat.createCompactFormat();
format.setEncoding("GB2312");
format.setIndent("    ");
//XMLWriter writer = new XMLWriter(new FileOutputStream("stu.xml"));輸出到文件
XMLWriter writer = new XMLWriter(format);// 規範化輸出
writer.write(doc);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}


xml 例子爲:

<?xml version="1.0" encoding="GB2312"?>
<?xml-stylesheet type="text/xsl" href="student.xsl"?>
<students>
<student sn="1">
<name>張三</name>
<age>12</age>
</student>
<student sn="2">
<name>李四</name>
<age>13</age>
</student>
<student sn="3">
<name>王五</name>
<age>14</age>
</student>
<student sn="4">
<name>趙六</name>
<age>15</age>
</student>
</students>

構建 DOM 樹 -- xml文件的 dom4j 解析

           dom4j 在 包中提供了兩個類,DOMReader :從一個現有的 W3C DOM 樹構建 dom4j 樹  
				      SAXReader : 使用 SAX 解析器,從不同的輸入源來構造 dom4j 樹
		以SAXReader 爲例來創建文檔對象
			SAXReader sax = new SAXReader();
		接上面代碼爲:
		SAXReader sax = new SAXReader();
		File file = new File("test.xml");
		try {
			Document d = sax.read(file);
			// 訪問根元素
			Element root = d.getRootElement();
			// 得到某個元素的所有子元素
			List list = root.elements();
			
			
			// 利用 XPath 表達式,需要引進 包 jaxen 的支持  
			list  = root.selectNodes("//name");  //獲取 所有 <name> 的元素
			list  = root.selectNodes("//student[@sn='1']"); //獲取 sn 的值=1的<student> 元素
			// XPath 表達式結束 --------------------------------------
			System.out.println("\n"+list.size());
			for(int m = 0;m<list.size();m++){
				Element name =(Element) list.get(m);
				System.out.println("這裏是 sn 的值 -- "+name.attributeValue("sn"));// 這裏是獲取元素的指定屬性  比如:sn
				//System.out.println("00 -- "+name.elementText("name"));// 獲取name 的值  這裏使用SAXReader 來獲取
				System.out.println("00 -- "+name.getStringValue());// 獲取name 的值 這裏使用 XPath 表達式來獲取
			}
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// -------------------------------------------------以 DOMReader 來構造對象
		DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder db = df.newDocumentBuilder();
			File f = new File("test.xml");
			org.w3c.dom.Document doc1 = db.parse(f);
			
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	好了 基礎回顧結束,下面開始講解 dom4j 的訪問者模式 和 基於事件的處理

2 : dom4j 訪問者模式

	實際應用中,我們往往需要遍歷整個XML 文檔,根據不同類型的節點進行不同的操作,這個時候可以考慮下訪問者模式(VIsitor),通常用於處理對象樹結構,樹中的每個節點對象都可以接受一個訪問者對象,
	節點對象向訪問者對象傳遞本身。訪問者對象反過來調用節點對象的操作。
	dom4j 包中 有個 Visitor 接口,針對不同類型節點,定義了多個重載的 visit()  方法  如:訪問元素方法爲 void visit(Element node)  訪問元素屬性方法爲:  void visit(Attribute node)
			我們需要實現 Visitor 接口  然後在 node 中定義了一個 accept(Visitor v)

      例子:
		public class Dom4jVisitor {


		/**
		 * dom4j 訪問者模式
		 */
		public static void main(String[] args) {
			// TODO Auto-generated method stub
			SAXReader read = new SAXReader();
			File f = new File("test.xml");
			try{
				Document doc = read.read(f);
				doc.accept(new MyVisitor());
			}catch(Exception e){
				e.printStackTrace();
			}
		}

	} 
	package com.tide.servlet;

import org.dom4j.Attribute;
import org.dom4j.Element;
import org.dom4j.ProcessingInstruction;
import org.dom4j.VisitorSupport;


public class MyVisitor extends VisitorSupport {


	/**
	 * 對於屬性節點,打印出屬性的名稱和值
	 */
	public void visit(Attribute node){
		System.out.println("attribute: "+node.getName()+" == "+node.getValue());
	}
	
	/**
	 * 對於處理指令節點,打印出處理指令目標和數據
	 */
	public void visit(ProcessingInstruction node){
		System.out.println("處理指令 :"+node.getTarget()+" -- "+node.getText());
		
	/**
	 * 對於元素節點,判斷是否只包含文本內容,如果是 打印出元素名稱和內容
	 * 如果不是,只打印元素的名稱
	 */
	public void visit(Element node){
		if(node.isTextOnly()){
			System.out.println("element: "+node.getName()+" == "+node.getText());
		}
	}
}

打印後的內容爲:
處理指令 :xml-stylesheet -- type="text/xsl" href="student.xsl"
attribute: sn == 1
element: name == 張三
element: age == 12
attribute: sn == 2
element: name == 李四
element: age == 13
attribute: sn == 3
element: name == 王五
element: age == 14
attribute: sn == 4
element: name == 趙六
element: age == 15



3:dom4j 基於對事件的處理

		dom4j 支持對文檔的基於事件的處理,尤其是對於較大的文檔,可以利用 dom4j 提供的基於事件的處理模型,在解析過程中進行處理,而不必等到整個文檔解析完畢。
	SAXReader 定義了 addHandler() 方法,用於添加一個 ElementHandler 實例
			public void addHandler(String path,ElementHandler handler)    當解析到參數 path 指定的路徑時,將調用參數 handler 指定的處理器,針對不同的節點路徑,可以添加多個ElementHandler實例。
	ElementHandler 接口的方法主要有:
		void onStart(ElementPath path) // 解析遇到元素的開始標籤時被調用
		void onEnd(ElementPath path)   // 解析遇到元素的結束標籤時被調用
	ElementPath 接口主要方法:
		void addHandler(String path,ElementHandler handler)  和 SAXReader 的 addHandler() 方法大致相同
		void removeHandler(String path)
		String getPath() //獲取當前節點路徑
		Element getCurrent() //獲取當前元素

	例子:xml 文件還是上面的xml     最大的好處是不必要便利文檔所有內容就可以對內容進行處理
		

public class Test4 {


	/**
	 * dom4j 基於事件的處理 ElementHandler
	 */
	public static void main(String[] args) {
		SAXReader read  = new SAXReader();
		File f = new File("test.xml");
		read.addHandler("/students/student", (ElementHandler) new StudentHandler());
		try{
			read.read(f);		
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}
package com.tide.servlet;


import org.dom4j.Element;
import org.dom4j.ElementHandler;
import org.dom4j.ElementPath;


/**
 * 定義 StudentHandler 處理器類, 對 <student> 元素進行處理
 * @author Administrator
 *
 */
public class StudentHandler implements ElementHandler{


	@Override
	public void onStart(ElementPath path) {
		Element ele =  path.getCurrent();
		System.out.println("Fount student : "+ele.attributeValue("sn"));
		//添加對子元素 name 的處理器
		path.addHandler("name", new Namehandler());
		System.out.println("添加對子元素 name 的處理器");
		
	}


	@Override
	public void onEnd(ElementPath path) {
		// 移除對子元素 name 的處理器
		path.removeHandler("name");
		System.out.println("移除對子元素 name 的處理器");
		
	}
	
}

package com.tide.servlet;


import org.dom4j.Element;
import org.dom4j.ElementHandler;
import org.dom4j.ElementPath;


public class Namehandler implements ElementHandler {


	@Override
	public void onEnd(ElementPath path) {
		Element ele = path.getCurrent();
		//輸出 <name> 元素的名稱和文本內容
		System.out.println("name :"+ele.getName()+" == "+ele.getText());
	}


	@Override
	public void onStart(ElementPath path) {
		System.out.println("path : "+path.getPath());
		
	}


}
最後的輸出內容爲:
Fount student : 1
添加對子元素 name 的處理器
path : /students/student/name
name :name == 張三
移除對子元素 name 的處理器
Fount student : 2
添加對子元素 name 的處理器
path : /students/student/name
name :name == 李四
移除對子元素 name 的處理器
Fount student : 3
添加對子元素 name 的處理器
path : /students/student/name
name :name == 王五
移除對子元素 name 的處理器
Fount student : 4
添加對子元素 name 的處理器
path : /students/student/name
name :name == 趙六
移除對子元素 name 的處理器

	






發佈了36 篇原創文章 · 獲贊 17 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章