程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> J2ME中的XML語法分析利器KXML

J2ME中的XML語法分析利器KXML

編輯:關於JAVA

Enhydra的KXML是一個只占很小存儲空間的XML語法分析程序,對於J2ME應用程序非常適合 。它有一個非常獨特的DOM操作方法和被稱為Pull的語法分析方法。

在開發一個用於J2ME設備的多人游戲項目。在這個應用程序中,服務器和設備之間的通訊 原來被編碼成由"&"分隔的鍵值對,這樣從服務器檢索變量會很快,但是當我開始處理更 復雜的數據結構和嵌套的數據結構時,我發現這種方法並不適用。在這種情況,它會變得很 難寫數據並且容易出錯。

為了解決這問題,我決定使用XML重新編寫應用程序的數據傳輸部分。對於我來說,XML是 一個自然而然的選擇,不僅僅因為我已經使用它在以前的一個項目中編寫了通過網絡向 applet中傳送信息的程序,而且因為XML確實很容易調試和編寫。當然,它還讓你使用一種很 豐富的格式來結構化這些數據。然而,讓我意想不到的是我竟為我的編程工具箱找到一顆珍 貴的寶石。

KXML是一個被設計用於J2ME設備的簡化類庫,雖然它也可以被用於其它需要小型XML語法 分析程序的環境,比如Applet。KXML是一個Enhydra維護的項目,支持下面的性能:

支持XML名稱空間

用"松散"模式分析HTML或其它SGML格式

占用很少的存儲空間(21 kbps)

基於Pull的分析

支持XML寫操作

可選的DOM支持

可選的WAP支持

在本文中,詳細說明其中的一些特點,尤其是Pull分析和DOM操作,而且我將告訴你如何 檢查KXML在內存中操作的效果。本文中的兩個MIDlet例程都有完整的源代碼,可以向你說明 如何使用KXML(點擊下載)。在KToolBar 1.04工程中不包含KXML類庫--你必須從 http://KXML.enhydra.org/取得類庫,然後把壓縮文件放在工程的"lib"目錄下。

使用XML工作

有兩個常見的使用XML工作的方法:操作DOM或者捕捉語法分析事件。操作DOM是一個與XML 相互作用的簡單方法,通常這個XML是一棵完整的XML樹,被解析成一個存放在存儲器中的節 點結構,你可以遍歷這棵樹。它非常簡單易用,但是因為整棵樹存在於存儲器中造成存儲器 的負擔。

第二種方法在捕捉語法分析事件中,每當語法分析程序遇到數據中的特定結構,它就會遍 歷XML數據,然後把結果發回前面注冊的一個事件監聽器中。比如說,當語法分析程序遇到一 個起始標記,如<html>,那麼事件監聽器將接收一個事件,通知它這個情況,並且向它傳 遞任何所需的信息。實現這種策略的語法分析程序被稱為push語法分析程序,因為這個語法 分析程序把事件"推入"一個監聽器中。

KXML支持DOM語法分析和操作,但是不支持push語法分析。取而代之,它使用一種稍微不 同的稱為"Pull"的分析方法。與push語法分析相反,Pull語法分析讓程序員從語法分析程序 中"拉"出下一個事件。在push語法分析中,你必須維護你正在分析的當前數據的狀態,然後 基於傳送到監聽器的事件,恢復任何以前的狀態,並且當你轉換到一個不同的狀態時保存新 的狀態。Pull語法分析使處理狀態改變更加容易,因為你可以發送分析器到不同的函數,維 護它們自己的狀態變量。

Pull語法分析

讓我們來研究一個例子,看看KXML如何做一個Pull語法分析程序。演示程序名為 KXMLDemo_Pull。它將使用一個Pull語法分析程序查看一個包含通訊錄信息的文件。下面給出 源代碼中比較重要的幾行,我還給出了注釋。

1.XmlParser parser = null;
2......
3.parser = new XmlParser( new InputStreamReader( 1this.getClass ().getResourceAsStream(resfile_name) ));

第三行創建了一個XmlParser,把它傳到一個InputStream中。這個語法分析程序反復調用 ,直到出現END_DOCUMENT事件。

1.while ( (event = parser.read()).getType() != Xml.END_DOCUMENT ) {
2. ...
3.if (name != null && name.equals("address")) {
4. ...
5. parseAddressTag( parser );

第三行判斷事件是否以一個<address>標記開始,第五行傳送語法分析器到控制語法分 析程序的"parseAddressTag"。

1.while ((event = parser.peek()).getType() != Xml.END_DOCUMENT) {
2....
3. if (type == Xml.END_TAG && name.equals("address")) {
4. return;
5. }
6....
7. ParseEvent next = parser.read();
8.
9. // if it's not a text event then skip it
10. if (next.getType() != Xml.TEXT) {
11. continue;
12. }
13....

14. System.err.println(name + ": " + text);

上面的這段代碼在"parseAddressTag"中循環,直到找到與<address>對應的終止標記。 如果它遇到其它任何標記,那麼標記名和標記內容就會被打印到控制台上。因此,如果找到 標記<name>Robert Cadena</name>,你將看到下面的控制台輸出:

name: Robert Cadena

一旦找到<address>的終止標記(8- 10行),控件被返回調用函數,然後又開始查找< address>。

如你所見,使用Pull語法分析程序非常容易,並且能夠傳送語法分析程序到另一個函數, 然後在文檔中查找元素。你並不局限於分析資源文件;你還可以使用HttpConnection把這個 函數傳遞到http InputStream。這把你從讀取InputStream、保存內容、分析內容等操作中解 放了出來,一切都由KXML為你完成。

DOM處理

Pull語法分析特別適用於當你需要維護非常小的存儲空間的時候,因為發出事件的文檔只 有一部分存在於內存中。換句話說,如果你感興趣的特定數據段是文檔中部的幾百個字節, 那麼前面的幾百個字節就不必保存在內存中了。

但是如果你能夠節省一些內存,你可以使用另一個版本的KXML語法分析程序,它包含對 DOM的支持。 DOM是保存在內存中的整個文檔樹,每個標記都被分離成節點(Node)對象。 你可以遍歷這個文檔樹,然後根據需要取得數據。

工程中的另一個MIDlet,KXMLDemo_dom,做了同樣的事情。它讀取一個通訊錄,然後把內 容打印到控制台,但是這次它使用了DOM。下面給出源代碼中比較重要的幾行.

1.Document doc = new Document();

2....

3.parser = new XmlParser( isr );

4.doc.parse( parser );

第一行創建了一個文檔,保存XML樹。第三行從一個名為isr的InputStreamReader中創建 一個KXML語法分析程序。第四行傳送這個語法分析程序到文檔,然後讓文檔開始分析。XML被 遞歸分析,直到到達文檔的結尾。當分析調用退出時,整個文檔被裝入內存,這時你就可以 操作它了。

1.Element root = doc.getRootElement();
2.int child_count = root.getChildCount();
3....
4.for (int i = 0; i < child_count ; i++ ) {
5....
6. Element kid = root.getElement(i);
7.
8. if (!kid.getName().equals("address")) {
9. continue;
10. }

因為我們知道<address>元素是根元素的直接子元素,我們可以遍歷根元素的子元素, 尋找address標記,如果子元素不是一個address 標記,則返回。

1.int address_item_count = kid.getChildCount();
2.
3. for (int j = 0; j < address_item_count ; j++) {
4....
如果我們找到了address子元素,我們開始遍歷它的子元素,並把這些子元素的內容 打印出來。不幸的是,你不能只是使用kid.getElement("name"),因為如果這個元素不存在 的話,那麼你將得到一個RuntimeException。所以我建議只有當你知道XML文檔中存在你所有 需要的所有字段時才使用這個方法。

檢查你的內存

根據經驗,當你不能確保你的應用程序的結構,並且你需要保持內存被占用情況較低時, 你應該使用Pull語法分析程序。當你有足夠內存並且可能需要通過添加或移動標記的方式操 作文檔時,可以使用DOM。

如果你想看看這兩種方法使用內存的情況,在KtoolBar中打開工程,使用內存監視器 (Edit-->Preferences:Monitoring Tag)。 當你運行MIDlet,你將看到內存監控窗口彈出 ,有圖形和數字表示內存的使用情況。 運行每一個應用程序,然後觀察綠線上升,這表示你 的應用程序消耗的內存量。 你將看到Pull應用程序比DOM應用程序使用內存少一些。雖然本 例中的兩個MIDlet之間的區別不是非常大,但是如果一個MIDlet用DOM方式遍歷一個更大的文 件,那麼它將消耗更多內存。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved