JDOM 是一種使用 XML 的獨特 Java 工具包,用於快速開發 XML 應用程序。它的設計包含 Java
語言的語法乃至語義。但是它是否比現有的 – 更標準的 – XML API
好呢?當我們看過一些示例並說明這個流行的開放源代碼項目的設計目標後,您自己來判斷吧。最近這個開放源代碼項目已被正式接受成為 Java 規范要求。
作為開發人員,您可能聽說過 80-20 規則,在其它領域被稱為 Pareto 法則:一種過程或方法能適應所有可能情況的 80%,另外的
20% 則需要根據具體情況來處理。軟件開發的必然結果是:對於開發人員而言,有了給定的技術後就能非常容易地完成可能要做的工作的 80%。
當然,軟件產品和標準並不總是根據 80-20 規則發展的。特別的,Java XML 的缺陷就是這條規則的一個例外。Java
的編程世界擁有很多的 API – 一些是自己開發的,一些是由幾個大公司開發並被制定為標準的 – 他們提供了解決特殊 XML
任務的成熟解決方案。作為 XML
普遍性的証明,每個新任務都存在?一種新技術,但如何將它們結合在一起,又如何尋找一種合適的工具去完成必須重復做的任務中的 80% – 利用
Java 語言的直觀映象的基本 XML 樹操作?JDOM 正好是用來解決上述問題的一個 XML API。
標記:Java 和 XML
在許多方面,Java 語言已變成供 XML 選擇的一種編程語言。由於 Apache 軟件基金會和 IBM alphaWorks 所做的開創性工作,現在已有完整的工具鏈用於創建,操作,傳送文檔和對 XML 文檔進行語法分析。
但是,雖然許多 Java 開發人員每天都在使用 XML,Sun 卻在將 XML 整合進 Java 平台方面落後了。因為在 XML
成為從商家對商家集成到 Web 站點內容流水化等方面的關鍵技術之前,Java 2 平台就已經非常流行了。Sun 已經使用 JSR
過程使之成為現存 XML API 的鼻祖,這一點已被廣泛接受。目前最顯著的是加入了 JAXP (用於 XML 語法分析的 Java
API),其中包含了三個軟件包:
- org.w3c.dom,W3C 推薦的用於 XML 標準規劃文檔對象模型的 Java 工具
- org.xml.sax,用於對 XML 進行語法分析的事件驅動的簡單 API
- javax.xml.parsers,工廠化工具,允許應用程序開發人員獲得並配置特殊的語法分析器工具
盡管對於 Java 開發人員而言,有了這些軟件包是件好事,但它僅僅代表獲得了現有 API 標準的正式許可而已,並沒有在提供一流的
Java-XML 互操作性方面取得了巨大飛躍。核心 Java 平台所缺乏的是將 XML 文檔作為 Java 對象操作的直觀接口。
進入 JDOM。JDOM 是兩位著名的 Java 開發人員兼作者,Brett Mclaughlin 和 Jason Hunter
的創作成果, 2000 年初在類似於 Apache 協議的許可下,JDOM 作為一個開放源代碼項目正式開始研發,JDOM
作為一個開放源代碼項目正式開始了。它已成長為包含來自廣泛的 Java 開發人員的投稿、集中反饋及錯誤修復的系統,並致力於建立一個完整的基於
Java 平台的解決方案,通過 Java 代碼來訪問、操作並輸出 XML 數據。
這是 JDOM 適合的 API、啞元
JDOM 能夠替換 org.w3c.dom 軟件包來有計劃地操作 XML 文檔。它並不是一個簡單的替代品,實際上 JDOM 和 DOM
能夠愉快地並存。另外,盡管它提供的類的封裝從配置和運行分析器執行中分擔了大量工作,但它不負責根據文本輸入來對 XML 進行語法分析。JDOM
建立在現有的 API 的能力之上,正如項目網頁所表述的"""""""""""
要理解需要備用 API 的原因,就要考慮 W3C DOM 設計的局限性:
- 語言獨立。DOM 並不是用人們心目中的 Java 語言設計的。雖然這種方法保留了在不同語言中非常相似的
API,它也使那些習慣 Java 語言的程序員感到更麻煩。例如:Java 語言內建了一種 String 類,而 DOM 則規范定義了自己的
Text 類。
- 嚴格的層次結構。DOM API 直接沿襲了 XML 規范。在 XML 中,每件東西都是一個結點,因此您能在 DOM
中找到一個幾乎每件東西都可以擴展的基於 Node 的接口和返回 Node 的一系列方法。就多態性的觀點來講,它是優秀的,但鑒於如上解釋,它在
Java 語言中的應用是困難而且不便的,其中從 Node 向葉類型作顯式下拉會導致代碼的冗長和難以理解。
- 接口驅動。公共 DOM API 僅由接口組成(Exception 類是一個例外,但恰恰足夠了)。w3c
對提供實現並不感興趣,它隻對定義接口(比較有意義)感興趣。但它也意味?作為 Java 程序員使用 API 在創建 XML
對象時增加了分散程度,因為 w3c 標準大量使用工廠化的類和類似的靈活的但不直接的模式。在某些應用中,XML
文檔是僅由語法分析器建立的,而從不會由應用程序級代碼建立,這是不相關的。但是,隨? XML
更廣泛的使用,並不是所有問題都繼續需要由語法分析器來驅動。應用程序的開發人員需要一個更方便的方法有計劃地構造 XML 對象。
對於程序員,這些約束意味?龐大(在內存佔用和接口大小方面)的和難掌握的 API,學習和使用都很難。相反,JDOM 是作為一種輕量級 API 被制定的,最主要的是它是以 Java 為中心的。它在遵循 DOM 主要規則的基礎上除去了上述缺點:
- JDOM 是 Java 平台專用的。隻要有可能,API 都使用 Java 語言的內建 String
支持,因此文本值也適用於 String。它還可利用 Java 2 平台的類集,如 List 和
Iterator,給程序員提供了一個豐富的並且和 Java 語言類似的環境。
- 沒有層次性。在 JDOM 中,XML 元素就是 Element 的實例,XML 屬性就是 Attribute
的實例,XML 文檔本身就是 Document 的實例。由於在 XML
中所有這些都代表了不同的概念,因此它們總是作為自己的類型被引用,而不是作為一個含糊的"""""
- 類驅動。因為 JDOM 對象就是像 Document、Element 和 Attribute
這些類的直接實例,因此創建一個新 JDOM 對象就如在 Java 語言中使用 new 操作符一樣容易。它還意味?不需要進行工廠化接口配置 –
JDOM 的使用是直截了當的。
看,沒有 Node:建立和操作 JDOM 文檔
JDOM 使用標準的 Java 編碼模式。隻要有可能,它使用 Java new
操作符而不用復雜的工廠化模式,使對象操作即便對於初學用戶也很方便。例如,讓我們看一下如何隨K使用 JDOM 建立一個簡單的 XML
文檔。我們將要建立的結構如清單 1 所示。(從參考資料上可下載關於本文的完整代碼)
清單 1. 建立 XML 文檔樣本
<?xml version="1.0" encoding="UTF-8"?>
<car vin="123fhg5869705iop90">
<make>Toyota</make>
<model>Celica</model>
<year>1997</year>
<color>green</color>
<license state="CA">1ABC234</license>
</car>
注意:我們將建立示例文檔,在下面的清單 2 到清單 7 中有詳細描述。
開始,讓我們先創建一個根元素,並將其添加到文檔中:
清單 2. 創建一個 Document
Element carElement = new Element("car");
Document myDocument = new Document(carElement);
這一步創建一個新 org.jdom.Element,並將其作為 org.jdom.Document myDocument
的根元素。(如果您使用參考資料中提供的樣本代碼,請務必導入 org.jdom.*。)因為一個 XML 文檔必須一直有一個唯一的根元素,所以
Document 將 Element 放在它的構造器中。
下一步,添加 vin 屬性:
清單 3. 添加一個 Attribute
carElement.addAttribute(new Attribute("vin", "123fhg5869705iop90"));
添加元素也是很簡單的。這裡我們添加 make 元素:
清單 4. 元素和子元素
Element make = new Element("make");
make.addContent("Toyota");
carElement.addContent(make);
由於 Element 的 addContent 方法返回 Element,我們也可以這樣寫:
清單 5. 用簡潔形式添加元素
carElement.addContent(new Element("make").addContent("Toyota"));
這兩個語句完成了相同的工作。有些人認為第一個示例可讀性更好,但是如果您一次建立許多元素,您會覺得第二個示例可讀性更好。要完成構建文檔:
清單 6. 添加其余的元素
carElement.addContent(new Element("model").addContent("Celica"));
carElement.addContent(new Element("year").addContent("1997"));
carElement.addContent(new Element("color").addContent("green"));
carElement.addContent(new Element("license")
.addContent("1ABC234").addAttribute("state", "CA"));
您會注意到對於 license 元素,我們不但添加了元素的內容,還為其添加了一個屬性,表明許可已被發出了這個狀態。這是因為 Element 的 addContent 方法總是返回 Element 本身,而不是一個無效的聲明。
用同樣的方法添加注釋部分或其它標準 XML 類型:
清單 7. 添加一條注釋
carElement.addContent(new Comment("Description of a car"));
操作文檔也是用類似方式。例如,要引用 year 元素,我們使用 Element 的 getChild 方法:
清單 8. 訪問子元素
Element yearElement = carElement.getChild("year");
該語句實際上將返回第一個元素名為 year 的子 Element。 如果沒有 year
元素,則調用返回一個空值。注意,我們不必回溯來自任何類似於 DOM Node 接口的返回值 – Element 的子元素就是
Element。用類似的方式,我們可把 year 元素從文檔中除去:
清單 9. 除去子元素
boolean removed = carElement.removeChild("year");
這次調用將隻除去 year 元素;文檔的其余部分保持不變。
到目前為止,我們已經涵蓋了文檔的生成和操作。要將完成的文檔輸出至控制台,可使用 JDOM 的 XMLOutputter 類:
清單 10. 將 JDOM 轉化為 XML 文本
try {
XMLOutputter outputter = new XMLOutputter(" ", true);
outputter.output(myDocument, System.out);
} catch (java.io.IOException e) {
e.printStackTrace();
}
XMLOutputter 有幾個格式選項。這裡我們已指定希望子元素從父元素縮進兩個空格,並且希望元素間有空行。 XMLOutputter 可輸出到 Writer 或 OutputStream。為輸出到文件,我們可以簡單地將輸出行簡化為:
清單 11. 使用 FileWriter 輸出 XML
FileWriter writer = new FileWriter("/some/directory/myFile.xml");
outputter.output(myDocument, writer);
writer.close();
與其它方法良好協作:和現有的 XML 工具進行互操作
JDOM 的一個有趣特征是和其它 API 有互操作性。使用 JDOM,不僅能把文檔輸出到 Stream 或 Reader,還可將文檔作為
SAX Event Stream 或作為 DOM Document。這種靈活性允許 JDOM
能在多種環境下使用或被添加到已經在使用另一種方法處理 XML 的系統中去。正如我們在後面一個示例中所看到的,它還允許 JDOM
使用其它的還不能識別 JDOM 的數據結構的 XML 工具。
JDOM 的另一個用處是它能夠讀取並操作現有的 XML 數據。使用 org.jdom.input 中的一個類可以閱讀結構很規范的 XML 文件。在這個示例中我們使用 SAXBuilder:
清單 12. 使用 SAXBuilder 對 XML 文件進行語法分析
try {
SAXBuilder builder = new SAXBuilder();
Document anotherDocument =
builder.build(new File("/some/directory/sample.xml"));
} catch(JDOMException e) {
e.printStackTrace();
} catch(NullPointerException e) {
e.printStackTrace();
}
您可以用清單 2 到清單 7 中顯示的方法來操作通過這個過程建立的文檔。
JDOM 的另一個實用應用程序將其與 Apache 的 Xalan
產品結合在一起(請參閱參考資料)。使用上面的汽車示例,我們將為在線汽車經銷商建立一個 Web
頁面,顯示特定汽車的詳細信息。首先,假設我們上面建立的文檔顯示我們準備呈現給用戶的汽車的信息。下一步,我們將把這個 JDOM Document
與一個 XSL 樣式表結合起來並把 HTML 格式的結果輸出到 servlet 的 OutputStream 上以便在用戶的瀏覽器中顯示。
在本例中,我們準備使用的 XSL 樣式表被稱為 car.xsl:
清單 13. 用於將汽車記錄轉換為 HTML 的 XSL 文檔
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http:>
<xsl:template match="/car">
<html>
<head>
<title><xsl:value-of select="make"/> <xsl:value-of select="model"/>
</head>
<body>
<h1><xsl:value-of select="make"/></h1><br />
<h2><xsl:value-of select="model"/></h2><br />
<table border="0">
<tr><td>VIN:</td><td><xsl:value-of select="@vin"/></td></tr>
<tr><td>Year:</td><td><xsl:value-of select="year"/></td></tr>
<tr><td>Color:</td><td><xsl:value-of select="color"/></td></tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
現在我們將把 org.jdom.Document 轉換為 DOM Document,並將其與顯示我們的 XSL 和
OutputStream 的文件一起提供給 Xalan,OutputStream 是我們從我們假定的使用 servlet(如清單 14
所示)的應用服務器上獲取的。
清單 14. 使用 JDOM 和 Xalan 創建 HTML 文檔
TransformerFactory tFactory = TransformerFactory.newInstance();
org.jdom.output.DOMOutputter outputter = new org.jdom.output.DOMOutputter();
org.w3c.dom.Document domDocument = outputter.output(myDocument);
javax.xml.transform.Source xmlSource =
new javax.xml.transform.dom.DOMSource(domDocument);
StreamSource xsltSource =
new StreamSource(new FileInputStream("/some/directory/car.xsl"));
StreamResult xmlResult = new StreamResult(response.getOutputStream());
Transformer transformer = tFactory.newTransformer(xsltSource);
transformer.transform(xmlSource, xmlResult);
在這個示例中,輸出是通過 Java servlet 的 HTTPResponse OutputStream
流出。然而,輸出流可以象早期的使用 XMLOutputter 的實例一樣簡單的通過文件流輸出。我們使用 DOMOutputter 為
Xalan 生成 XML 源代碼。但是我們可以生成相同的輸出,方法是使用 XMLOutputter 將我們的 XML 文檔作為 String
輸出並使其進入 StreamSource。說到靈活性:JDOM 可將它的結構作為 String、SAX Event Stream 或 DOM
Document 輸出。這允許 JDOM 與能把任何這些模型作為輸入的工具一起工作。(關於附加功能,請訪問 JDOM Web 站點的
contrib 包,在那裡您將發現一個基於 JDOM 工具的寶庫,可提供基於 JDBC ResultSet 的構建器、XPATH
實現方法和其它更多工具。)
在短短幾行代碼中,JDOM 啟用了許多功能,我們已經在 XML 中分析過並有計劃地創建了 XML 文檔,操作了那些文檔,並使用它們產生 XML 驅動的 Web 頁面。