?
實戰 Groovy: 用 Groovy 生成器作標記
拋開標記語言的細節,聚焦應用程序的內容
|
|
級別: 初級
Andrew Glover
, CTO, Vanward Technologies
2005 年 4 月 12 日
Groovy 生成器讓您能夠利用諸如 Swing 這樣的框架來模擬標記語言(如 XML、HTML、Ant) 任務以及 GUI。它們對于快速原型化非常有用,并且正像 Andrew Glover 這個月在“實戰 Groovy”專欄中向您展示的那樣,當您馬上需要可消費的標記時,它們是數據綁定框架的一種便利的替代方案。
幾個月前,當我最初撰寫有關 實戰 Groovy: 用 Groovy 進行 Ant 腳本編程 的文章時,我提及了 Groovy 中的生成器 概念。在那篇文章里,我向您展示了,使用一個叫做 AntBuilder
的 Groovy 類,構建富有表現力的 Ant 構建文件是多么容易。本文中,我將深入 Groovy 生成器的世界,向您展示您還能用這些強大的類做些什么。
用生成器進行構建
Groovy 生成器讓您能夠利用諸如 Swing 這樣的框架來模擬標記語言(如 XML、HTML、Ant) 任務以及 GUI。使用生成器,您可以迅速地創建復雜的標記(如 XML),而無須理會 XML 本身。
生成器的范例非常簡單。生成器的實例的方法表示該標記(如 HTML 中的 <body>
標簽)的元素。方法的創建于閉包中的對象表示子節點(例如,<body>
標簽中所包含的 <p>
標簽)。
為了便于您查看這一過程,我將創建一個簡單的生成器,以程序方式來表示一個具有清單 1 所示結構的 XML 文檔。
|
關于本系列文章
在開發實踐中采用任何工具的關鍵是,了解何時使用這些工具,何時將其棄而不用。腳本語言可能是對工具包的一個功能強大的擴充,但是只有在正確應用于適當的環境時才是如此??傊?a >實戰 Groovy系列文章旨在展示 Groovy 的實際使用,以及何時和如何成功應用它。
|
|
清單 1. 簡單 XML 結構
<person>
<name first="Megan" last="Smith">
<age>32</age>
<gender>female</gender>
</name>
<friends>
<friend>Julie</friend>
<friend>Joe</friend>
<friend>Hannah</friend>
</friends>
</person>
|
要表示這個結構非常簡單。首先將 person
方法連接到生成器實例,現在它表示 XML 的根節點,即 <person>
。要創建子節點,我創建一個閉包并聲明一個名叫 name
的新對象(它接收 map
形式的參數。順便說一下,這些參數是元素的屬性的基礎。
接下來,在 name
對象中,將兩個附加對象連接到閉包,一個對象是 age
,另一個是 gender
,它們對應于 <name>
的類似子元素。您明白其中的訣竅了么?確實很簡單。
<friends>
元素是 <person>
的兄弟元素,于是我跳出這個閉包,聲明了一個 friends
對象,當然,還附加了一個集合了多個 friend
元素的閉包,如清單 2 所示。
清單 2. 生成器是如此的簡單
import groovy.xml.*
import java.io.*
class XMLBuilder{
static void main(args) {
writer = new StringWriter()
builder = new MarkupBuilder(writer)
friendnames = [ "Julie", "Joey", "Hannah"]
builder.person() {
name(first:"Megan", last:"Smith") {
age("33")
gender("female")
}
friends() {
for (e in friendnames) { friend(e) }
}
}
println writer.toString()
}
}
|
如您所見,這里的 Groovy 表示非常優雅,且易于映射到相應的標記表示。在底層,Groovy 顯然在處理煩人的標記元素(如 < and >),使我們可以將更多精力放在內容上,而不必過分在意結構的細節。
顯示 HTML
生成器也可以有助于構建 HTML,這在開發 Groovlet 時可以派上用場。如同小菜一碟,假設我要創建一個如清單 3 所示的 HTML 頁面。
清單 3. HTML 101
<html>
<head>
<title>Groov'n with Builders</title>
</head>
<body>
<p>Welcome to Builders 101. As you can see this Groovlet is fairly simple.</p>
</body>
</html>
|
我可以輕易地將它編碼在 Groovy 中,清單 4 所示。
清單 4. HTML in Groovy 101
import groovy.xml.*
import java.io.*
class HTMLBuilderExample{
static void main(args) {
writer = new StringWriter()
builder = new MarkupBuilder(writer)
builder.html(){
head(){
title("Groov'n with Builders"){}
}
body(){
p("Welcome to Builders 101. As you can see " +
"this Groovlet is fairly simple.")
}
}
println writer.toString()
}
|
來點有意思的,讓我們再看看用生成器建立一個成熟的 GUI 有多么容易。前面我曾提到過,Groovy 的 SwingBuilder
使它能夠以一種極為簡單的方式構造 GUI。您可以查閱清單 5 中 SwingBuilder
是如何工作的。
清單 5. Groovy 中的 GUI 生成器真的很“GROOVY”(很“棒”)
import java.awt.FlowLayout
import javax.swing.*
import groovy.swing.SwingBuilder
class SwingExample{
static void main(args) {
swinger = new SwingBuilder()
langs = ["Groovy", "Ruby", "Python", "Pnuts"]
gui = swinger.frame(title:'Swinging with Groovy!', size:[290,100]) {
panel(layout:new FlowLayout()) {
panel(layout:new FlowLayout()) {
for (lang in langs) {
checkBox(text:lang)
}
}
button(text:'Groovy Button', actionPerformed:{
swinger.optionPane(message:'Indubitably Groovy!').createDialog(null, 'Zen Message').show()
})
button(text:'Groovy Quit', actionPerformed:{ System.exit(0)})
}
}
gui.show()
}
}
|
圖 1 顯示了上面的結果,還不錯吧?
圖 1. Groovy 中神奇的 GUI 編程
可以想像,對于原型化,SwingBuilder
是一個多么強大的工具,不是么?
一些事實
這些例子雖然瑣碎,卻也有趣。我希望我能讓您明白,Groovy 的生成器可以讓您避免特定語言(如 XML)中的底層標記。顯然,有時避免 XML 或 HTML 會更好,并且,那些標記協助器(facilitator)對 Java 平臺來說并不陌生。例如,我最喜歡的 XML 協助框架是 JiBX。
使用 JiBX,您可以輕易地將 XML 結構映射到對象模型,反之亦然。綁定是個強大的范例,有不計其數的類似工具擁有此功能,如 JAXB、 Castor 和 Zeus 等。
綁定框架的惟一缺點是,它們恐怕 要耗費不少時間。幸運的是,您可以使用 Groovy 的生成器作為一個較簡單的 解決方案,這在某些情況下是有效的。
用生成器進行偽綁定
假設有一個英文詞典的簡單數據庫。有一個表用于 word
,另一個表用于 definition
,最后還有一個表用于 synonym
。圖 2 是這個數據庫的簡單表示。
圖 2. 詞典數據庫
如您所見,這個數據庫非常直觀:word
與 definition
和 synonym
具有一對多的關系。
詞典數據庫擁有一個消費者,他在尋求一種表示數據庫內容的關鍵方面的 XML 結構。所尋求的 XML 結構如清單 6 所示。
清單 6. 可采用的詞典 XML
<words>
<word spelling="glib" partofspeech="adjective">
<defintions>
<defintion>Performed with a natural, offhand ease.</defintion>
<defintion>Marked by ease and fluency of speech or writing that often suggests
or stems from insincerity, superficiality, or deceitfulness</defintion>
</defintions>
<synonyms>
<synonym spelling="artful"/>
<synonym spelling="urbane"/>
</synonyms>
</word>
</words>
|
如果選擇使用 JiBX 這樣的綁定框架來解決這個問題,則很可能需要創建一些中間對象模型,以從關系模型到達最終的 XML 模型。然后必須將數據庫內容讀取到對象模型中,并請求底層框架將其內部的結構編組為 XML 格式。
這一過程內含了將對象結構映射到 XML 格式的步驟(使用所需的框架過程)。某些框架,如 JAXB,實際上是從 XML 和其他框架(如 JiBX )生成 Java 對象,允許您自定義自己的 Java 對象到 XML 格式的映射。總之,這都需要大量的工作。
并且,這是一項宏偉的計劃。我并不提倡避免使用綁定框架。這里,我要聲明:我已經預先警告過您。我計劃向您展示的是一個生成 XML 的便捷方式。
可消費的 XML 很簡單
使用 Groovy 的 MarkupBuilder
,結合新的數據庫訪問框架 GroovySql,您可以輕易地生成可消費的 XML。您所要做的只是計算出所需的查詢,并將結果映射到生成器實例 —— 然后,您馬上就可以得到表示詞典數據庫內容的 XML 文檔。
讓我們逐步來了解這一過程。首先,創建一個生成器實例,在本例中是 MarkupBuilder
,因為您想要生成 XML。最外面的 XML 元素(也就是“根”)是 words
,這樣就創建了一個 words
方法。在閉包里,調用第一個查詢,并在迭代中將查詢結果映射到 word
子節點。
接著,通過兩個新的查詢,創建 word
的兩個子節點。創建一個 definitions
對象,并在迭代中映射它,接著用同樣的方法處理 synonyms
。
清單 7. 用生成器集合所有元素
import groovy.sql.Sql
import groovy.xml.MarkupBuilder
import java.io.File
import java.io.StringWriter
class WordsDbReader{
static void main(args) {
sql = Sql.newInstance("jdbc:mysql://localhost/words",
"words", "words", "org.gjt.mm.mysql.Driver")
writer = new StringWriter()
builder = new MarkupBuilder(writer)
builder.words() {
sql.eachRow("select word_id, spelling, part_of_speech from word"){ row |
builder.word(spelling:row.spelling, partofspeech:row.part_of_speech){
builder.definitions(){
sql.eachRow("select definition from definition where word_id = ${row.word_id}"){ defrow |
builder.definition(defrow.definition)
}
}
builder.synonyms(){
sql.eachRow("select spelling from synonym where word_id = ${row.word_id}"){ synrow |
builder.synonym(synrow.spelling)
}
}
}
}
}
new File("dbouuput.xml").withPrintWriter{ pwriter |
pwriter.println writer.toString()
}
}
}
|
結束語
這里,我向您展示的綁定解決方案似乎簡單得讓人難以置信,特別是以 Java 純化論者的觀點看來更是如此。盡管該解決方案不比使用綁定框架(如 JABX 和 JiBX) 更好,但它確實更快一些 —— 而且,我主張使用這樣較簡單的方法。是不是我在簡單的 Java 代碼中做一些類似的事情?是的,但我敢肯定,某些時候我也不得不處理 XML。
用 Groovy 生成器進行開發的速度和簡易性,在調用標記的時候可大顯神威。例如,就像在第二個例子里展示的那樣,我可以馬上加快數據庫的 XML 表示。對于原型化,或者當需要以最少的開發時間和精力來產生可工作的解決方案時,生成器也是一個不錯的選擇。
在下個月的實戰 Groovy 中我會講些什么呢?哦,當然是在 Java 語言中使用 Groovy!
參考資料
關于作者