從XML誕生之日起,它就一直是業界的焦點話題之一。經過了幾年的發展,XML技術日趨成熟,現在越來越多的應用都是基於XML開發的。在Internet日益普及的今天,分布式編程日顯重要,越來越多的應用都開始向這一方向轉型。在這一領域中,XML作為一種中間的資料介面,已經顯示出其不可替代的重要性。與此同時,Java語言開發Internet分布式應用程式的潛力也被越來越多的人看好,EJB體繫結構也日漸成熟。利用Java,人們可以很迅速的開發出可移植的、彈性好的、易於管理的分布式應用程式。
Java語言一直都被認為是最適合進行XML編程的語言之一。與平台無關的語言Java加上與平台無關的資料XML,確實能夠完成最為複雜且彈性最好的分布式應用。
在Java應用中引入XML,其實並不是很難,而且已經有諸多規範和諸多的類庫開發出來,以簡化Java中的XML的編程。在這些規範中,最為流行的就是SAX和DOM,後者也是W3C所推薦的標準。而支援XML的Java類庫更是不勝枚舉,除了Sun所發布的JXAP之外,還有像IBM、Microsoft等巨頭所提供的類似產品。而且,這些產品大多都是免費的,用起來不用花一分錢。所有的這些規範和類庫,已經在很大程度上簡化了XML編程的複雜係數,你只需要瞭解這些規範和JXAP所定義的API,就已經能夠進行XML編程了。而我們這篇文章的目的,也就是為大家介紹這些規範和API。相信讀完本文後,您就不會再認為XML編程是多麼困難的事了。
背景知識
關於XML的討論已經很多了,對於XML的看法也是見仁見智。要給XML下一個確切的定義是一件很困難的事情,但我們可以從下面四個方面來看:
1.XML是一種被設計成方便的用來在Internet上傳播的標記語言。XML與SGML相容(確切的說是SGML的一個簡化了的子集),並且能夠很容易的在任何文字編輯器中進行瀏覽和編輯。
2.XML用來定義資料的邏輯結構,用樹的方式將所有的資料群組織起來,這使得XML文檔很容易理解和處理。而XML文檔的結構是通過DTD或者Schema預先定義的,這使得XML中的資料在特定的應用中都能夠有確切的含義。
3.XML是一種定義嚴格的語言,它幾乎沒有定義什麼可選的特性。這使得XML達到了最大程度的通用性,任何與XML相容的解析器都可以對一個合法的XML文檔進行解析而不會出現任何錯誤。這樣,XML就能夠作為一種最廣義的中介,在各種平台,各種語言和各種程式中流通。
4.XML是一種用來定義資料和原資料的文法,這就使得你能夠定義資料本身。這也是XML最重要的特性之一,因為從理論上講,任何東西都可以用資料進行描敘。也就是說,由於XML提供了描敘資料的方法,因而也就具備了描敘任何事物的能力。
關於XML的應用,我們舉一個簡單的例子來看看它的威力所在。
現在的大部分網站都是用HTML編寫的。網頁設計師們精心設計的網頁,能夠在Web瀏覽器上很漂亮的顯示出來,但是如果想把這些網頁所包含的內容重新設計在一本書中的話,顯然,瀏覽器上的漂亮內容就不能很方便的在書中體現出來了。我們知道,HTML是一種結構性很差的語言,它將顯示和內容緊密的結合在一起,要將內容有選擇的從HTML檔案中分離出來是非常困難的,特別是在那些設計精美的網頁中。這時候,或許唯一的辦法就是重新進行設計了。但是,XML的出現為解決這種問題提供了一種良好的解決方案。
因為XML只是定義資料,它並不關心資料是如何顯示的,所以用XML設計出的網站其內容和顯示是分離的。一般的網頁是通過XSLT對給定的XML文檔進行變換之後產生的。現在我們要將網站的內容放在一本書中,只需要重新定義XSLT,給出變化規則,就可以將內容完美的再現在另外的一種形式中了。
上面所講述的只是XML應用的一個重要方面,實際上現在XML的應用遠遠不止如此,很多協議比如SOAP,都是基於XML的。
下面的內容,就是具體的XML編程了。由於本文假定您已對Java語言(或者其它物件導向的語言)有了一定的瞭解,因而對一些關於語言的細節問題,就不再贅述了。
Java下XML編程介面比較:DOM SAX JDOM JAXP
一、DOM (文件物件模型)
為 XML 文檔的已解析版本定義了一組介面。解析器讀入整個文檔,然後構建一個駐留記憶體的樹結構,然後代碼就可以使用 DOM 介面來操作這個樹結構。
優點:整個文檔樹在記憶體中,便於操作;支援刪除、修改、重新排列等多種功能;
缺點:將整個文檔調入記憶體(包括無用的節點),浪費時間和空間;
使用場合:一旦解析了文檔還需多次訪問這些資料;
硬體資源充足(記憶體、CPU)
二、SAX
為解決DOM的問題,出現了SAX。
SAX ,事件驅動。當解析器發現元素開始、元素結束、文本、文檔的開始或結束等時,發送事件,程式員編寫響應這些事件的代碼,儲存資料。
優點:不用事先調入整個文檔,佔用資源少;
SAX解析器代碼比DOM解析器代碼小,適於Applet,下載
缺點:不是持久的;事件過後,若沒儲存資料,那麼資料就丟了;
無狀態性;從事件中只能得到文本,但不知該文本屬於哪個元素;
使用場合:Applet;
只需XML文檔的少量內容,很少回頭訪問;
機器記憶體少;
三、JDOM
為減少DOM、SAX的編碼量,出現了JDOM;
優點:20-80原則,極大減少了代碼量
使用場合:要實現的功能簡單,如解析、建立等
Java程式
但在底層,JDOM還是使用SAX(最常用)、DOM、Xanan
四、JAPX
為多個XML解析器提供了統一編程介面
更換解析器,不用更改代碼
使用場合:若不用Jdom,一般建議使用JAPX,將代碼與各種解析器的實現細節隔離。
(一)JDOM的介紹以及與JAXB的比較
Java + XML = JDOM !
這就是JDOM設計者的目標。如果你曾經使用過煩人的SAX或是DOM來處理XML,你就會知道為什麼要有JDOM或者是JAXB。在今年(2002)的JavaOne會議上JDOM的主要創始人Jason Hunter有一篇精彩的演講介紹了JDOM技術,題目就是JDOM Makes XML Easy。
在那篇文檔裡,JDOM被拿來與DOM比較,而我更願意拿它同JAXB比較。因為JAXB和JDOM都是為了在Java中提供比DOM和SAX更為方便的XML處理介面而開發的,並且通過完全不同的途徑來解決這個問題。JDOM的處理方式是與DOM類似的樹操作。而JAXB通過DTD和繫結模式來產生訪問XML文檔的Java代碼,將XML映射成了Java對象來操作。你可以根據項目的需要和個人喜好來決定採用哪一個。
JDOM與JAXB的比較,從本身的特點來看:
1) JDOM比JAXB更容易上手。使用JAXB首先要會編寫DTD,然後還要會編寫繫結模式。JDOM沒有這樣的要求,如果你會Java和XML,甚至可以說光是看JDOM的javadoc文檔就能夠使用JDOM。
2) JAXB編寫好DTD和繫結模式以後,XML文檔被映射成了Java對象,其資料就是Java對象的屬性,連資料類型都做好了轉換,因此,訪問XML文檔比JDOM要簡便,可以說是一勞永逸。
3) JAXB由某個DTD和繫結模式產生的程式碼只能訪問該DTD所約束的文檔。如果想要訪問其他XML文檔,需要再編寫DTD和繫結模式。JDOM可以處理任何XML文檔,包括受約束的和不受約束的。
目前JDOM和JAXB都沒有正式版本。JDOM的最新版本是beta8,JAXB是1.0 early access,其規範版本是0.21。相對而言,JDOM更成熟一些。例如JAXB不支援名字空間、不能向XML文檔寫入處理指示,有時我們需要保留的分行符號和首尾空格在JAXB中自動過濾掉了,就連放在<![CDATA[ 和 ]]>裡面也不能倖免。JDOM就沒有這些限制。如果說以上的3點比較是JDOM和JAXB本身的特點所決定的,幾乎不可能改變,那麼這裡表明,JAXB還需要更多的工作。
(二)獲得並安裝JDOM
在http://jdom.org可以下載JDOM的最新版本。以JDOM beta8的2進位版本為例。下載後解壓縮,JDOM的jar檔案就是build目錄下的檔案jdom.jar,將之加入類路徑。另外JDOM還需要lib目錄下那些jar檔案如xerces.jar的支援。如果在使用中出現以下錯誤:
java.lang.NoSuchMethodError
或
java.lang.NoClassDefFoundError: org/xml/sax/SAXNotRecognizedException
你需要保證xerces.jar檔案在CLASSPATH中位於其他XML類,如JAXP或Crimson之前,這些類檔案,包括以前老版本的xerces,可能不支援SAX2.0或DOM Level 2。於是導致了上面的錯誤。
(三)一個簡單的例子
JDOM的處理方式有些類似於DOM,但它主要是用SAX實現的,你不必擔心處理速度和記憶體的問題。另外,JDOM中幾乎沒有介面,的類全部是實實在在的類,沒有類工廠類的。其最重要的一個包org.jdom中主要有以下類:
? Attribute
? CDATA
? Comment
? DocType
? Document
? Element
? EntityRef
? Namespace
? ProcessingInstruction
? Text
資料輸入要用到XML文檔要通過org.jdom.input包,反過來需要org.jdom.output。如前面所說,關是看API文檔就能夠使用。
我們的例子讀入XML檔案exampleA.xml,加入一條處理指示,修改第一本書的價格和作者,並添加一條屬性,然後寫入檔案exampleB.xml:
//exampleA.xml
<?xml version="1.0" encoding="GBK"?>
<bookList>
<book>
<name>Java編程入門</name>
<author>張三</author>
<publishDate>2002-6-6</publishDate>
<price>35.0</price>
</book>
<book>
<name>XML在Java中的應用</name>
<author>李四</author>
<publishDate>2002-9-16</publishDate>
<price>92.0</price>
</book>
</bookList>
//testJDOM.java
import org.jdom.*;
import org.jdom.output.*;
import org.jdom.input.*;
import java.io.*;
public class TestJDOM{
public static void main(String args[])throws Exception{
SAXBuilder sb = new SAXBuilder();
//從檔案構造一個Document,因為XML檔案中已經指定了編碼,所以這裡不必了
Document doc = sb.build(new FileInputStream("exampleA.xml"));
//加入一條處理指示
ProcessingInstruction pi = new ProcessingInstruction
("xml-stylesheet","href="bookList.html.xsl" type="text/xsl"");
doc.addContent(pi);
Element root = doc.getRootElement(); //得到根項目
java.util.List books = root.getChildren(); //得到根項目所有子項目的集合
Element book = (Element)books.get(0); //得到第一個book元素
//為第一本書添加一條屬性
Attribute a = new Attribute("hot","true");
book.setAttribute(a);
Element author = book.getChild("author"); //得到指定的字元素
author.setText("王五"); //將作者改為王五
//或 Text t = new Text("王五");book.addContent(t);
Element price = book.getChild("price"); //得到指定的字元素
//修改價格,比較鬱悶的是我們必須自己轉換資料類型,而這正是JAXB的優勢
author.setText(Float.toString(50.0f));
String indent = " ";
boolean newLines = true;
XMLOutputter outp = new XMLOutputter(indent,newLines,"GBK");
outp.output(doc, new FileOutputStream("exampleB.xml"));
}
};
執行結果exampleB.xml:
<?xml version="1.0" encoding="GBK"?>
<bookList>
<book hot=”true”>
<name>Java編程入門</name>
<author>50.0</author>
<publishDate>2002-6-6</publishDate>
<price>35.0</price>
</book>
<book>
<name>XML在Java中的應用</name>
<author>李四</author>
<publishDate>2002-9-16</publishDate>
<price>92.0</price>
</book>
</bookList>
<?xml-stylesheet href="bookList.html.xsl" type="text/xsl"?>
在預設情況下,JDOM的Element類的getText()這類的方法不會過濾空白字元,如果你需要過濾,用setTextTrim() 。
(四)參考文檔
1) JDOM Makes XML Easy (http://www.servlets.com/speaking/jdom-javaone.pdf)
2) The Java ™ Architecture for XML Binding User’s Guide (http://java.sun.com/xml/jaxb/jaxb-docs.pdf)
3) Web Services Made Easier. The Java TM APIs and Architectures for XML, A Technical White Paper (http://java.sun.com/xml/webservices.pdf )
什麼時候使用DOM
--------------------------------------------------------------------------------
如果你的XML文檔包含文檔資料(例如, Framemaker documents stored in XML format), 那麼DOM就是你的解決方案的最自然選擇。如果你要建立一些類似於文檔資訊管理的系統,那麼你不得不處理大量的文檔資料。Datachannel RIO 產品就是這麼一個例子,它可以索引和組織各種類型文檔資源中的資訊(例如Word和Excel 檔案)。在這種情況下,DOM是非常合適程式去訪問存貯在這些文檔中的資訊的。
然而,如果你主要處理的是結構化的資料(在XML中的序列化的JAVA對象the equivalent of serialized Java objects in XML),DOM不是最好的選擇。那就是SAX會比較合適的地方。
什麼時候使用SAX
--------------------------------------------------------------------------------
如果在你XML文檔中的資訊是機器易讀的(和機器產生的)資料,那麼SAX是讓你可以訪問這些資訊的合適的API。機器易讀和產生的資料類型包含像下面這些東東:
存成XML格式的Java對象屬性
用一些以文本為基礎的查詢語句(SQL, XQL, OQL)表示的查詢
由查詢產生的結果集(這也許內含項目關聯性型資料庫表中的資料編碼成XML).
這麼看來機器產生的資料是你一般要在java中產生資料結構和類的資訊。一個簡單的例子是包含個人資訊的地址簿,在所示。這個地址簿xml檔案不像文書處理器文檔,它是一個包含已經被編碼成文本的純資料的XML文檔。
當你的資料是這種樣式,你要建立你自己的資料結構和類(物件模型)來管理操作以及持續儲存這些資料。SAX容許你快速建立一個可以產生你的物件模型執行個體的處理器類。一個執行個體是:一個SAX文檔處理器。它完成的工作有讀入包含我的地址薄資訊的XML文檔,建立一個可以訪問到這些資訊的AddressBook類。SAX指南告訴你該怎麼做到這些。這個地址薄XML文檔包含person元素,person元素中有name和email元素。我的AddressBook物件模型包括下面的類:
AddressBook 類,Person對象的容器
Person 類,String 型的name和email的容器
這樣我的“SAX 地址簿文檔處理器”可以把person元素轉變成Person對象了,然後把它們都存入AddressBook對象。這個文檔處理器將name和email元素轉變為String對象。