1. 程式人生 > >使用XWAF框架(5)——XML解析器:CXDP

使用XWAF框架(5)——XML解析器:CXDP

       XWAF推出了自己的組合式XML文件解析器,英文名叫:“CXDP“Combined XML Document Parser”的縮寫。核心程式碼屬XWAF原創,註釋、日誌和幫助文件採用全中文描述,特別適合於中文背景的初級程式設計師學習和使用。

       CXDP解析器融合了DOM解析DSE解析兩種XML解析技術

       DOM解析就是基於文件物件樹的解析技術,編碼簡單,功能強大,且能對

XML原文進行“增、刪、改、查”操作,是行業內最早推出的XML解析方案,應用廣泛,但是對使用者計算機的效能和記憶體要求較高,解析速度稍慢。

       DSEDocument Scanning Events)解析是基於文件掃描事件機制的解析方案。就是以XML原文的節點和元素為最小解析單元,“一邊掃描文件內容,一邊丟擲解析資料”。每次丟擲解析資料,就引發一次事件,解析器就會執行與此事件關聯的方法。程式設計師可以在該事件方法中編寫捕獲資料的程式碼,為自己所用。DSE解析技術的最大特點,就是“邊掃描、邊解析、邊丟擲”,解析器不儲存解析的歷史資料,交與開發者自己去處理。因此,該方案對計算機的硬體配置和記憶體要求不高,且解析速度快,特別適合於解析

XML大資料文件。與行業內的SAX解析思想一致。

  為了簡化程式設計,CXDP解析器提供了一個名叫XmlManager的管理器類。該類包含建立、解析和儲存XML文件的靜態方法。方法要求使用者指定XML檔案的路徑或者符合XML語法規範的字串。如果希望解析器採用DSE解析模式,則需要使用者額外提供一個實現了XmlUserParser<T> 泛型抽象類的例項引數。該例項包括捕獲解析資料的各種事件方法,以及返回解析資料的物件型別。若採用DOM解析模式,則不需要此引數。也就是說,開發者呼叫XmlManager管理器的解析方法時,管理器會自動選擇DOM模式或DSE模式來完成解析工作。唯一的差別是提供的引數是否包含

XmlUserParser<T>例項。這就簡化了應用程式的編碼。

       XWAF框架包含CXDP解析器的所有類。如果不想使用XWAF框架,也可以下載或使用獨立的壓縮檔案“com.xwaf.cxdp.jar”來獲取CXDP解析器。

5.1  基於DOMXML解析

    DOM解析XML文件的基本步驟,分為以下四步

1)載入XML文件,獲取XmlDocument物件。參考程式碼如下:

String  fileName = "D:\\myXmlFile.xml";

XmlDocument  xd = XmlManager.loadXmlFile(fileName);

2)提取根元素節點物件(XmlElement。參考程式碼如下:

XmlElement  xeRoot = xd.getDocumentElement();

3)遍歷根元素的子節點或後代節點,提取想要的資料。

  參考程式碼如下:

XmlNodeList xbl = xeRoot.getChildNodes();

for(INode n : xbl.getNodeList()){

if("userName".equals(n.getNodeName())){

......   // 根據使用者的XML結構提取資料!

}

}

4銷燬XmlDocument物件,釋放寶貴的記憶體資源

  也就是呼叫文件物件的方法:xd.destroy();

  說明:最核心的解析程式碼,必須由知道被解析XML文字的結構和各個節點含義的應用程式設計人員根據元素節點的名稱,屬性節點的設定,以及文字節點與元素節點的父子關係,分別提取相應的屬性值,或是文字子節點的內容,來完成XML資料的解析和邏輯組裝。使用者也可以使用獲得的XML資料建立自己的實體物件,然後在應用程式中引用或共享。

  程式設計師可以根據需求,找到特定的元素節點,並將建立的新元素或文字節點新增到所找到節點的子節點集合中;或者將找到的節點修改或刪除後,重新儲存到檔案,從而實現對原XML檔案的增、刪、改、查操作。

       CXDP解析器實現了DOM3範的絕大多數介面、類和方法,常用的介面、類和方法如下:

INode介面:是DOM的頂級介面。在DOM物件樹中,所有的XML資料項都被看做是節點(Node),包括屬性和文字。所以,INode也是最重要的介面,它定義了XML操作的絕大多數方法,如:

getNodeName()方法:獲取節點的限定名(包含名稱空間字首)。

getLocalName()方法:獲取當前節點的本地名稱。

getPrefix()方法:獲取節點所屬名稱空間的字首。

getNextSibling()方法:獲取下一個兄弟節點。

getPreviousSibling()方法:獲取上一個兄弟節點。

getParentNode()方法:獲取當前節點的父節點。

getFirstChild()方法:獲取第一個子節點。

getLastChild()方法:獲取最後一個子節點。

getChildNodes()方法:獲取當前節點的全部子節點集合。

getNodeType()方法:獲取當前節點的型別常量。

getNodeValue()方法:獲取節點值。

getTextContent()方法:返回節點及其子孫節點的文字內容。如果文字子孫節點中包含實體引用,將被替換為實體值。

appendChild(INode)方法:將指定的新節點新增到當前節點的子節點集合中;

insertAfter(INode newChild, INode refChild)方法:在指定的子節點之後插入一個新節點。

insertBefore(INode newChild, INode refChild)方法:在指定的子節點前插入一個新節點。

removeChild(INode)方法:移除指定的子節點。

replaceChild(INode newChild, INode oldChild)方法:將當前節點中指定的子節點替換成指定的新節點。

cloneNode(boolean deep):克隆(複製)當前節點物件的副本。

       INode介面還是文件介面(IDocument)和元素介面(IElement)的父介面。

 

XmlNode類:DOM的頂級類,它實現了INode介面的全部方法。是文件類(XmlDocument)和元素類(XmlElement)的父類。

XmlDocumentXML文件節點類,是XmlNode的子類,繼承了XmlNode的全部protected屬性和方法。另外增加了如下方法:

adoptNode(INode srcNode) :從另一個文件向本文件過繼一個節點,並返回過繼後的節點。

createElement(String qualifiedName):建立指定限定名(可以包含字首、冒號和本地名)的元素節點。

createTextNode(String data) :建立帶有指定字串資料的文字節點。

load(String xmlFileName) :將指定的檔名載入到當前文件物件。該方法有四個過載,最重要的過載方法是load(String xmlFileName, XmlUserParser<?> xup, boolean createDOM)方法。該過載方法除了要求指定檔名以外,還要求提供一個實現了泛型抽象類(XmlUserParser<?>)的例項,以及是否建立DOM物件樹的引數。如果泛型抽象類引數為null,則第三個引數會自動為true,即自動建立DOM物件樹。

 loadXML(String srcXml, String baseURI) :從指定的XML文件片段構建文件物件。第一個引數為文件片段,第二個引數是基礎DOM資源識別符號(可以為null)。

 saveFile(String xmlFileName, boolean formatXml) :以指定的檔名和格式處理模式將XML文件內容儲存到磁碟。第二個引數表示是否對文件內容進行縮排格式化。

 toXmlString(boolean formatXml) :將當前XML文件物件的節點樹,根據引數formatXml的值輸出為緊湊格式或排版格式的字串。如果引數formatXmltrue,將對XML內容以元素為單元進行換行和縮排等排版處理。

 

XmlElementXML元素節點類,是XmlNode的子類,繼承了XmlNode的全部protected屬性和方法。另外增加了如下方法:

 createAttribute(String name, String val) :建立帶有指定名稱和值的屬性節點,並返回建立的 XmlAttribute物件。

 getAttribute(String name):獲取指定名稱的屬性值。

 getAttributeNode(String name)方法:獲取指定名稱的屬性節點物件(XmlAttribute)。

 getAttributes():獲取元素的屬性集合。

 getElementById(String eId):從文件中查詢並返回ID型別的屬性值匹配引數值(eId)的第一個元素節點。

 getElementsByTagName(String tagName):獲取與指定元素標籤名稱相匹配的元素節點及其子元素節點的列表。

 getTagName():獲取當前元素節點的標籤名。

 removeAttribute(String name):刪除指定名稱的屬性節點。

 setAttribute(String name, String value):新增或修改當前元素中,屬性名稱為 name 的屬性值。說明:如不存在同名屬性,就新增一個新屬性。

 hasAttribute(String name):判斷是否存在與指定名稱相匹配的屬性節點。

5.2  基於DSEXML解析

  採用了XML文件掃描事件機制,要求程式設計師提供實現了XmlUserParser<T>泛型抽象類的例項引數。XmlUserParser<T> 是一個泛型抽象類,它定義瞭解析器掃描XML文件的過程中,與掃描事件對應的抽象方法。包括:

1start_Element():該方法在解析遇到一個元素開始節點執行,包括5引數,分別是:父元素的限定名稱、元素的本地名稱、名稱空間的字首、名稱空間識別符號、包含的屬性集合。

2end_Element()該方法在解析遇到一個元素的結束節點執行,包括2引數,分別是:元素的本地名稱、名稱空間的字首。

3Text_Parsed()該方法在解析解析完一個文字節點後被執行,包括2引數,分別是:父元素的限定名稱、文字內容。

4EntityReference_Parsed()該方法在解析器解析到一個實體引用節點時執行,包括3引數,分別是:父元素的限定名稱、引用實體名、引用實體值(字串)。

5Comment_Parsed()該方法在解析器解析到一個註釋節點時執行,包括2引數,分別是:父元素的限定名稱、註釋內容。

6ProcessingInstruction_Parsed()該方法在解析器解析到一個XML處理指令節點時執行,包括2引數,分別是:目標處理器名稱、處理指令的內容。

7getParsedData():該方法返回使用者解析得到的資料物件,其真實型別是程式設計師事先指定的泛型類。

  程式設計師可以在自己的實現子類中,選擇與要解析的XML檔案內容相關的方法並編碼實現它,其它的抽象方法可以採用無程式碼實現!

  注意:編寫解析程式碼時要使用方法中的引數來獲取解析器傳遞出來的資料,並根據XML資料的結構來還原資料邏輯。

  方法getParsedData()”是為方便使用者提取解析資料而設計的,程式設計師應該設計合適的類來儲存解析得到的資料,並作為該泛型類的型別引數,也是本方法的返回型別,在實現程式碼中返回該型別的物件。

  基於DSE的解析特點就是:一邊讀取XML文件,一邊解析XML資料結構,一邊丟擲各種掃描事件,並通過響應事件的方法引數輸出XML資料。所以有人將這種方式稱為基於掃描事件的XML解析。該模式的解析步驟分為兩步:

1建立繼承XmlUserParser<T>的子類,並實現其中的抽象方法;

2呼叫XmlManager的靜態方法parseXml()parseXmlFile(),並將文件內容或檔名,以及XmlUserParser<T>子類物件傳遞給靜態方法

5.3  XmlManager管理類

  該類提供了操作XML文件最基本的靜態方法,目的是簡化應用程式的編碼。

1)loadXml(String, String)方法:載入引數1指定的XML文字,使用並遵循DOM規範,返回一個XmlDocument物件;

2)loadXmlFile(String)方法:載入指定的XML檔案,使用和遵循DOM規範,並返回一個XmlDocument文件物件;

3)parseXml(String,XmlUserParser<?>,String)方法快速解析引數1指定的XML文字,但不實現DOM介面,也不返回XmlDocument物件,而是在解析過程中,通過各種解析事件以引數將XML節點和屬性資料傳遞給實現了xmlUserParser<T>的子類例項,該子類在方法中處理解析得到的XML資料。

4)parseXmlFile(String,XmlUserParser<?>)方法parseXml()類似,但它快速解析一個XML檔案

5)createXmlDocument()方法建立一個新的XML文件並儲存到檔案

6)saveXmlToFile(String xmlFileName, String xmlContent)方法儲存XML文字到指定的檔案。

說明parseXml()parseXmlFile()方法不建立節點樹,但要求提供一個實現了XmlUserParser<T>抽象的子類例項。使用者在該例項類中要編碼實現全部的抽象方法(響應各種解析事件),正是在重寫這些抽象方法的程式碼中,完成了提取和使用XML文件資料的工作。因此,程式設計師會覺得編碼工作比較困難,而且很難同時訪問同一個文件中的不同資料。

5.4  小結

  基於DOMXML解析,核心思想是XML文件內容轉化為一個節點物件樹,可以對樹節點進行遍歷、新增、修改或刪除;當然,還可以建立XML文件功能十分強大且程式設計簡單。因此,常用於XML文件需要頻繁改變的服務中。但缺點也非常明顯,因為解析器在對XML節點樹進行遍歷、新增、修改或刪除之前,必須先讀入整個XML文件,在記憶體中建立DOM節點物件因此,要消耗大量的記憶體資源文件比較小,不會造成大的問題XML文件比較大,對記憶體的需求將成倍增長,這會從解析速度上明顯的體現出來,甚至會因記憶體被消耗殆盡而宕機。

  基於DSE的解析,採用了掃描XML文件並丟擲解析資料的事件機制,即:一邊讀入XML內容,一邊掃描節點、一邊通過節點事件丟擲解析資料。解析器並不儲存每個XML節點物件,所以記憶體的消耗與XML文件的大小無關,特別適合於XML大文件快速解析。當然,這種路過式解析並處理資料的策略,不能實現對原文件內容的修改和刪除,而且先後丟擲的資料之間的邏輯,需要程式設計師在攔截掃描事件的方法中,自己編寫程式碼進行暫時儲存、關聯和最終處理。程式設計難度稍大。好在XWAF提供了XmlUserParser<T>泛型抽象類,提供了應用解析的基本框架和公共處理程式碼,程式設計師只需要建立繼承子類,並真正實現滿足自己功能需求的部分抽象方法,就大功告成。另外,程式設計師只需要關注、截留和處理自己需要的節點資料,無關的資料可以不管並隨即拋棄。即節省了記憶體資源,有加快了解析速度。對於只讀XML解析,DSE是最好的方案!

       CXDP集成了DOMDSE兩種解析方案,提供的XmlManager管理器進一步簡化了編碼,是程式設計師解析XML文件最好的幫手和選擇!