本文示例源代碼或素材下載
您現在應該具備的(回顧)
與前一篇文章一樣,本文也對您系統的設置情況和您的技能做一些假設。首先,需要按照本系列的第 1 部分中的描述下載並安裝 Castor 的最新版本,設置類路徑和相關的 Java 庫(參見 參考資料 中本系列第一篇文章的鏈接)。然後,按照第 2 部分中的描述,熟悉 Castor 的基本編組和解組設施。
所以,您應該能夠使用 Castor 提取出 XML 文檔中的數據,並使用自己的 Java 類處理數據。用數據綁定術語來說,這稱為解組(unmarshalling)。反向的過程稱為編組(marshalling):您應該能夠把 Java 類的成員變量中存儲的數據轉換為 XML 文檔。如果您還不熟悉 Castor 的解組器和編組器,那麼應該閱讀 第 2 部分(參見 參考資料 中的鏈接)。
非理想環境下的數據綁定
初看上去,您似乎已經掌握了有效地使用 Castor 所需了解的所有過程:設置、編組和解組。但是,您到目前為止學到的所有東西只適用於所謂的理想環境。在這樣的環境中,每個人編寫的 XML 都是完美的,其中的元素名是有意義的,比如 “title” 和 “authorAddress”,而不是 “t” 或 “aa”。Java 類是按照有組織的方式創建的,采用單數作為類名(比如 “Book”),采用單數名詞作為成員變量名(比如 “isbn” 和 “price”)。另外,數據類型也是正確的:沒有開發人員把 price 的數據類型設置為 int 而不是 float,或者使用 char 數組存儲字符串數據(這是 C 語言的做法)。
但是,大多數程序員所處的環境並不完美(我真想找到一個能夠把我送到完美世界的魔法衣廚)。在大多數程序員所處的環境中有許多不理想的情況:XML 文檔常常有糟糕的元素名和屬性名,還要應付名稱空間問題。元素數據存儲在屬性中,一些數據甚至由管道符或分號分隔。
Java 類是繼承的,對它們進行重新組織在時間和工作量方面的成本可能會超過帶來的好處。這些類常常無法簡潔地映射到 XML 模式(認為 XML 和數據人員會與 Java 程序員相互妥協的想法也是非常不可思議的),而且在某些情況下,即使實現了簡潔映射,也肯定不會跨所有類和數據。XML 元素名可能不合適,許多 Java 變量名也可能不合適。甚至可能遇到使用 Hungarian 表示法的名稱,按照這種表示法,所有成員變量都以 “m” 開頭,比如 mTitle。這很不好看。
在這些情況下,您目前學到的數據綁定方法就無能為力了。XML 文檔中可能會出現 Hungarian 風格的元素名,Java 類中也可能出現沒有意義的結構。這種情況是無法接受的。如果不能按照您希望的方式獲取和操作 XML 文檔的數據,那麼 Castor(或任何數據綁定框架)又有什麼意義呢?
靈活數據綁定的目標
首先要注意,在 Castor 或任何其他數據綁定框架中,使用映射文件都要花一些時間。必須先學習一些新語法。盡管映射文件使用 XML 格式(大多數框架都是這樣的),但是您需要學習一些新元素和屬性。還必須做一些測試,確保 XML 和 Java 代碼之間的相互轉換產生您希望的結果。最後,如果親自指定映射,而不是讓框架處理映射,就可能在數據綁定中遇到更多的錯誤。例如,如果希望讓框架把 XML 中的 fiddler 元素映射到 Java 代碼中的 violin 屬性,但是錯誤地聲明這個屬性是在 player 類中(應該是在 Player 類中),那麼就會遇到錯誤。因此,在親自指定映射時,必須非常注意拼寫、大小寫、下劃線、單引號和雙引號。
在學習使用映射文件之前,應該確定確實需要這麼做。如果掌握了映射文件,但是卻不使用它,那就是浪費時間。但是,映射確實有一些優點。
Java 代碼不再受 XML 命名方式的限制
前面曾經提到,在把 XML 轉換為 Java 代碼時,大小寫可能會導致錯誤。在 XML 中,最常用的做法是名稱全部小寫並加連字符,比如 first-name。有時候,甚至會看到 first_name。這樣的名稱會轉換為很難看的 Java 屬性名;沒人願意在代碼中調用 getFirst-name()。實際上,在大多數由程序員(而不是 XML 開發人員或數據管理員)編寫的文檔中,往往使用駝峰式(camel-case)命名法,比如 firstName。通過使用映射文件,很容易把 XML 風格的名稱(比如 first-name)映射為 Java 風格的名稱(比如 firstName)。最棒的一點是,不需要強迫 XML 人員像 Java 程序員那樣思考,這往往比學習新的映射語法困難得多。
XML 不再受 Java 命名方式的限制
是的,這似乎很明顯。既然可以調整 XML 到 Java 的命名轉換,反過來肯定也可以:在把 Java 類和屬性包含的數據轉換為 XML 時,可以修改 Java 名稱。但是,有一個更重要,也更微妙的好處:不再受到 Java 類名和包名的限制。
這很可能成為一個組織問題。例如,在大多數情況下,XML 中的嵌套元素轉換為類結構,最內層的嵌套元素轉換成類屬性(成員變量)。看一下清單 1 中的 XML:
清單 1. 代表圖書的 XML
<?XML version="1.0" encoding="UTF-8"?>
<book>
<authors total-sales="0">
<last-name>Finder</last-name>
<first-name>Joseph</first-name>
</authors>
<isbn>9780312347482</isbn>
<title>Power Play</title>
</book>
Castor(或任何其他數據綁定框架)可能假設您需要一個 Book 類,這個類引用幾個 Author 類實例。author 類應該有成員變量 lastName 和 firstName(這裡會出現前面提到的命名問題,Author 中的成員變量應該是 last-name,還是 lastName?對於名字也有這個問題)。但是,如果這不是您希望的結果,應該怎麼辦?例如,您可能在一個稱為 Person 或 Professional 的類中存儲所有作家、會議演講人和教授。在這種情況下就真有麻煩了,而且您不會願意全面修改 XML 元素的結構和名稱來解決這個問題。實際上,在這種情況下,要想原樣保持 XML,使用映射是惟一的辦法。
映射允許我們在 Java-XML 轉換的兩端指定命名方式。我們不希望由於 XML 文檔的原因修改 Java 代碼,同樣不願意修改 XML 結構來適應 Java 類和成員變量。另外,Java 包也會增加復雜性。盡管在 Castor 中包並不是大問題,但是仍然必須在編組的 XML 中存儲 Java 類和包的相關信息,這對於業務邏輯(Java 類)和數據(XML)的隔離很不利。映射可以解決所有這些問題。
映射允許在現有環境中添加數據綁定
前兩個問題(對 XML 和 Java 代碼的限制)實際上與一個更大的問題相關。大多數情況下,您已經有了一組 Java 對象和一個或多個 XML 文檔。因此,不具備前兩篇文章中的那種自由度:不能讓 Castor 根據它自己的規則把 Java 代碼解組為 XML,或者為 XML 文檔生成 Java 類。
相反,更為常見的情況是,您需要把一種新技術 — 數據綁定 — 添加到現有的結構中。在這種情況下,映射文件就是使用數據綁定的關鍵。在兩個 “端點”(當前的對象模型和當前的 XML 結構)固定的情況下,映射使我們仍然能夠把這兩者的數據聯系起來。簡而言之,良好的映射系統使數據綁定能夠在真實環境中發揮作用,而不僅僅停留在理論上。
一個映射場景示例
我們先來看一個簡單的映射場景。在前一篇文章中,我們開發了 Book 和 Author 類。清單 2 是 Book 類。
清單 2. Book 類
package ibm.XML.castor;
import Java.util.LinkedList;
import Java.util.List;
public class Book {
/** The book's ISBN */
private String isbn;
/** The book's title */
private String title;
/** The authors' names */
private List<Author> authors;
public Book() { }
public Book(String isbn, String title, List<Author> authors) {
this.isbn = isbn;
this.title = title;
this.authors = authors;
}
public Book(String isbn, String title, Author author) {
this.isbn = isbn;
this.title = title;
this.authors = new LinkedList<Author>();
authors.add(author);
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getIsbn() {
return isbn;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setAuthors(List<Author> authors) {
this.authors = authors;
}
public List<Author> getAuthors() {
return authors;
}
public void addAuthor(Author author) {
authors.add(author);
}
}
清單 3 是 Author 類。
清單 3. Author 類
package ibm.XML.castor;
public class Author {
private String firstName, lastName;
public Author() { }
public Author(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
注意:與前一篇文章相比,惟一的修改是在 Author 中刪除了總銷售額(totalSales 變量)。我發現它的意義不大,所以在這個版本中刪除了它。
一個比較麻煩的 XML 文檔
這一次不使用前一篇文章中的 XML,而是使用一個不太容易映射的 XML 文檔。清單 4 給出希望綁定到 清單 2 和 清單 3 中的 Java 類的 XML 文檔。
清單 4. 用於數據綁定的 XML
<?XML version="1.0" encoding="UTF-8"?>
<book>
<author>
<name first="Douglas" last="Preston" />
</author>
<author>
<name first="Lincoln" last="Child" />
</author>
<book-info>
<isbn>9780446618502</isbn>
<title>The Book of the Dead</title>
</book-info>
</book>
需要映射哪些數據?
在處理映射文件語法或 Castor 的 API 之前,第一個任務是判斷需要把 XML(清單 4)中的哪些數據綁定到 Java 類(清單 2 和 清單 3)。請考慮一會兒。
下面簡要總結一下這個 XML 文檔應該如何映射到 Java 類:
book 元素應該映射到 Book 類的一個實例。
每個 author 元素應該映射到 Author 類的一個實例。
每個 Author 實例應該添加到 Book 實例中的 authors 列表中。
對於每個 Author 實例,firstName 應該設置為 name 元素上的 first 屬性的值。
對於每個 Author 實例,lastName 應該設置為 name 元素上的 last 屬性的值。
Book 實例的 ISBN 應該設置為 book-info 元素中嵌套的 isbn 元素的值。
Book 實例的書名應該設置為 book-info 元素中嵌套的 title 元素的值。
其中一些映射您已經知道如何實現了。例如,book 到 Book 類實例的映射是標准的,Castor 會默認處理這個任務。但是,也有一些新東西,比如說作者。盡管把一個 author 元素映射到一個 Author 實例沒什麼問題,但是沒有分組元素,比如 authors,它清楚地顯示出所有作者屬於 Book 實例中的一個集合。
這裡還有一些元素和屬性並不直接映射到 Java 對象模型。Author 類包含表示名字和 姓氏的變量,但是在 XML 中只用一個元素(name)表示作者姓名,這個元素有兩個屬性。book-info 元素中嵌套的書名和 ISBN 並不映射到任何 Java 對象。
這種情況非常適合使用映射文件。它使我們能夠使用這種 XML(包含我們需要的數據,但是結構不符合希望),仍然能夠把文檔中的數據放到 Java 對象中。而且,映射文件本身並不難編寫。
基本的映射文件
Castor 中的映射是通過使用映射文件(mapping file) 實現的。映射文件僅僅是一個 XML 文檔,它提供了如何在 Java 代碼和 XML 之間進行轉換的相關信息。因為您熟悉 XML,所以您會發現編寫映射文件是非常容易的。實際上,對於簡單的映射(只需修改元素名和 Java 類或成員變量的名稱),只需一點兒時間就能編寫好映射文件。
然後,當進行編組和解組時(前兩篇文章已經介紹過如何在程序中進行編組和解組),Castor 會使用這個文件。只需對 Castor 多做一個 API 調用;其他代碼都是一樣的。
mapping 元素
Castor 映射文件的開始是一個普通的 XML 文檔,然後是根元素 mapping。還可以引用 Castor 映射 DTD。這樣就可以檢驗文檔,確保結構和語法沒有任何問題。這會大大簡化對映射的調試。
清單 5 給出最基本的映射文件。
清單 5. 基本的 Castor 映射文件
<?XML version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<!-- All your mappings go here -->
</mapping>
這個文件顯然沒有實質性內容,但它是所有映射文件的起點。
用 class 元素對類進行映射
建立基本的映射文件之後,差不多總是先要把一個 Java 類映射到一個 XML 元素。在這個示例中,需要把 Book 類映射到 book 元素中的數據。映射文件首先考慮類,所以需要添加一個 class 元素,並在這個元素的 name 屬性中指定完全限定的 Java 類名,比如:
<?XML version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.XML.castor.Book">
</class>
</mapping>
現在,可以使用 map-to 元素和 xml 屬性指定這個類要映射到的 XML 元素。這個元素嵌套在 XML 元素映射到的 Java 類(完全限定,包括包名)的 class 元素中,比如:
<?XML version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.XML.castor.Book">
<map-to XML="book" />
</class>
</mapping>
這非常簡單。實際上,到目前為止,這個映射文件只實現 Castor 的默認操作。除非由於以下兩個原因,否則可以刪除這個部分並讓 Castor 處理這個任務:
需要指定如何填充 Book 中的某些字段,比如書名和 ISBN。
如果使用映射文件,那麼最好指定所有內容 的映射方式。這會更明確 XML 和 Java 代碼之間的配合。
把字段映射到元素
有了基本的類到元素的映射之後,就可以開始把 Book 類的字段映射到 XML 文檔中的特定元素。Castor 映射文件使用 fIEld 元素指定要使用的 Java 成員變量,使用其中嵌套的 bind-xml 元素指定映射到的 XML 元素。因此,下面的代碼指定把 Book 類中的 title 變量映射到 book 元素中嵌套的 title 元素:
<?XML version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.XML.castor.Book">
<map-to XML="book" />
<fIEld name="Title" type="Java.lang.String">
<bind-XML name="title" node="element" />
</fIEld>
</class>
</mapping>
在這裡要注意兩點。首先,提供了屬性名(在這個示例中是 “title”)。這是屬性(property) 名,而不是成員變量名。換句話說,Castor 通過調用 set[PropertyName]() 來使用這個屬性名。如果提供屬性名 “foo”,Castor 就會嘗試調用 setfoo() — 這可能不是您希望的情況。因此,要仔細注意大小寫,並使用屬性 名而不是 Java 類中的變量名。
要注意的第二點是 type 屬性。這個屬性向 Castor 說明數據究竟是什麼類型的。在這個示例中,這很簡單;但是在某些情況下,希望將以 XML 文本式數據存儲的數字存儲為整數、小數或者只是字符串,這時指定正確的數據類型就很重要了。另外,類型應該使用完全限定的 Java 類名,比如 Java.lang.String。
在 bind-xml 元素中,指定要綁定到的 XML 元素的名稱(在這個示例中是 “title”),並使用 node 屬性指定是綁定到元素還是綁定到屬性。這樣就可以輕松地使用元素和屬性數據,只需在映射文件中稍做修改即可。
指定 XML 元素的位置
但是,這裡需要解決一個問題:書名和 ISBN 嵌套在 book-info 元素中,而不是直接嵌套在 book 元素中。所以需要在映射文件中指出這一情況。
當遇到這種情況時 — 一個類中的一個字段並不直接映射到與這個類對應的 XML 元素中的數據 — 就需要在 bind-xml 元素中使用 location 屬性。這個屬性的值應該是 XML 文檔中包含您希望綁定到的數據的元素。如果綁定到元素數據,它就應該是目標元素的父 元素;如果綁定到屬性數據,它就應該是包含這個屬性的 元素。
因此,在這個示例中,希望把 Book 類的書名屬性綁定到 title 元素的值,而這個元素嵌套在 book-info 元素中。下面是映射方法:
<?XML version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.XML.castor.Book">
<map-to XML="book" />
<fIEld name="Title" type="Java.lang.String">
<bind-XML name="title" node="element" location="book-info"
</fIEld>
</class>
</mapping>
然後為書的 ISBN 添加另一個字段映射:
<?XML version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.XML.castor.Book">
<map-to XML="book" />
<fIEld name="Title" type="Java.lang.String">
<bind-XML name="title" node="element" location="book-info" />
</fIEld>
<fIEld name="Isbn" type="Java.lang.String">
<bind-XML name="isbn" node="element" location="book-info" />
</fIEld>
</class>
</mapping>
現在,Book 類的屬性都已經設置好了。該處理 Author 類了。
對其他類進行映射
按照相同的方式對其他類進行映射。惟一的差異是在其他類中不需要使用 map-to 元素。
對 Author 類進行映射
需要把 Author 類中的字段映射到 author 元素。請記住,下面是要處理的 XML 片段:
<author>
<name first="Lincoln" last="Child" />
</author>
惟一需要注意的是,這裡並不用兩個元素分別包含名字和姓氏,而是使用一個帶兩個屬性的元素。但是,前面已經使用過 location 屬性(需要用這個屬性指定 name 元素是映射到的位置)和 node 屬性(可以在這裡指定要綁定到屬性數據,而不是元素)。所以在映射文件中需要以下代碼:
<?XML version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.XML.castor.Book">
<map-to XML="book" />
<fIEld name="Title" type="Java.lang.String">
<bind-XML name="title" node="element" location="book-info" />
</fIEld>
<fIEld name="Isbn" type="Java.lang.String">
<bind-XML name="isbn" node="element" location="book-info" />
</fIEld>
</class>
<class name="ibm.XML.castor.Author">
<fIEld name="FirstName" type="Java.lang.String">
<bind-XML name="first" node="attribute" location="name" />
</fIEld>
<fIEld name="LastName" type="Java.lang.String">
<bind-XML name="last" node="attribute" location="name" />
</fIEld>
</class>
</mapping>
現在,您應該很容易看懂這些代碼。這裡指定了映射到的類(Author)和這個類上要映射的屬性(FirstName 和 LastName)。對於每個屬性,指定要查看的 XML 元素(都是 name)並指定需要的是屬性數據。
把 Book 和 Author 類鏈接起來
如果看一下 上面 的 XML,就會注意到並沒有指定 Author 類應該映射到哪個 XML 元素。這是一個問題,因為 Castor 不會猜測您的意圖;只要使用映射文件,最好指定所有映射信息。
如果每本書只有一位作者,那麼在 Book 類中可能有一個 Author 屬性。在這種情況下,可以在映射文件中插入以下代碼:
<?XML version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.XML.castor.Book">
<map-to XML="book" />
<fIEld name="Title" type="Java.lang.String">
<bind-XML name="title" node="element" location="book-info" />
</fIEld>
<fIEld name="Isbn" type="Java.lang.String">
<bind-XML name="isbn" node="element" location="book-info" />
</fIEld>
<fIEld name="Author" type="ibm.XML.castor.Author">
<bind-XML name="author" />
</fIEld>
</class>
<class name="ibm.XML.castor.Author">
<fIEld name="FirstName" type="Java.lang.String">
<bind-XML name="first" node="attribute" location="name" />
</fIEld>
<fIEld name="LastName" type="Java.lang.String">
<bind-XML name="last" node="attribute" location="name" />
</fIEld>
</class>
</mapping>
在這種情況下,把這一映射放在映射文件的圖書部分中,因為映射的是屬於 Book 類的一個屬性。映射的類型指定為 ibm.xml.castor.Author,並指定 XML 元素 author。這樣的話,Castor 的映射系統就會使用 class 元素中的 Author 類的定義處理作者的屬性。
但是,問題在於 Book 類中沒有 Author 屬性。相反,這個類中有一個 Authors 屬性,其中包含 Author 實例的集合。因此,必須讓 Castor 把每個 author 元素映射到一個 Author 實例(這一步差不多已經完成了),然後把所有實例組合成 Book 的 Authors 屬性。
把元素映射到集合
為了映射圖書和作者的關系,需要把幾個元素(XML 文檔中的每個 author)映射到一個集合,然後把這個集合分配給 Book 的 Authors 屬性。
首先使用 fIEld 元素,因為確實要映射到 Book 的一個字段。還要把 name 屬性的值指定為 “Authors”,因為這是 Book 中將映射到的屬性:
<fIEld name="Authors">
</fIEld>
接下來,需要提供屬性的類型。您可能認為這應該是集合類型。但是,實際上希望指定集合中每個成員的類型。所以類型應該是 ibm.xml.castor.Author。您將會獲得 ibm.XML.castor.Author 類的實例,Castor 將把這些實例放到 Authors 屬性中:
<fIEld name="Authors" type="ibm.XML.castor.Author">
</fIEld>
下面是關鍵之處:使用 collection 屬性指定這個屬性是一個集合。這個屬性的值是集合的類型。Castor 當前只支持兩個值:vector(代表列表類型)和 array(代表數組類型)。通過標准的 Java 集合 API(比如 next() 等調用)訪問第一種集合;管理第二種集合的方法與 Java 數組相似,按照索引來訪問它們,比如 ar[2]。在這個示例中,因為 Java 類型是 List,所以使用 vector:
<fIEld name="Authors" type="ibm.XML.castor.Author" collection="vector">
</fIEld>
如果指定了 collection 屬性,Castor 就知道應該用與 type 屬性對應的值構建這個集合。因此,這裡的 Authors 屬性應該是 ibm.XML.castor.Author 類型的實例的集合。
現在只剩下一步了:指定獲取這些 Author 實例的來源。這要使用 bind-XML 元素:
<fIEld name="Authors" type="ibm.XML.castor.Author" collection="vector">
<bind-XML name="author" />
</fIEld>
所有工作都完成了;現在形成了一個完整的映射文件。最終的文件應該像清單 6 這樣。
清單 6. 完整的映射文件
<?XML version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="ibm.XML.castor.Book">
<map-to XML="book" />
<fIEld name="Title" type="Java.lang.String">
<bind-XML name="title" node="element" location="book-info" />
</fIEld>
<fIEld name="Isbn" type="Java.lang.String">
<bind-XML name="isbn" node="element" location="book-info" />
</fIEld>
<fIEld name="Authors" type="ibm.XML.castor.Author" collection="vector">
<bind-XML name="author" />
</fIEld>
</class>
<class name="ibm.XML.castor.Author">
<fIEld name="FirstName" type="Java.lang.String">
<bind-XML name="first" node="attribute" location="name" />
</fIEld>
<fIEld name="LastName" type="Java.lang.String">
<bind-XML name="last" node="attribute" location="name" />
</fIEld>
</class>
</mapping>
在程序中使用映射文件
最後,需要在解組過程中使用這個映射文件。以前,我們靜態地使用 Unmarshaller 類,通過調用 Unmarshaller.unmarshal() 把 XML 轉換為 Java 代碼。但是,因為現在要使用映射文件,所以需要創建一個 Unmarshaller 實例並設置一些選項。清單 7 給出的類處理從 XML 文檔到 Java 對象的解組過程。
清單 7. 用映射文件進行解組
package ibm.XML.castor;
import Java.io.FileReader;
import Java.util.Iterator;
import Java.util.List;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.XML.Unmarshaller;
public class BookMapUnmarshaller {
public static void main(String[] args) {
Mapping mapping = new Mapping();
try {
mapping.loadMapping("book-mapping.XML");
FileReader reader = new FileReader("book.XML");
Unmarshaller unmarshaller = new Unmarshaller(Book.class);
unmarshaller.setMapping(mapping);
Book book = (Book)unmarshaller.unmarshal(reader);
System.out.println("Book ISBN: " + book.getIsbn());
System.out.println("Book Title: " + book.getTitle());
List authors = book.getAuthors();
for (Iterator i = authors.iterator(); i.hasNext(); ) {
Author author = (Author)i.next();
System.out.println("Author: " + author.getFirstName() + " " +
author.getLastName());
}
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace(System.err);
}
}
}
與前兩篇文章中的解組器相比,這裡的更改非常少。首先,創建一個 Unmarshaller 實例,使用的參數是 Book.class。這告訴解組器要解組的頂級類是哪個類。注意,這個頂級 Java 類對應於使用 map-to 元素的 mapping 元素。然後設置映射,最後調用 unmarshal() 的非靜態版本。
現在完成了!這個過程與以前的過程差異並不大。作為練習,您可以自己試著編寫把 Java 代碼編組為 XML 的代碼。請參考前一篇文章中的 BookMarshaller 類並設置映射文件,然後嘗試在 XML 和 Java 代碼之間來回轉換。
結束語
數據綁定最終關注的是數據,而不是存儲數據的格式。對於大多數 Java 程序員來說,處理 Java 對象是很容易的,而通過數據綁定,能夠同樣輕松地把來自各種來源(尤其是 XML)的數據轉換為 Java 對象。另外,數據綁定環境中的映射甚至更進了一步:在填充 Java 對象時,可以非常靈活地處理數據源格式。因此,如果您喜歡數據綁定,那麼一定也會喜歡映射;它使您能夠綁定那些與您需要的命名約定不太相符的 XML 文檔,也能夠使用與您的 Java 對象不相符的結構。
對於數據人員,映射會帶來同樣的好處。當調用 Java 方法並保存在命名古怪的 XML 風格的變量中,或者 XML 文檔中有多個元素全部映射到同一個類,那麼不需要構建中間層就可以從 Java 類中取得所需的數據。最重要的是靈活性,能夠對數據做您 想做的事情,而不受框架或工具的限制。
後續內容
您已經看到了 Castor 在 XML 環境中提供了什麼。但是,這僅僅觸及到了 Castor 的皮毛。在下一篇文章中,將進一步擴展簡單的 XML 數據綁定並研究 Castor 的 SQL 數據綁定設施。我們將把數據從 Java 類轉移到 SQL 數據庫中,再轉移回來,而且不需要使用 JDBC。請復習一下 XML 和 SQL 知識,下個月我們將進一步體驗數據綁定的威力。
學完下一篇文章(本系列的最後一篇)之後,您就能夠用相同的 API 在 XML、Java 和 SQL 數據庫之間進行轉換。這甚至會帶來比映射文件更大的靈活性。對於所有數據存儲格式,可以使用單一 API 和相似的調用處理數據庫、Java 對象和 XML 文檔。實際上,對於那些了解 C# 的程序員來說,這聽起來非常 像 LINQ(LINQ 是 Visual C# 2008 中最新最熱門的技術之一)。相似的功能已經用 Java 技術實現了,而且具有一個穩定的 API。很棒,不是嗎?所以請繼續研究 Castor,綁定數據,試試您能實現哪些功能。享受創造的樂趣吧!我們網上相見。