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+"]";
}
}