JAVA學習之路(三)。。。

    這是開始學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();
     }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章