這是開始學Java的第三天,今天看了Java的關於XML的解析,總共看了有三種,一是DOM,二是SAX,還有三是STAX,對XML的解析有了更進一步的瞭解。在DOM中,是將整個XML文檔加載到內存中,形成一個文檔對象,所有的對XML操作都是對內存中文檔對象進行,如果過大的XML文檔用DOM的話,會讓內存空間變小,但是隻是一般的小項目,XML文檔不算大的話,用DOM解析會好一點。其次是SAX解析,這是一種一邊解析,一邊處理,一邊釋放內存資源,不會再內存中保留大規模內存數據,這是一種推(push)模式:有服務器爲主導,向客戶端主動發送數據。最後一個是STAX,這個實際上和SAX差不多,只是具體的實現的方式有所不同,STAX是一種拉(pull)模式:由客戶端爲主導,主動向服務器申請數據。感覺今天收穫挺多,一下是今天整個總結的內容:
使用XML 存儲和傳輸數據
1.通過程序生成xml
2.讀取xml中數據 --- xml解析
XML解析方式分爲兩種:dom和sax
dom:(Document Object Model,即文檔對象模型)是W3C組織推薦的解析XML的一種方式。
DOM思想:將整個xml文檔加載到內存中,形成文檔對象,所有對xml操作都對內存中文檔對象進行。
DOM是官方xml解析程序
*所有語言都支持
sax:(Simple API for XML)不是官方推薦,它產生自XML社區,幾乎所有的XML解析器都支持它。
發明sax的原因:當xml文檔非常大,不可能將xml所有數據加載到內存
sax思想:一邊解析,一邊處理,一邊釋放內存資源 ---- 不允許在內存中保留大規模xml數據
JDK6的新特性StAX是JDK6.0中除了DOM和SAX之外的又一種拉模式處理XML文檔的API
XML解析開發包
Jaxp(sun)、xml pull、dom4j
stAX The Stream API for XML ------ XML流API
stAX 是一種拉模式 xml解析模式,sax是推模式xml解析方式
推push模式:由服務器爲主導,向客戶端主動發送數據
拉pull模式:由客戶端爲主導,主動向服務器申請數據
程序員在實際開發中,使用已經開發好的工具包-----JAXP、DOM4j、XML PULL
解析方式使解析xml思想,沒有具體代碼,解析開發包是解析xml思想具體代碼實現
JAXP是sun官方推出的實現技術 同時支持DOM SAX STAX
DOM4j 是開源社區開源框架 支持DOM解析方式
XML PULL Android移動設備內置xml
DOM和SAX/STAX區別
DOM支持回寫
會將整個XML載入內存,以樹形結構方式存儲
XML比較複雜的時候,或者當你需要隨機處理文檔中數據的時候不建議使用
SAX/STAX
相比DOM是一種更爲輕量級的方案
採用串行方法讀取---文件輸入流(字節、字符)讀取
編程較爲複雜
無法再讀取過程中修改XML數據 解析技術 STAX解析方式
當SAX和STAX讀取xml數據時,如果讀取到內存數據不釋放 ----- 內存中將存在整個xml文檔數據(類似DOM支持修改和回寫)
選擇DOM還是SAX/STAX,這取決於幾個因素
應用程序的目的:如果必須對數據進行更改,並且作爲XML將他輸出,則在多數情況下,使用DOM
數據的數量:對於大文件,SAX/STAX是更好的選擇
將如何使用數據:如果實際上只使用一小部分數據,則使用SAX/STAX將數據抽取到應用程序中,這種方法更好
需要速度:通常,SAX/STAX實現比DOM更快
在JAVAee日常開發中----優先使用DOM(變成簡單)
在XML文檔數據非常多,不可能使用DOM --- 造成內存溢出 ---- 優先使用STAX
移動開發 使用STAX ---- Android XML PULL
JAXP開發 進行xml解析:
javax.xml.parsers 存放DOM和SAX解析器
javax.xml.stream 存放STAX解析相關類
orgw3c.dom 存放DOM解析時 數據結點類
org.xml.sax 存放SAX解析相關工具類
DOM是以層次結構組織的結點或信息片段的集合,是XML數據的一種樹形表示
文檔中所有的元素、樹形、文本都會被解析成node結點
結點之間關係----parent、children、sibling
使用DOM方式解析XML
解析器工廠類DocumentBuilderFactory
DocumentBuilderFactory dbf= DocumentBuilderFactory.newInstance();
解析器類DocumentBuilder
DocumentBuilder db = dbf.newDocumentBuilder();
解析生成Document對象
Document doc = db.parse("message.xml");
通過Document對象查詢結點
document.getElementsByTagName返回NodeList對象
節點列表內NodeList就是代表了一個包含一個或多個Node的列表
可以簡單的把他看成一個Node數組
常用方法
getLength():返回列表長度
類似ArrayList size()
item(index):返回指定位置的Node對象
類似ArrayList get(index)
節點對象Node
Node對象提供了一系列常量來代表節點的類型
當開發人員獲得某個Node類型後,就可以把Node節點轉換成相應的結點對象
Element、Attr、Text
節點的操作:三個node的通用API
getNodeName():返回節點的名稱
getNodeType():返回節點的類型
getNodeValue():返回節點的值----所有元素節點的value都是null
節點對象 Element Attr Text
元素節點:
獲得元素節點中的屬性值
element.getAttribute(屬性名稱);
獲得元素節點內部文本內容
element.getTextContent();
element.getFirstChild().getNodeValue();
更新javax.xml.transform包中的Transformer類用於把代表XML文件的Document對象轉換成XML格式進行輸出
Transformer對象通過TransformerFactory獲得
Transformer類通過transfoem方法完成轉換操作,該方法接收一個源和一個目的地。
我們可以通過:
javax.xml.transform.dom.DOMSource類來關聯要轉換的document對象
用javax.xml.transform.stream.StreamResult對象來表示數據的目的地
節點對象的增加、修改、刪除總結
*節點對象的增加
document.createXXX()創建節點
element.appendChild(org.w3c.dom.Node)添加節點
*節點對象的修改
修改元素的屬性值element.setAttribute(name,value);
修改元素的文本內容element.setTextContent(value);
節點對象的刪除
刪除節點.getParentNode().removeChild()刪除節點
DOM解析快速入門
1.創建XML文檔 books.xml
在企業實際開發中,爲了簡化xml生成和解析 ---- xml數據文件通常不使用約束
2.使用DOM解析xml
將整個xml文檔加載到內存中
工廠----解析器----解析加載
3.Document通過getElementsByName 獲得節點集合 NodeList
通過NodeList提供getLength和item遍歷節點集合
節點對象的查詢總結
全局查找元素節點
document.getElementsByTagName
document.getElementById
相對節點位置查找節點
getChildNodes():返回這個節點的所有子節點列表
getFirstChild():返回這個節點的第一個子節點
getParentNode():返回這個節點的父節點對象
getNextSibling():返回該節點下一個兄弟節點
getPreviousSibling():返回其前一個兄弟節點
遍歷ArrayList
for(int i=0;i<arrayList.size();i++){
arrayList.get(i);
}
遍歷NodeList
for(int i=0;i<nodeList.getLength();i++){
nodeList.item(i);//----------將遍歷每個結點轉換成子接口類型
}
什麼是Node?---對於xml來說,xml所有數據都是node節點(元素節點、屬性節點、文本節點、註釋節點、CDATA節點、文檔節點)
Element(元素)、Attr(屬性)、Text(文本)、Comment(註釋)、CDATASection、Document(文檔)----都是Node的子接口
DOM編程思路小結
1.裝載XML文檔--------Document
2.Document獲得置頂元素 ---------getElementsByName(返回NodeList)
3.遍歷NodeList獲得每個Node
4.將每個Node強制轉換成Element
5.通過元素節點API操作屬性和文本內容
getAttrbute 獲得屬性值
getTextCotent 獲得元素內部文本內容
強化查詢
1.獲得Document文檔樹對象
2.全局查找
document.getElementsByTagName----根據元素名稱進行全局查找 NodeList
document.getElementById----默認情況下該方法不能直接用,必須要有約束,才能使用該方法
3.相對位置查找
*在企業使用XML作爲配置文件時,一般xml都有約束,但是使用XML存儲和傳輸文件時,需要用程序生成XML,大多數情況不使用約束
*XML的DTD約束默認支持的,如果使用的是Schema約束,單獨編程導入約束文件schema
XML DOM增加 修改和刪除操作------操作內存中文檔對象
XML的回寫
XML元素添加:1.創建節點元素 2.將節點元素加入指定位置
XML元素修改:查詢指定元素 1.修改屬性setAttribute 2.修改元素的文本內容 setTextContent
SAX解析原理
SAX是事件驅動的XML處理方法
它是基於事件驅動的
startElement()回調在每次SAX解析器遇到元素的起始標記時被調用
characters()回調爲字符數據所調用
endElement()爲元素的結束標記所調用
DefaultHandler(在org.xml.sax.helpers軟件包中)來實現所有這些回調,並提供所有回調方法默認的空實現
SAX解析原理
SAX是事件驅動的XML處理方法
它是基於事件驅動的
startElement()回調在每次SAX解析器遇到元素的起始標記時被調用
characters()回調爲字符數據所調用
endElement()爲元素的結束標記所調用
DefaultHandler(在org.xml.sax.helpers軟件包中)來實現所有這些回調,並提供所有回調方法默認的空實現
SAX和STAX都是基於事件驅動----SAX推模式 STAX拉模式
SAX常用事件
startDocument() ---- 文檔開始事件
startElement() ---- 元素開始事件
characters() ---- 文本元素事件
endElement() ---- 元素結束事件
endDocument() ---- 文檔結束事件
使用SAX方式解析XML
使用SAXParserFactory創建SAX解析工廠
SAXParserFactory spf = SAXParserFactory.newInstance();
通過SAX解析工廠得到解析器對象
SAXParser sp = spf.newSAXParser();
通過解析器對象解析xml文件
xmlReader.parse("book.xml",new XMLConteneHandler());
這裏的XMLContentHandler繼承DefaultHandler
爲什麼叫推模式-----由解析內部主導 事件方法調用
在startElement() endElement()獲得開始和結束元素名稱
在characters()獲得讀取到文本內容
在startElement()讀取屬性值
使用XML PULL解析XML
PULL是STAX的一個實現技術
STAX是The Streaming API for XML的縮寫,一種利用拉模式解析(pull-parsing)XML文檔的API。
STAX通過提供一種基於事件迭代器(Iterator)的API讓程序員取控制xml文檔解析過程
Android系統內置的Pull解析器也可以進行XML文件的解析
Pull解析器是一個開源的Java項目,既可以用於Android,也可以用於JavaEE
官方站點:http://www.xmlpull.org/
下載實現xpp3
Pull解析器運行方式與SAX解析器類似
基於事件驅動
關鍵代碼
創建解析器工廠
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();//根據工廠創建解析器
xpp.setInput(inStream,"UTF-8");//讀取xml文件
int eventType = xpp.getEventType(); ---- 當前節點事件類型
eventType = xpp.next(); ---- 下一個節點事件
xpp.getAttributeValue ---- 獲得標籤屬性值
xpp.nextText ---- 獲得標籤屬性值
STAX拉模式xml解析方式 ---- 客戶端程序,自己控制xml事件,主動調用相應事件方法
當使用XML PULL如果使用Android系統,系統內置無需下載任何開發包,如果想JavaSE JavaEE 使用pull解析技術 下載單獨pull開發工具包
xpp3-----XML Pull Parser 3 是pull API代碼實現
使用pull解析器
1.網上下載pull解析器實現xpp3(Android內置)
2.將xpp3-1.1.3.4.C.jar導入java工程
導入jar包 位於當前工程內部,在工程內新建lib,將jar賦值過來,將pull解析器jar添加build path
jar包就是.class文件集合壓縮包(採用zip格式壓縮)
Pull解析器使用stax解析方式----拉模式解析
Pull採用將xml文檔傳遞給解析器,手動通過next觸發文檔解析時間,在客戶端代碼中獲取當前事件,從而調用相應事件處理方法
3.創建pull解析器
4.將xml文檔內容傳遞pull
爲什麼STAX解析方式效率好於SAX?
1.SAX無選擇性的,所有時間都會處理 解析方式,STAX由用戶控制需要處理時間類型
2.在使用STAX進行數據解析的時候,可以隨時終止解析
Pull解析器 生成xml文檔 ---- 通過 XmlSerializer 生成xml文檔
解析xml:文檔開始、元素開始、文本元素、元素結束、文檔結束
生成xml:生成文檔聲明(文檔開始)、元素開始、文本內容、元素結束、文檔結束
一下代碼實例:
將XML文檔存入List集合示例:
package cn.huangnan.stax.jaxp;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
public class PullCURD {
@Test
public void demo1() throws Exception {
List<Company> companies=new ArrayList<Company>();
Company company=null;
//創建pull解析器
XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
XmlPullParser parser=factory.newPullParser();
parser.setInput(new FileInputStream("company.xml"),"utf-8");//對XML文檔進行解析,解析爲parser
int event;//設置 pull的事件
while((event=parser.getEventType())!=XmlPullParser.END_DOCUMENT) {
if(event==XmlPullParser.START_TAG && parser.getName().equals("company")) {
company=new Company();
}
if(event==XmlPullParser.END_TAG && parser.getName().equals("company")) {
companies.add(company);
}
if(event==XmlPullParser.START_TAG && parser.getName().equals("name")) {
company.setName(parser.nextText());
}
if(event==XmlPullParser.START_TAG && parser.getName().equals("pnum")) {
company.setPnum(Integer.parseInt(parser.nextText()));
}
if(event==XmlPullParser.START_TAG && parser.getName().equals("address")) {
company.setAddress(parser.nextText());
}
parser.next();
}
for(Company com:companies) {
System.out.println(com.getName());
System.out.println(com.getPnum());
System.out.println(com.getAddress());
System.out.println("------------------");
}
}
}
class Company {
private String name;
private int pnum;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPnum() {
return pnum;
}
public void setPnum(int pnum) {
this.pnum = pnum;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
/*public Company(String name, int pnum, String address) {
this.name = name;
this.pnum = pnum;
this.address = address;
}*/
}
在程序中抽取出兩個方法:1.XML轉化成List對象 2.List對象生成XML
最後對內存中的List對象進行CURD操作
以下爲示例:
package cn.huangnan.stax.pull;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
/**
* 抽取兩個方法 從List到XML 和 從XML到List
* @author Administrator
*
*/
public class PullUtils {
/**
* 接收xml文件返回List集合
* @return
* @throws Exception
*/
public static List<Company> ParseXml2List(String filename) throws Exception{
List<Company> companies=new ArrayList<Company>();
Company company=null;
//獲得解析器
XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
XmlPullParser parser =factory.newPullParser();
//設置xml輸入文件
parser.setInput(new FileInputStream(filename),"utf-8");
//解析遍歷
int event;
while((event=parser.getEventType())!=XmlPullParser.END_DOCUMENT) {
//將每個<company>元素 封裝成Company對象
//1.在company開始的時候創建一個對象
if(event==XmlPullParser.START_TAG&&parser.getName().equals("company")) {
company=new Company();
}
if(event==XmlPullParser.START_TAG&&parser.getName().equals("name")) {
company.setName(parser.nextText());
}
if(event==XmlPullParser.START_TAG&&parser.getName().equals("pnum")) {
company.setPnum(Integer.parseInt(parser.nextText()));
}
if(event==XmlPullParser.START_TAG&&parser.getName().equals("adderss")) {
company.setAddress(parser.nextText());
}
if(event==XmlPullParser.END_TAG&&parser.getName().equals("company")) {
companies.add(company);
}
parser.next();
}
return companies;
}
/*
* 同時接收List集合和xml文件 將集合中數據寫入xml中
*/
public static void Serializer2Xml(List<Company> companies,String fileName) throws Exception {
//獲得序列化對象
XmlPullParserFactory factory=XmlPullParserFactory.newInstance();
XmlSerializer serializer=factory.newSerializer();
//寫文件之前,指定輸出文件
serializer.setOutput(new FileOutputStream(fileName),"utf-8");
//文檔開始
serializer.startDocument("utf-8", true);
//根元素開始 companies
serializer.startTag(null,"companies");
//遍歷集合List 每個List中Company對象生成一個片段
for(Company c:companies) {
//company開始
serializer.startTag(null, "company");
//name開始
serializer.startTag(null, "name");
//輸入name文本
serializer.text(c.getName());
//name結束
serializer.endTag(null, "name");
serializer.startTag(null, "pnum");
serializer.text(String.valueOf(c.getPnum()));
serializer.endTag(null, "pnum");
serializer.startTag(null, "address");
serializer.text(c.getAddress());
serializer.endTag(null, "address");
//company結束
serializer.endTag(null, "company");
}
//文檔結束
serializer.endTag(null, "companies");
serializer.endDocument();
}
}