1. 程式人生 > >XML解析---DOM解析和SAX解析

XML解析---DOM解析和SAX解析

   XML是一種通用的資料交換格式,它的平臺無關性、語言無關性、系統無關性、給資料整合與互動帶來了極大的方便。XML在不同的語言環境中解析方式都是一樣的,只不過實現的語法不同而已。

一、DOM解析

  DOM的全稱是Document Object Model,也即文件物件模型。在應用程式中,基於DOM的XML分析器將一個XML文件轉換成一個物件模型的集合(通常稱DOM樹),應用程式正是通過對這個物件模型的操作,來實現對XML文件資料的操作。通過DOM介面,應用程式可以在任何時候訪問XML文件中的任何一部分資料,因此,這種利用DOM介面的機制也被稱作隨機訪問機制。

  DOM介面提供了一種通過分層物件模型來訪問XML文件資訊的方式,這些分層物件模型依據XML的文件結構形成了一棵節點樹。無論XML文件中所描述的是什麼型別的資訊,即便是製表資料、專案列表或一個文件,利用DOM所生成的模型都是節點樹的形式。也就是說,DOM強制使用樹模型來訪問XML文件中的資訊。由於XML本質上就是一種分層結構,所以這種描述方法是相當有效的。

  DOM樹所提供的隨機訪問方式給應用程式的開發帶來了很大的靈活性,它可以任意地控制整個XML文件中的內容。然而,由於DOM分析器把整個XML文件轉化成DOM樹放在了記憶體中,因此,當文件比較大或者結構比較複雜時,對記憶體的需求就比較高。而且,對於結構複雜的樹的遍歷也是一項耗時的操作。所以,DOM分析器對機器效能的要求比較高,實現效率不十分理想。不過,由於DOM分析器所採用的樹結構的思想與XML文件的結構相吻合,同時鑑於隨機訪問所帶來的方便,因此,DOM分析器還是有很廣泛的使用價值的。

    優點:

      1、形成了樹結構,有助於更好的理解、掌握,且程式碼容易編寫。

      2、解析過程中,樹結構儲存在記憶體中,方便修改。

    缺點:

      1、由於檔案是一次性讀取,所以對記憶體的耗費比較大。

      2、如果XML檔案比較大,容易影響解析效能且可能會造成記憶體溢位。

  DOM解析示例:

專案目錄結構

  1.DOM解析

  TestXML.java檔案

import java.io.FileReader;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

//採用DOM進行解析
//DOM的讀取時是將XML整個檔案裝載成DOM樹,即使文件中有不需要的資訊時也會被裝載進來,在大多數的時候DOM是非常方便好用的。
public class TestXMl {
	public static void main(String[] args) {
		// 文件構建器的工廠
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		// 得到XML文件構建器
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			// 1.得到XML文件物件
			// 當test.xml放在本專案的根目錄時(和src bin同一目錄下時)
			// db.parse("test.xml");
			// 當test.xml放在bin目錄下時
			String path = FileReader.class.getResource("/").getFile();
			/// System.out.println(path);
			// 匯入的是org.w3c.dom.Document;
			Document doc = db.parse(path + "test.xml");
			// 得到文件根節點
			Element root = doc.getDocumentElement();
			String rootName = root.getNodeName();
			System.out.println(rootName);
			NodeList list = doc.getElementsByTagName("People");
			// 2.獲取XML中的節點
			System.out.println("當前有幾個People:" + list.getLength());

			// 3.得到節點裡面的有用資訊
			for (int i = 0; i < list.getLength(); i++) {
				Element peopleElement = (Element) list.item(i);
				String id = peopleElement.getAttribute("id"); // 獲取id的屬性值
				System.out.println("id:" + id);
				// 遍歷當前元素的子節點
				NodeList childNodeList = peopleElement.getChildNodes();
				// test.xml中一個People元素下有Name和Age兩個標籤,但是它把回車也算作一個節點,所以打印出來是五個
				// 第一個是沒有回車的,第二個有
				System.out.println("子節點個數:" + childNodeList.getLength());

				// 判斷這些子節點中的元素是不是有效的元素,即不為回車
				for (int j = 0; j < childNodeList.getLength(); j++) {
					// 判斷是不是元素,有標籤的,若是元素才把它轉換為元素
					if (childNodeList.item(j) instanceof Element) {
						Element cElement = (Element) childNodeList.item(j);
						String tagName = cElement.getTagName();
						String content = cElement.getTextContent();
						System.out.println(tagName + ":" + content);
					}
				}
			}

		} 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();
		}

	}
}

2.往XML檔案中寫入的是Document物件

  Write.java檔案


import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

//由物件到檔案,把document物件儲存到檔案中
//XML是磁碟檔案,DOM是記憶體物件。
//往XML檔案中寫入的是Document物件,所以要編輯XML檔案,實際上編輯的是Document文件物件。
public class WriteXML {
    public static void main(String[] args) {
    	//建立一個document,通過builder建立
    	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    	try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.newDocument();
			
			//通過document建立節點Element
			Element stuEle = doc.createElement("Student");
			stuEle.setAttribute("stuNo","S1001");
			//給stuEle新增子節點
			Element nameEle = doc.createElement("Name");
			//方式一:建立一個文字節點
			/*Text txtName = doc.createTextNode("zhangsan");
			nameEle.appendChild(txtName);*/
			//方式二:直接新增文字
			nameEle.setTextContent("zhangsan");
			Element ageEle = doc.createElement("Age");
			ageEle.setTextContent("20");
			stuEle.appendChild(nameEle);
			stuEle.appendChild(ageEle);
			
	    	//將Element物件新增到document中
			doc.appendChild(stuEle);
			
	    	//將document物件儲存到硬碟檔案xml中
	    	//通過transformer進行儲存
			TransformerFactory tf = TransformerFactory.newInstance();
			Transformer former = tf.newTransformer();
			former.transform(new DOMSource(doc), new StreamResult("stu.xml"));
			System.out.println("生成xml成功...");
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
    	
    }
}

  test.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<PeopleList>
   <People id="1">
      <Name en="zhangsan">張三</Name>
      <Age>20</Age>
	  <Address>蘇州</Address>
   </People>
   <People id="2">
      <Name en="lisi">李四</Name>
      <Age>39</Age>
	  <Address>常州</Address>
    </People>
	 <People id="3">
      <Name en="wangwu">王五</Name>
      <Age>14</Age>
	  <Address>楊州</Address>
    </People>
	 <People id="4">
      <Name en="zhaowu">趙武</Name>
      <Age>31</Age>
	  <Address>貴州</Address>
    </People>
	 <People id="5">
      <Name en="sunliu">孫劉</Name>
      <Age>26</Age>
	  <Address>廣州</Address>
    </People>
</PeopleList>

二、SAX解析

  SAX的全稱是Simple APIs for XML,也即XML簡單應用程式介面。與DOM不同,SAX提供的訪問模式是一種順序模式,這是一種快速讀寫XML資料的方式。當使用SAX分析器對XML文件進行分析時,會觸發一系列事件,並激活相應的事件處理函式,應用程式通過這些事件處理函式實現對XML文件的訪問,因而SAX介面也被稱作事件驅動介面。

    優點:

      1、採用事件驅動模式,對記憶體耗費比較小。

      2、適用於只處理XML檔案中的資料時。

    缺點:

      1、編碼比較麻煩。

      2、很難同時訪問XML檔案中的多處不同資料。

SAX解析示例

      XMLHandler.java

     


import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class XMLHandler extends DefaultHandler {
	
	private String value; //讀取到的文字
	private People people; //臨時存放的一個人
	private List<People> peopleList;

	
	public List<People> getPeopleList() {
		return peopleList;
	}

	

	//當讀到文件開始處觸發事件,該方法只執行一次
	@Override
	public void startDocument() throws SAXException {
		// TODO Auto-generated method stub
		super.startDocument();
		System.out.println("開始執行startDocument,開始讀取xml文件");
		peopleList = new ArrayList<People>();
	}
    
	//當讀到文件結束處觸發事件,該方法只執行一次
	@Override
	public void endDocument() throws SAXException {
		// TODO Auto-generated method stub
		super.endDocument();
		System.out.println("開始執行endDocument,結束讀取xml文件");
	}
    
    //當讀到元素開始處觸發事件
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		// TODO Auto-generated method stub
		super.startElement(uri, localName, qName, attributes);
		System.out.println("開始執行startElement,開始讀取xml文件的標籤,該標籤為:"+qName);
		if("People".equals(qName)) {
			people = new People();
			System.out.println("當前people有屬性"+attributes.getLength());
			for(int i = 0;i<attributes.getLength();i++) {
				//獲取當前屬性名
				if("id".equals(attributes.getQName(i))) {
					people.setId(attributes.getValue(i));
				}
			}
		}
	}
    
	//當讀到元素結束處觸發事件
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		// TODO Auto-generated method stub
		super.endElement(uri, localName, qName);
		System.out.println("開始執行endElement,結束讀取xml文件的標籤,該標籤為:"+qName);
		if("People".equals(qName)) {
			peopleList.add(people);
			people = null;
		}else if("Name".equals(qName)) {  //讀到Name的結束標籤
			people.setName(value);
		}else if("Age".equals(qName)) {
			people.setAge(value);
		}
	}
    
	//讀到內容時觸發事件
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		// TODO Auto-generated method stub
		super.characters(ch, start, length);
		value = new String(ch,start,length);
		System.out.println("當前讀到的文字是:"+value);
	}
  
}

   ReadXMLBySAX.java

import java.io.IOException;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

//SAX解析
//流讀取的機制(SAX),Document的讀取在內部也是使用流的機制去讀的。
//流讀取的機制是隻負責讀取,不進行儲存,但是會給出一定的關鍵的事件,提示你進行相應的儲存操作。
public class ReadXMLBySAX {
    public static void main(String[] args) {
    	//得到saxParser
    	SAXParserFactory  factory = SAXParserFactory.newInstance();
    	try {
			SAXParser parser = factory.newSAXParser();
			XMLHandler handler = new XMLHandler();
			//通過saxParse接卸器的parse方法,解析xml,parse需要一個處理器,handler
			parser.parse("test.xml", handler);
			List<People> list = handler.getPeopleList();
			System.out.println("一共讀取倒了"+list.size()+"個人");
			for(People people : list) {
				System.out.println(people);
			}
		} 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();
		}
    	
    }
}

   People.java

   


public class People {
	private String id;
	private String name;
	private String age;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	public People(String id, String name, String age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}

	public People() {
		super();
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "Student[id="+id+",name="+name+",age="+age+"]";
	}
	
	

}