jaxp相關

JAXP 專述
 
作者:Brett Mc…    文章來源:IBM developerWorks    點擊數:179    更新時間:2006-4-27 
 
這是篇細探 JAXP,Sun 的 Java API for XML 的文章,幫助解除了有關 JAXP 本質和服務目的的疑惑。本文講解了 JAXP 的基本概念,演示 XML 語法分析爲什麼需要 JAXP,並顯示如何輕易更改 JAXP 使用的語法分析器。本文還進一步講述了 SAX 和 DOM 這兩個流行的與 JAXP 相關的 Java 和 XML API。
Java 和 XML 在每一個技術領域都製造了新聞,並且對於軟件開發人員來說,似乎是 1999 年和 2000 年最重要的發展。結果,Java 和 XML API 的數量激增。其中兩個最流行的 DOM 和 SAX 還引起極大興趣,而 JDOM 和數據綁定 API 也接踵而來。只透徹理解這些技術中的一個或兩個就是一項艱鉅任務,而正確使用所有這些技術就會使您成爲專家。但在去年,另一個 API 給人留下了深刻印象,它就是 Sun 的 Java API for XML,通常稱爲 JAXP。如果考慮到 Sun 在其平臺上還沒有任何特定於 XML 的產品,那麼這個進展就不足爲奇。而令人驚奇的是人們對 JAXP 瞭解的缺乏。多數使用它的開發人員在他們所用的這個 API 的概念理解上都有錯誤。

什麼是 JAXP?

本文假設您有 SAX 和 DOM 的基本知識。這裏實在沒有足夠篇幅來解釋 SAX、DOM 和 JAXP。如果您是 XML 語法分析的新手,那麼可能要通過聯機資源閱讀 SAX 和 DOM,或者瀏覽我的書。( 參考資源 一節中有至 API 和我的書的鏈接。)獲得基本知識後再看本文會比較好。

 

 


 
 

 

API 還是抽象?

在講解代碼之前,介紹一些基本概念很重要。嚴格地說,JAXP 是 API,但是將其稱爲抽象層更準確。它不提供處理 XML 的新方式,不補充 SAX 或 DOM,也不向 Java 和 XML 處理提供新功能。(如果在這點上理解有誤,則本文正好適合您!)它只是使通過 DOM 和 SAX 處理一些困難任務更容易。如果在使用 DOM 和 SAX API 時遇到特定於供應商的任務,它還使通過獨立於供應商的方式處理這些任務成爲可能。

雖然要分別講述所有這些特性,但是真正需要掌握的是:JAXP 不提供語法分析功能 !沒有 SAX、DOM 或另一個 XML 語法分析 API,就 無法分析 XML 語法 。有很多人曾讓我將 DOM、SAX 或 JDOM 與 JAXP 進行對比。但進行這些對比是不可能的,因爲前三個 API 與 JAXP 的目的完全不同。SAX、DOM 和 JDOM 都分析 XML 語法。而 JAXP 卻提供到達這些語法分析器和結果的方式。它自身不提供分析文檔語法的新方法。如果要正確使用 JAXP,則一定要弄清這點。這將使您比其它 XML 開發人員領先一大截。

如果仍然懷疑(或認爲我故弄玄虛),請從 Sun 的 Web 站點下載 JAXP 分發(請參閱 參考資料 一節),然後就會知道基本 JAXP 是什麼。在包括的 jar ( jaxp.jar ) 中 只有六個類 !這個 API 會有多難哪?所有這些類( javax.xml.parsers 包的一部分)都位於現有語法分析器之上。這些類中的兩個還用於錯誤處理。JAXP 比人們想象的要簡單得多。那麼,爲什麼還感到困惑哪?

 

 


 
 

 

Sun 的 JAXP 和 Sun 的語法分析器

JAXP 下載時包括 Sun 的語法分析器。所有 parser 器類作爲 com.sun.xml.parser 包和相關子包的一部分位於 parser.jar 檔案中。應該知道,該語法分析器(代碼名爲 Crimson) 不 是 JAXP 自身的一部分。它是 JAXP 版本的一部分,但不是 JAXP API 的一部分。令人困惑嗎?有一點。換這種方式想想:JDOM 與 Apache Xerces 語法分析器一起提供。該語法分析器不是 JDOM 的一部分,但由 JDOM 使用,所以包括它,以確保 JDOM 可以單獨使用。JAXP 也是如此,但不象 JDOM 那樣好表達:JAXP 與 Sun 的語法分析器一起提供,以便可以立即使用。但是,很多人將 Sun 的語法分析器中包括的類當成 JAXP API 的一部分。例如,新聞組中一個常見的問題是:“怎樣使用 JAXP 中的 XMLDocument 類?其目的是什麼?”這個答案可有些複雜。

首先, com.sun.xml.tree.XMLDocument 類不是 JAXP 的一部分。它是 Sun 語法分析器的一部分。所以,這個問題從一開始就給人以誤導。其次,JAXP 的整個意義在於在處理語法分析器時提供供應商獨立性。使用 JAXP 的同一代碼可以與 Sun 的 XML 語法分析器、Apache 的 Xerces XML 語法分析器和 Oracle 的 XML 語法分析器一起使用。而使用特定於 Sun 的類是個壞主意。這與 JAXP 的整個意義相背離。現在看出來這個問題怎樣混淆概念了嗎?語法分析器和 JAXP 發行版本(至少是 Sun 的版本)中的 API 被混爲一談,開發人員將其中一個的類和特性當成是另一個的了,反之亦然。

 

 


 
 

 

舊和新

關於 JAXP,最後需要指出的是:使用 JAXP 有一些缺陷。例如,JAXP 只支持 SAX 1.0 和 DOM 第一層規範。SAX 2.0 從 2000 年 5 月起就完成,DOM 第二層規範支持甚至在大多數語法分析器中存在更長時間。DOM 第二層規範還沒有完成,但確實足夠穩定以用於生產。這兩個 API 的新版本都有重大改進,最明顯的是對 XML 名稱空間的支持。該支持還允許“XML Schema 確認”,這個與 XML 相關的另一熱門技術。公平地說,當 JAXP 發佈 1.0 最終發行版時,SAX 2.0 和 DOM 第一層規範都還沒有完成。但是,由於沒有包括這些新版本,確實爲開發人員帶來很大不便。

還可以使用 JAXP,但是也可以等待 JAXP 1.1,它支持 SAX 2.0 和 DOM第二層規範 。否則,將發現,JAXP 提供的優點以 SAX 和 DOM 最新版本中的功能爲代價,並使應用程序更加難以編碼。無論是否等待下一個 JAXP 發行版,都要留意這個問題。如果將 JAXP 與語法分析器一起使用,而語法分析器支持的 DOM 和 SAX 版本比 JAXP 支持的要高,則可能會有類路徑問題。所以,事先留意一下,並且,一旦有 JAXP 1.1,馬上升級。基本理解 JAXP 之後,讓我們看一下 JAXP 依賴的 API:SAX 和 DOM。

 

 


 
 

 

從 SAX 開始

SAX (Simple API for XML)是用於處理 XML 的事件驅動方法。它基本由許多回調函數組成。例如,每當 SAX 語法分析器遇到元素的開始標記時就調用 startElement() 。對於字符串,將調用 characters() 回調函數,然後在元素結束標記處調用 endElement() 。還有很多回調函數用於文檔處理、錯誤和其它詞彙結構。現在知道這是怎麼回事了。SAX 程序員實現一個定義這些回調函數的 SAX 接口。SAX 還實現一個名爲 HandlerBase 的類,該類實現所有這些回調函數,並提供所有這些回調方法的缺省空實現。(提到這一點是因爲它在後面講到的 DOM 中很重要。)SAX 開發人員只需擴展這個類,然後實現需要插入特定邏輯的方法。所以,SAX 的關鍵在於爲這些不同的回調函數提供代碼,然後允許語法分析器在適當的時候觸發這些回調函數中的每一個。

因此,典型的 SAX 過程如下:

用特定供應商的語法分析器實現創建一個 SAXParser 實例
註冊回調實現(例如,通過使用擴展 HandlerBase 的類)
開始進行語法分析,然後在觸發回調實現時等待
JAXP 的 SAX 組件提供執行所有這些步驟的簡單方式。如果沒有 JAXP,SAX 語法分析器要直接從供應商類(如 org.apache.xerces.parsers.SAXParser )進行實例化,或者必須使用名爲 ParserFactory 的幫助類。第一個方法的問題很明顯:不獨立於供應商。第二個方法的問題在於類廠需要一個自變量,即要使用的語法分析器類的字符串名稱(還是那個 Apache 類 org.apache.xerces.parsers.SAXParser )。可以通過將不同語法分析器作爲 String 傳遞來更改語法分析器。使用這種方法不必更改任何 import 語句,但是還是要重新編譯類。這顯然不是最佳解決方案。如果能夠不重新編譯類而更改語法分析器,可能會簡單得多,是不是這樣呢?

JAXP 提供了更好的替代方法:它允許將語法分析器作爲 Java 系統屬性來提供。當然,當從 Sun 下載版本時,將得到使用 Sun 語法分析器的 JAXP 實現。可以從 Apache XML Web 站點下載在 Apache Xerces 上構建其實現的相同 JAXP 接口。因此(無論哪一種情況),更改正在使用的語法分析器需要更改類路徑設置,即從一種語法分析器實現更改到另一個,但是 不要求重新編譯代碼。這就是 JAXP 的魔力,或抽象性。

SAX 語法分析器一瞥

JAXP SAXParserFactory 類是能夠輕易更改語法分析器實現的關鍵所在。必須創建這個類的新實例(等一會將講到)。創建新實例之後,類廠提供一個方法來獲得支持 SAX 的語法分析器。在內部,JAXP 實現處理依賴於供應商的代碼,使您的代碼不受影響。這個類廠還提供其它一些優秀特性。

除創建 SAX 語法分析器實例的基本工作之外,類廠還允許設置配置選項。這些選項影響所有通過類廠獲得的語法分析器實例。JAXP 1.0 中兩個可用的功能是設置名稱空間敏感性 ( setNamespaceAware (boolean awareness)),和打開確認 ( setValidating (boolean validating))。請記住,一旦設置了這些選項,在調用該方法之後,它們將影響 所有從 類廠獲得的實例。

設置了類廠之後,調用 newSAXParser() 將返回一個隨時可用的 JAXP SAXParser 類實例。這個類封裝了一個下層的 SAX 語法分析器(SAX 類 org.xml.sax.Parser 的實例)。它還防止向語法分析器類添加任何特定於供應商的附加功能。(還記得以前對 XmlDocument 的討論嗎?)這個類可以開始進行實際的語法分析。以下清單顯示如何創建、配置和使用 SAX 類廠。


清單 1. 使用 SAXParserFactory

import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;

// SAX
import org.xml.sax.AttributeList;
import org.xml.sax.HandlerBase;
import org.xml.sax.SAXException;

public class TestSAXParsing {

 public static void main(String[] args) {
 try {
 if (args.length != 1) {
 System.err.println ("Usage: java TestSAXParsing [filename]");
 System.exit (1);
 }

 // 獲得SAX 語法分析器類廠
 SAXParserFactory factory = SAXParserFactory.newInstance();

 //設置設置名稱空間敏感性選項,關掉確認選項
 factory.setValidating(true);
 factory.setNamespaceAware(false);

 SAXParser parser = factory.newSAXParser();
 parser.parse(new File(args[0]), new MyHandler());

 } catch (ParserConfigurationException e) {
 System.out.println("The underlying parser does not support " +
 " the requested features.");
 } catch (FactoryConfigurationError e) {
 System.out.println("Error occurred obtaining SAX Parser Factory.");
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
}

class MyHandler extends HandlerBase {
 //通過 DocumentHandler, ErrorHandler等實現的SAX回調函數
}

 


請注意,在這段代碼中,在使用類廠時可能發生兩個特定於 JAXP 的問題:無法獲得或配置 SAX 類廠,以及無法配置 SAX 語法分析器。當無法獲得 JAXP 實現中指定的語法分析器或系統屬性時,通常會發生第一個問題 FactoryConfigurationError 。當正在使用的語法分析器中的特性不可用時,會發生第二個問題 ParserConfigurationException 。這兩個問題都容易處理,應該不會對 JAXP 的使用造成任何困難。

在獲得類廠、關閉名稱空間並打開“確認”之後,將獲得 SAXParser ,然後開始語法分析。請注意, SAX 語法分析器的 parse() 方法取得前面提到的 SAX HandlerBase 類的一個實例。(可以通過完整的 Java 清單 查看該類的實現 。)還要傳遞要進行語法分析的文件。但是, SAXParser 所包含的遠不止這一個方法。

使用 SAX 語法分析器

獲得 SAXParser 類的實例之後,除了向語法分析器傳遞 File 進行語法分析之外,還可以用它做更多的事。由於如今大型應用中的應用程序組件之間通信方式,“對象實例創建者就是其使用者”這樣的假定並不總是安全的。換句話說,一個組件可能創建 SAXParser 實例,而另一組件(可能由另一開發人員編碼)可能需要使用那個實例。由於這個原因,提供了一些方法來確定語法分析器的設置。執行此任務的兩個方法是 isValidating() ,它通知調用程序:語法分析器將要、或不要執行“確認”,以及 isNamespaceAware() ,它返回一個指示,說明語法分析器可以或不可以處理 XML 文檔中的名稱空間。雖然這些方法能提供有關語法分析器可以執行功能的信息,但是無法更改這些特性。必須在語法分析器類廠級別執行該操作。

另外,有多種方法來請求對文檔進行語法分析。除了只接受 File 和 SAX HandlerBase 實例,SAXParser 的 parse() 方法還能以 String 形式接受 SAX InputSource 、Java InputStream 或 URL,所有這些都要與 HandlerBase 實例一起提供。所以,不同類型的輸入文檔可以用不同方式的語法分析來處理。

最後,可以直接通過 SAXParser 的 getParser() 方法獲得和使用下層的 SAX 語法分析器( org.xml.sax.Parser 的實例)。獲得這個下層實例之後,就可以獲得通常的 SAX 方法。下一個清單顯示 SAXParser 類(這個 JAXP 中 SAX 語法分析的核心類)的各種使用示例。


清單 2. 使用 JAXP SAXParser

 //獲得SAXP的一個實例
 SAXParser saxParser = saxFactory.newSAXParser();

 //查看是否支持 Validate 選項
 boolean isValidating = saxParser.isValidating();

 //查看是否支持 namespace 選項
 boolean isNamespaceAware = saxParser.isNamespaceAware();

 // 運用一個File 和一個SAX HandlerBase 的實例進行多種形式的語法分析
 saxParser.parse(new File(args[0]), myHandlerBaseInstance);

 // 運用一個 SAX InputSource實例 和一個 SAX HandlerBase 實例
 saxParser.parse(mySaxInputSource, myHandlerBaseInstance);

 //運用一個 InputStream 實例和一個SAX HandlerBase 實例
 saxParser.parse(myInputStream, myHandlerBaseInstance);

 // 運用一個 URI 和一個SAX HandlerBase 實例
 saxParser.parse("http://www.newInstance.com/xml/doc.xml", myHandlerBaseInstance);

 //獲得底層的(封裝)SAX 語法分析器
 org.xml.sax.Parser parser = saxParser.getParser();

 //利用底層的語法分析器
 parser.setContentHandler(myContentHandlerInstance);
 parser.setErrorHandler(myErrorHandlerInstance);
 parser.parse(new org.xml.sax.InputSource(args[0]));

 


目前爲止,關於 SAX 已經講了很多,但是還沒有揭示任何不尋常或令人驚奇的東西。事實上,JAXP 的功能很少,特別是當 SAX 也牽涉進來時。這很好,因爲有最少的功能性意味着代碼可移植性更強,並可以由其他開發人員與任何與 SAX 兼容的 XML 語法分析器一起使用,無論是免費(通過開放源碼,希望如此)還是通過商業途徑。就是這樣。在 JAXP 中使用 SAX 沒有更多的東西。如果已經知道 SAX,那麼現在已經掌握大約 98% 的內容。只需學習兩個新類和兩個 Java 異常,您就可以開始了。如果從沒使用過 SAX,那也很簡單,現在就可以開始。

 

 


 
 

 

處理 DOM

如果要休息以迎接 DOM 挑戰,那麼先別休息。在 JAXP 中使用 DOM 的過程與 SAX 幾乎相同,所要做的全部只是更改兩個類名和一個返回類型,這樣就差不多了。如果理解 SAX 的工作原理和 DOM 是什麼,則不會有任何問題。

DOM 和 SAX 的主要差異是它們的 API 結構。SAX 包含一個基於事件的回調函數集,而 DOM 有一個內存中的樹狀結構。換句話說,在 SAX 中,從不需要操作數據結構(除非開發人員手工創建)。因此,SAX 不提供修改 XML 文檔的功能。而 DOM 正好提供這種類型的功能。 org.w3c.dom.Document 類表示 XML 文檔,它由表示元素、屬性和其它 XML 結構的 DOM 節點 組成。所以,JAXP 無需觸發 SAX 回調,它只負責從語法分析返回一個 DOM Document 對象。

DOM 語法分析器類廠一瞥

基本理解 DOM 以及 DOM 和 SAX 的差異之後,就沒什麼好說的了。以下代碼看起來與 SAX 代碼類似。首先,獲得 DocumentBuilderFactory (與 SAX 中的方式相同)。然後,配置類廠來處理確認和名稱空間(與 SAX 中的方式相同)。下一步,從類廠中檢索 DocumentBuilder (它與 SAXParser 類似)(與 SAX 中的方式相同. . . 啊,您都知道了)。然後,就可以進行語法分析了,產生的 DOM Document 對象傳遞給打印 DOM 樹的方法。


清單 3. 使用文檔構建器類廠

import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;

// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;

// DOM
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class TestDOMParsing {

 public static void main(String[] args) {
 try {
 if (args.length != 1) {
 System.err.println ("Usage: java TestDOMParsing [filename]");
 System.exit (1);
 }

 // 獲得 Document Builder Factory
 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

 //打開確認選項,關掉名稱空間敏感性選項。
 factory.setValidating(true);
 factory.setNamespaceAware(false);

 DocumentBuilder builder = factory.newDocumentBuilder();
 Document doc = builder.parse(new File(args[0]));

 // 從DOM 數中打印文檔,並加一初始空格
 printNode(doc, "");

 // 在這裏也可以對 DOM 文檔進行修改
 } catch (ParserConfigurationException e) {
 System.out.println("The underlying parser does not support the requested features.");
 } catch (FactoryConfigurationError e) {
 System.out.println("Error occurred obtaining Document Builder Factory.");
 } catch (Exception e) {
 e.printStackTrace();
 }
 }

 private static void printNode(Node node, String indent) {
 // 打印 DOM 樹
}

 


此代碼中可能會出現兩個不同的問題(與 JAXP 中的 SAX 類似): FactoryConfigurationError 和 ParserConfigurationException 。每一個的原因與 SAX 中的相同。不是實現類 ( FactoryConfigurationError ) 中有問題,就是語法分析器不支持請求的特性 ( ParserConfigurationException )。DOM 和 SAX 的唯一差異是:在 DOM 中,用 DocumentBuilderFactory 替代 SAXParserFactory ,用 DocumentBuilder 替代 SAXParser 。就這麼簡單!(可以 查看完整代碼清單 ,該清單包括用於打印 DOM 樹的方法。)

使用 DOM 語法分析器

有了 DOM 類廠之後,就可以獲得 DocumentBuilder 實例。 DocumentBuilder 實例可以使用的方法與 SAX 的非常類似。主要差異是 parse() 的變種不需要 HandlerBase 類的實例。它們返回表示語法分析之後的 XML 文檔的 DOM Document 實例。另一唯一不同之處是:爲類似於 SAX 的功能提供了兩個方法:用 SAX ErrorHandler 實現來處理語法分析時可能出現的問題的 setErrorHandler() ,和用 SAX EntityResolver 實現來處理實體解析的 setEntityResolver() 。如果不熟悉這些概念,則需要通過聯機或在我的書中學習 SAX。以下清單顯示使用這些方法的示例。


清單 4. 使用 JAXP DocumentBuilder

    //獲得一個 DocumentBuilder 實例
 DocumentBuilder builder = builderFactory.newDocumentBuilder();

 //查看是否支持 Validate 選項
 boolean isValidating = builder.isValidating();

  //查看是否支持 namespace 選項
 boolean isNamespaceAware = builder.isNamespaceAware();

 // 設置一個 SAX ErrorHandler
 builder.setErrorHandler(myErrorHandlerImpl);

 // 設置一個 SAX EntityResolver
 builder.setEntityResolver(myEntityResolverImpl);

 // 運用多種方法對 file 進行語法分析
 Document doc = builder.parse(new File(args[0]));

 // 運用 SAX InputSource
 Document doc = builder.parse(mySaxInputSource);

 // 運用 InputStream
 Document doc = builder.parse(myInputStream, myHandlerBaseInstance);

 // 運用 URI
 Document doc = builder.parse("http://www.newInstance.com/xml/doc.xml");

 


是不是感到 DOM 這一節有些令人厭煩?有這種想法的不止您一個,寫 DOM 代碼有些令人厭煩是因爲它是直接取得所學的 SAX 知識,然後將其用於 DOM。因此,和朋友、同事打賭吧,說使用 JAXP 只是小菜一碟。

 

 


 
 

 

更改語法分析器

最後要探討的主題是 JAXP 輕易更改類廠類使用的語法分析器的能力。更改 JAXP 使用的語法分析器實際意味着更改 類廠,因爲所有 SAXParser 和 DocumentBuilder 實例都來自這些類廠。既然確定裝入哪個語法分析器的是類廠,因此,必須更改類廠。可以通過設置 Java 系統屬性 javax.xml.parsers.SAXParserFactory 來更改要使用的 SAXParserFactory 接口實現。如果沒有定義該屬性,則返回缺省實現(供應商指定的任何語法分析器)。相同原理適用於 DocumentBuilderFactory 實現。在這種情況下,將查詢 javax.xml.parsers.DocumentBuilderFactory 系統屬性。就這麼簡單,我們已經學完了!這就是 SAXP 的全部:提供到 SAX 的掛鉤,提供到 DOM 的掛鉤,並允許輕易更改語法分析器。

 

 


 
 

 

結束語

如您所見,沒多少複雜的東西。更改系統屬性,通過類廠、而不是語法分析器或構建器來設置“確認”,以及弄清楚JAXP實際上不是人們通常所認爲的那樣,這些是使用 JAXP 的最困難部分。除了沒有 SAX 2.0 和 DOM第二層規範支持之外,JAXP 在兩個流行的 Java 和 XML API 之上提供一個有幫助的可插入層。它使代碼獨立於供應商,並允許不編譯語法分析代碼而更改語法分析器。那麼,從 Sun、Apache XML 或其它方便之處下載 JAXP,並使用它吧!繼續關注 JAXP 1.1,並增加對 SAX 2 和 DOM 2、XSLT 及更多內容的支持。您將在這裏獲得第一手新聞,所以,請關注 developerWorks。
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


首先簡單介紹一下Java關於xml的API,這樣大家看到了縮寫就知道是幹什麼的了。

  1,JAXP(Java API for XML Parsing)
  2,JAXB(Java API for XML Binding)
  3,JAXM(Java API for XML Messaging)
  4,JAX-RPC(Java API for XML-RPC)

  1,JAXP定義了在Java中使用DOM, SAX, XSLT的通用的接口。這樣在你的程序中你只要使用這些通用的接口,當你需要改變具體的實現時候也不需要修改代碼。比如,你用的XSLT處理器太慢了,你想換一個,你不需要修改你以前的代碼,只要修改一下JAXP的相關配置。(在後面我將詳細地介紹)作爲一個共同的接口,JAXP也有所謂的“最小公分母”效應,也就是說它支持的東西很有限。JAXP1.0支持XML1.0,XML Namespace1.0,SAX1.0以及DOM level 1。而JAXP1.1增加了對SAX2.0,DOM level 2以及XSLT1.0的支持。很明顯如果你想使用Xalan的XPath相關的接口,JAXP就沒有支持,你也只能將代碼綁定到特定的Xalan的API上了。

  這裏還要提一下JDOM,雖然它沒有實現JAXP,但是由於它使用的簡單性,還是很受歡迎,並且成爲了JCP正式推薦的API。它也是一種樹狀的結構表現XML,在使用方法上要比w3c的dom標準簡單易用的多。最新版本的JDOM在其內部已經開始使用JAXP的API,它會儘可能的去調用JAXP的API,如果不行就使用自己的默認XML解析器Xerces,XSLT處理器Xalan。

  2,JAXB定義了Java數據對象和xml結構之間的一種雙向映射關係。這樣你就可以很方便地將一個Java對象存儲爲一個xml文檔,也可以從一個xml文檔實例化一個Java對象。它的結構是這樣子的:首先要有xml的dtd以及binding schema(這個不是xml的schema,而是一個定義Java對象和xml結構之間映射關係xml文檔),通過這兩個文件JAXB就可以生成與xml文檔結構一致的Java源文件,編譯之後就可以很方便地通過具體的xml文檔得到與xml結構一致的Java類(就是生成的那些類)unmarshalling,反過來marshalling也可以。

  它的缺點也很明顯,一旦xml的結構發生了改變,就要重新寫bindng schema以及重新生成編譯Java類。

  sun的動作總是一如既往地慢,在JAXB出臺之前已經有了一些用於xml data binding的框架,我們再來看看同樣也是做xml databinding但是並沒有實現JAXB的框架:

  一,Castor

  Castor不僅僅支持對XML的綁定,它還支持對LDAP對象,用OQL將SQL查詢映射爲對象,以及對JDO的支持。與JAXB不同的是,它需要的僅僅是xml的Schema。通過xml的Schema來生成相應的Java源代碼,編譯之後就可以marshalling和unmarshalling了。

  二,Zeus

  Zeus與Castor和JAXB相比,在class generation方面多做了些步驟,因此它可以支持多種的約束關係,包括對DTD,XML Schema以及TREX等等的支持。不過目前該項目好像已經不做了。

  三,Quick

  Quick也是一個非常靈活的框架,詳細的情況可以google一下。

  3,JAXM

  JAXM是爲SOAP通信提供訪問方法和傳輸機制的API。目前它支持SOAP1.1規範以及同步和異步通信。JAXM定義了大量服務,JAXM的實現產品將會提供這些服務,使得開發者不用面對複雜的通信系統。JAXM體系結構中包括兩個重要的組件:JAXM Client和Provider。Client通常是作爲J2EE web或EJB容器的一部分,以提供你所寫的程序訪問JAXM服務的能力。而Provider可以以不同的方式實現,主要負責發送和接收SOAP消息。這樣你就可以直接地使用JAXM的API直接發送和接收SOAP消息。

 

 

4,JAX-RPC

  JAX-RPC是通過xml進行遠程過程調用的Java API。它是基於SOAP技術的,使用SOAP作爲底層的協議。這樣對於開發者來說,只有方法,參數,返回值是可見的,而底層的soap通信都被隱藏起來了,開發人員不需要與之直接打交道。

  JAXM和JAX-RPC在Web Services方面有很重要的作用。

  補充: JAXP框架查找具體實現的步驟

  JDK1.4自帶的是JAXP的參考實現:Crimson的DOM, SAX解析器,Xalan的XSLT處理器。

  如果你想用其他的實現替代它們,那就必須瞭解JAXP框架查找實現的具體步驟:

  1,首先,算法會通過諸如javax.xml.transform.TranformerFactory這樣的系統屬性來定位具體實現的類。你可以在命令行中直接指定:

  java -Djavax.xml.transform.TransformerFactory=com.foo.ConcreteTransformer YourApp

  ConcreteTransformer是實現了TransformerFactory的子類,如果你用的是ant,也可以在build file中指定。

  同樣地有,javax.xml.parsers.DocumentBuilderFactory和javax.xml.parsers.SAXBuilderFactory屬性。

  2,接着,如果系統屬性中沒有指定,JAXP將會在JRE的目錄中查找lib/jaxp.properties屬性文件,它像一般的properties文件一樣是由name=value組成的,假設有如下的一行:

  javax.xml.transform.TransformerFactory=com.foo.ConcreteTransformer

  那麼JAXP就會使用相應的TransformerFactory實現。

  在Java程序中,你可以通過如下的代碼獲得JRE所在的目錄:

  String javaHomeDir = System.getProperty("java.home");

  不過要注意,如果是在一些IDE中使用,IDE會改變這個java.home的值,比如JBuilder。

  3,如果jaxp.properties不存在或者沒有相應的值,那麼JAXP將會使用JAR文件的服務提供體制來定位正確的子類。簡單地說,你可以在jar文件的META-INF/services目錄下新建一個名爲javax.xml.transform.TransformerFactory的文件,這個文件中只有一行:com.foo.ConcreteTransformer就可以了。

  4,最後,如果上面3步都沒有找到任何具體的實現,JAXP就會使用缺省的實現:Crimson和Xalan。

 

 

 

 

 

 

 

 

 

 

 

Java XML API 漫談
轉載自forum.hibernate.org.cn, author:robbin

 

在IBM的developerWorks上有幾篇非常優秀的關於Java XML API的評測文章,它們是:

http://www-900.ibm.com/developerWorks/cn/xml/x-injava/index.shtml

http://www-900.ibm.com/developerWorks/cn/xml/x-injava2/index.shtml

http://www-900.ibm.com/developerWorks/cn/xml/x-databdopt/part2/index.shtml

http://www-900.ibm.com/developerWorks/cn/xml/x-databdopt/part1/index.shtml

對這幾篇文章我想說的就是“吐血推薦”

Java的XML API這幾篇文章該講的都講到了,我只想補充幾點:

一、Crimson和Xerces恩仇錄
Crimson來自於Sun捐贈給Apache的ProjectX項目,Xerces來自IBM捐贈給Apache的XML4J項目,結果Xerces勝出,成了Apache XML小組全力開發的XML API,而Crimon已經早就不做了,如今Xerces名滿天下,到處都是在用Xerces DOM和SAX解析器,只有Sun不服氣,非要在JDK1.4裏面使用過時的Crimson,讓人感覺像是在賭氣一樣,真是讓人可憐又可氣!不過IBM發行JDK用的XML 解析器自然是Xerces。

由於JDK的Class Loader的優先級關係,當你採用JAXP編寫XML程序的時候,即使把Xerces包引入CLASSPATH,JDK還是會頑固的使用Crimson,這一點通過打開JVM的verbose參數可以觀察到。不過JDK也允許你採用其它的解析器,因此我們可以通過在JRE/lib/目錄下建一個jaxp.properties的文件,來替換解析器,jaxp.properties內容如下:

引用:
javax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl
javax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl

這樣就可以使用Xerces,當然你必須還是要把Xerces包放到CLASSPATH下。

二、JAXP的姍姍來遲
Sun在XML領域總是後知後覺,等到Sun重視XML的時候,XML的API早就滿天 飛了,尤其是IBM具有非常大的領先優勢。不過Sun是規範的制訂者,於是參考W3C的標準制訂了JAXP規範。JAXP不像Xerces和Crimon那樣,它只是一個spec,本身是不做任何事情的,它的作用就是提出一個統一的接口,讓其它的XML API都來遵循JAXP編程,那麼用JAXP寫出來的程序,底層的API可以任意切換。

具體來說JAXP包括了幾個工廠類,這就是JDK1.4裏面的javax.xml.parsers 包,用來尋找符合DOM標準的XML API實現類的位置;此外JAXP還包括一整套interface,這就是JDK1.4裏面的org.w3c.dom那幾個包。工廠類負責加載DOM的實現類。那麼加載的規則是什麼呢?

我是通過閱讀JAXP的源代碼知道的,工廠類首先會根據java命令行傳入的參數進行尋找,然後在根據JRE/lib/jaxp.properties中定義的實現類尋找,最後什麼都找不到的話,就用Crimson。注意Crimons是由Bootstrap Class Loader來load的,如果你不通過上面兩個方法來改變工廠的尋找順序,那麼鐵定用Crimson了

三、 DOM解析器和DOM API
當你嚴格採用JAXP編程的時候,是遵循W3C的DOm標準的,那麼在JAXP底層你實際上可以任意切換不同的DOM實現,例如Xerces,或者Crimon,再或者其它,切換方法就是配置jaxp.properties。因此JAXP就是一些標準接口而已。

而Xerces和Crimon也不單單是一個DOM實現那麼簡單,他們本身實際上也包含SAX解析器和DOM解析器。所以一個JAXP程序下面有如下層次:

引用:

JAXP應用程序 -> JAXP接口 -> Xerces DOM實現 -> Xerces DOM/SAX 解析器

只要你用JAXP編程,那麼你就可以切換到Crimson上來

引用:

JAXP應用程序 -> JAXP接口 -> Crimson DOM實現 -> Crimson DOM/SAX 解析器

另外你也可以這樣來做:

引用:

JAXP應用程序 -> JAXP接口 -> Crimson DOM實現 -> Xerces DOM/SAX 解析器

不過如果你的程序不安裝JAXP來寫,那麼就沒有辦法切換不同的DOM實現了。

四、不是標準的dom4j和jdom
W3C的DOM標準API難用的讓人想撞牆,於是有一幫人開發Java專用的XML API目的是爲了便於使用,這就是jdom的由來,開發到一半的時候,另一部分人又分了出來,他們有自己的想法,於是他們就去開發dom4j,形成了今天這樣兩個API,至於他們之間的性能,功能之比較看看上面我推薦的文章就知道了,jdom全面慘敗。

jdom 相當於上面的 JAXP接口 + Xerces DOM實現部分,它本身沒有解析器,它可以使用Xerces或者Crimson的解析器,就是這樣:

引用:

jdom應用程序 -> jdom API -> Xerces/Crimson解析器

dom4j 和jdom類似,不過他自己綁定了一個叫做Alfred2的解析器,功能不是很全,但是速度很快,當沒有其它的解析器的時候,dom4j將使用Alfred2解析器,如下:

引用:

dom4j應用程序 -> dom4j API -> Xerces/Crimson解析器

或者

引用:

dom4j應用程序 -> dom4j API -> Alfred2解析器

你在SF上下載的dom4j.jar是不含 Alfred2解析器的,而dom4j-full.jar包含了 Alfred2解析器,在這種情況下,實際上你什麼也不需要,光是一個dom4j-full.jar就全部都包括了。

因此可以看出採用dom4j/jdom編寫的應用程序,已經不具備可移植性了。

五、小插曲
Sun是JAXP標準的制訂者,甚至很執著的在JDK1.4裏面綁定Crimson DOM實現和解析器,然後可笑的是,Sun自己的JAXM RI竟然不是用JAXP寫出來的,而是dom4j,制訂標準讓大家遵守,自己卻監守自盜,這未免太說不過去了吧!

BTW: Hibernate也用的是dom4j來讀取XML配置文件,如今已經越來越多的程序紛紛採用dom4j,如果你不是那麼在乎可移植性,我強烈建議你採用dom4j。
 

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