XML 作爲數據存儲一種常見的格式,凡見代碼的地方,都可以見到,所以選擇何種解析方式也是比較重要的,合適的方式不僅可以提高編譯效率,還能節約內存,防止內存溢出!
下面就綜合各種博客(主要參考博客有:https://www.cnblogs.com/longqingyang/p/5577937.html),實測四種解析方式,代碼可運行,供給大家參考
XML的解析方式分爲四種:
1、DOM解析;
2、SAX解析;
3、JDOM解析;
4、DOM4J解析。
其中前兩種屬於基礎方法,是官方提供的平臺無關的解析方式;
後兩種屬於擴展方法,它們是在基礎的方法上擴展出來的,只適用於java平臺。
針對以下XML文件,會對四種方式進行詳細描述:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="001">
<name>狂人日記</name>
<year>1918</year>
<price>14</price>
<language>China</language>
</book>
<book id="002">
<name>安徒生童話</name>
<year>2004</year>
<price>32</price>
<language>English</language>
</book>
</bookstore>
一、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文件比較大,容易影響解析性能且可能會造成內存溢出。
以下是解析代碼:
package com.study.xml;
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.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class DomParse {
public static void main(String[] args) throws SAXException {
// 創建一個DocumentBuilderFactory的對象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 創建一個DocumentBuilder的對象
try {
// 創建DocumentBuilder對象
DocumentBuilder db = dbf.newDocumentBuilder();
// 通過DocumentBuilder對象的parser方法加載books.xml文件到當前項目下
Document document = db.parse("src/books.xml");
// 獲取所有book節點的集合
NodeList bookList = document.getElementsByTagName("book");
// 遍歷每一個book節點
for (int i = 0; i < bookList.getLength(); i++) {
// 通過 item(i)方法 獲取一個book節點,nodelist的索引值從0開始
Node book = bookList.item(i);
// 獲取book節點的所有屬性集合
NamedNodeMap attrs = book.getAttributes();
// 遍歷book的屬性
for (int j = 0; j < attrs.getLength(); j++) {
// 通過item(index)方法獲取book節點的某一個屬性
Node attr = attrs.item(j);
// 獲取屬性名
System.out.print("屬性:" + attr.getNodeName());
// 獲取屬性值
System.out.println("--" + attr.getNodeValue());
}
// 解析book節點的子節點
NodeList childNodes = book.getChildNodes();
// 遍歷childNodes獲取每個節點的節點名和節點值
for (int k = 0; k < childNodes.getLength(); k++) {
// 區分出text類型的node以及element類型的node
if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) {
// 獲取了element類型節點的節點名
System.out.print(childNodes.item(k).getNodeName());
// 獲取了element類型節點的節點值
System.out.println("--" + childNodes.item(k).getFirstChild().getNodeValue());
}
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
}
二、SAX解析
SAX的全稱是Simple APIs for XML,也即XML簡單應用程序接口。與DOM不同,SAX提供的訪問模式是一種順序模式,這是一種快速讀寫XML數據的方式。當使用SAX分析器對XML文檔進行分析時,會觸發一系列事件,並激活相應的事件處理函數,應用程序通過這些事件處理函數實現對XML文檔的訪問,因而SAX接口也被稱作事件驅動接口。
優點:
1、採用事件驅動模式,對內存耗費比較小。
2、適用於只處理XML文件中的數據時。
缺點:
1、編碼比較麻煩。
2、很難同時訪問XML文件中的多處不同數據。
SAX解析可分四個步驟進行:
1、得到xml文件對應的資源,可以是xml的輸入流,文件和uri
2、得到SAX解析工廠(SAXParserFactory)
3、由解析工廠生產一個SAX解析器(SAXParser)
4、傳入輸入流和handler給解析器,調用parse()解析
以下是解析代碼:
package com.study.xml;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
public class SaxParse {
public static void main(String[] args) throws Exception {
// 創建解析工廠
SAXParserFactory factory = SAXParserFactory.newInstance();
// 得到解析器
SAXParser sp = factory.newSAXParser();
// 得到解讀器
XMLReader reader = sp.getXMLReader();
// 設置內容處理器
reader.setContentHandler(new JDomParse().new ListHandler());
// 讀取xml的文檔內容
reader.parse("src/books.xml");
}
class ListHandler implements ContentHandler {
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
// 解析到節點的開頭標籤'<..'時被調用,實際上就是節點開頭<xx>內容
System.out.print("<" + qName);
//獲取屬性
for (int i = 0; atts != null && i < atts.getLength(); i++) {
System.out.print(" " + atts.getQName(i) + "='" + atts.getValue(i) + "'");
}
System.out.print(">");
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// 解析到節點的開頭標籤'/>'時被調用,實際上就是節點結尾</xx>內容
System.out.print("</" + qName + ">");
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
//真正的節點內容,包括換行符和內容
String content = new String(ch, start, length);
System.out.print(content);
}
@Override
public void setDocumentLocator(Locator locator) {
}
@Override
public void startDocument() throws SAXException {
}
@Override
public void endDocument() throws SAXException {
}
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
}
@Override
public void endPrefixMapping(String prefix) throws SAXException {
}
@Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
}
@Override
public void processingInstruction(String target, String data) throws SAXException {
}
@Override
public void skippedEntity(String name) throws SAXException {
}
}
}
三、JDOM解析
需要導入包:
jdom.jar
xercesImpl.jar (這個包不導入的話,會報 SAX2 driver class org.apache.xerces.parsers.SAXParser not found: SAX2 driver class org.apache.xerces.parsers.SAXParser not found 這個錯誤)
特徵:
1、僅使用具體類,而不使用接口。
2、API大量使用了Collections類。
以下是解析代碼:
package com.study.xml;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
public class JDomParse {
public static void main(String[] args) throws JDOMException, IOException {
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(new File("src/books.xml"));
Element root = doc.getRootElement();
List list = root.getChildren("book");
for (int i = 0; i < list.size(); i++) {
Element element = (Element) list.get(i);
String id = element.getAttributeValue("id");
String name = element.getChildText("name");
String year = element.getChildText("year");
String price = element.getChildText("price");
String language = element.getChildText("language");
System.out.println("--" + id);
System.out.println("--" + name);
System.out.println("--" + year);
System.out.println("--" + price);
System.out.println("--" + language);
}
}
}
四、DOM4J解析
需要導入包:
dom4j-1.6.1.jar
特徵:
1、JDOM的一種智能分支,它合併了許多超出基本XML文檔表示的功能。
2、它使用接口和抽象基本類方法。
3、具有性能優異、靈活性好、功能強大和極端易用的特點。
4、是一個開放源碼的文件
以下是解析代碼:
package com.study.xml;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Dom4JParse {
public static void main(String[] args) {
// 解析books.xml文件
// 創建SAXReader的對象reader
SAXReader reader = new SAXReader();
try {
// 通過reader對象的read方法加載books.xml文件,獲取docuemnt對象。
Document document = reader.read(new File("src/books.xml"));
// 通過document對象獲取根節點bookstore
Element bookStore = document.getRootElement();
// 通過element對象的elementIterator方法獲取迭代器
Iterator it = bookStore.elementIterator();
// 遍歷迭代器,獲取根節點中的信息(書籍)
while (it.hasNext()) {
Element book = (Element) it.next();
// 獲取book的屬性名以及 屬性值
List<Attribute> bookAttrs = book.attributes();
for (Attribute attr : bookAttrs) {
System.out.println("屬性" + attr.getName() + "--" + attr.getValue());
}
Iterator itt = book.elementIterator();
while (itt.hasNext()) {
Element bookChild = (Element) itt.next();
System.out.println("節點" + bookChild.getName() + "--" + bookChild.getStringValue());
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
Final:比較總結
DOM4J性能最好,連Sun的JAXM也在用DOM4J。目前許多開源項目中大量採用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J來讀取XML配置文件。如果不考慮可移植性,那就採用DOM4J。
JDOM和DOM在性能測試時表現不佳,在測試10M文檔時內存溢出。在小文檔情況下還值得考慮使用DOM和JDOM。雖然JDOM的開發者已經說明他們期望在正式發行版前專注性能問題,但是從性能觀點來看,它確實沒有值得推薦之處。另外,DOM仍是一個非常好的選擇。DOM實現廣泛應用於多種編程語言。它還是許多其它與XML相關的標準的基礎,因爲它正式獲得W3C推薦(與基於非標準的Java模型相對),所以在某些類型的項目中可能也需要它(如在JavaScript中使用DOM)。
SAX表現較好,這要依賴於它特定的解析方式-事件驅動。一個SAX檢測即將到來的XML流,但並沒有載入到內存(當然當XML流被讀入時,會有部分文檔暫時隱藏在內存中)。