自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

用XSL轉(zhuǎn)換增強Ant的功能

開發(fā)
Ant是用于創(chuàng)建程序構(gòu)建過程腳本的工具,功能非常強大。Ant 與 XSLT 結(jié)合后,其功能與靈活性將會急劇增強。在本文中,作者根據(jù)他以前的經(jīng)歷,用真實的例子闡明了這一概念。

我在過去的幾年中領(lǐng)導(dǎo)過一個程序構(gòu)建小組,在這段時間內(nèi)我親眼目睹,軟件從概念到代碼再到用戶的方式,已經(jīng)發(fā)生了相當(dāng)多的變化。特別需要指出一點,用于管理大規(guī)模軟件開發(fā)項目的構(gòu)建活動的工具和技術(shù),已經(jīng)發(fā)生了非常大的變化。

在20世紀(jì)90年代中期,大多數(shù)源代碼都是用 C 或是 C++ 編寫的。要描述并管理代碼的編譯過程,可供選擇的工具就是 make , 再加上零星幾個批處理文件或是 shell 腳本以增加自動化程度,您的構(gòu)建過程也就這樣了。

現(xiàn)在時代已經(jīng)變了。出現(xiàn)了 Java 技術(shù)、XML、XSLT、極限編程與持續(xù)構(gòu)建、還有很多其他的新技術(shù)新思想。到90年代后期,情況出現(xiàn)了很大的變化。在程序構(gòu)建工具集中,最大的變化也許就是增加了 Ant。

Ant 是一種基于 Java 的程序構(gòu)建工具。它來自 Apache Software Foundation 的 Jakarta 項目,已經(jīng)成為構(gòu)建 Java 項目的事實標(biāo)準(zhǔn)。Ant 腳本的結(jié)構(gòu),以及它的很多易用特性,都源于 XML。同時,因為 Ant 腳本用 XML 表示,所以可以對其進行解析、修改、生成,或是用可擴展樣式表語言轉(zhuǎn)換(eXtensible Stylesheet Language Transformations,XSLT)進行程序轉(zhuǎn)換。您甚至可以從一個 Ant 任務(wù)內(nèi)部調(diào)用樣式表處理器(查閱 參考資料中有關(guān) Ant 樣式任務(wù)的描述)。

兩個人才能跳出優(yōu)美的探戈!

現(xiàn)在我們要考慮 Ant 與 XSLT 結(jié)合的情況。本文剩余部分將著眼于三個實例,每一個都闡述了我在工作中遇到的某個問題。在每一個例子中,我描述的解決方案的基本思路都是將一個基本的 Ant 腳本與一個或者多個 XSL 樣式表相結(jié)合。XSLT 使得原本是靜態(tài)的腳本變得靈活。請根據(jù)您的經(jīng)驗考慮一下 Ant 在這些情況下的用法:

◆ 如何簡化腳本的維護過程

◆ 如何根據(jù) XML 元數(shù)據(jù)創(chuàng)建復(fù)雜的腳本

◆ 如何實現(xiàn)腳本瀏覽器

問題的價值體現(xiàn)在解決方法中。您也許會覺得每個特定的例子對您都沒有什么用處,但是我相信您可以找到自己的辦法,用這樣一種簡單的技術(shù)使您的構(gòu)建過程充滿活力。

通過實例學(xué)習(xí)

在我們開始之前,我想確認一下您是否理解一些基本概念。我提供的每一個解決方案都要求進行一次 XSL 轉(zhuǎn)換。圖 1 描述了 XSLT 工作的一般方式。在本文的場景中,source document(源文檔)通常是一個 Ant 腳本,但是有時候可能是另一個 XML 數(shù)據(jù)文件。transformation process(轉(zhuǎn)換過程)將 stylesheet(樣式表)中的規(guī)則應(yīng)用到源文件上,并生成 result document(結(jié)果文檔)。

 
圖 1. XSLT 過程概覽

例 1: 用樣式構(gòu)建程序

前面提到過,我在一個程序構(gòu)建小組中工作了若干年。我的團隊與許多不同的開發(fā)組織接觸,支持他們進行程序構(gòu)建。我曾經(jīng)同時支持過多達 17 種不同的產(chǎn)品,并為一個不斷變化的軟件提供將近50個發(fā)布版本。

我們所面臨的挑戰(zhàn)之一就是對如此之多的活動及其多樣性進行管理。通常情況下,開發(fā)團隊的共性很少,相互之間也沒有交互。因此標(biāo)準(zhǔn)化就成為解決問題的關(guān)鍵。從抽象的層次來看,我們的構(gòu)建過程在每一次發(fā)布時都是相同的:

◆ 定義您計劃構(gòu)建的內(nèi)容;

◆ 將源代碼提取到用于構(gòu)建的計算機上;

◆ 運行編譯和打包的子過程;

◆ 發(fā)布構(gòu)建結(jié)果;

◆ 通知大家構(gòu)建已經(jīng)就緒。

我們原先打算開發(fā)通用的腳本,即便不是全都一樣,至少也要遵從所有的要點。由于有這么多不同的設(shè)計,問題也層出不窮。一段時間以后,這些腳本如果不嚴(yán)加看管,就開始向不同的方向漫開了。每一個腳本都變得更加特殊。而一般的維護過程要花費大量的人力、時間和協(xié)調(diào)工作。

#p#

解決方案

最近,我們決定重新制作腳本,要鞏固 Ant 作為主要腳本工具的地位。我們首先對一個缺省的構(gòu)建過程達成一致,此后,對前面列出的這些一般性任務(wù)進行精煉,劃分成更小的步驟,每一個步驟都表示一個工作單元,對多個構(gòu)建過程而言,工作單元可能是通用的。對于這個精煉過的過程來說,每一個步驟都實現(xiàn)成一個或者多個 Ant 目標(biāo),每一個目標(biāo)都具有缺省的行為,適應(yīng)于大多數(shù)情況。在側(cè)欄“構(gòu)建腳本的要點”中,我們給出了實際的操作順序,其中每個步驟都是用 Ant 目標(biāo)名表示的。

這些要點對于每一個構(gòu)建過程都是適用的,但是對于某個特定的步驟,缺省的的行為可能并不適用。這也就是 XSLT 可以增強靈活性的地方。如果不具備對缺省腳本進行轉(zhuǎn)換的能力,我們可能還是得為幾乎相同的腳本維護多份拷貝。最好變成每一次構(gòu)建過程都實現(xiàn)一個局部的腳本,其中包含的步驟只對這個過程有效。我們設(shè)計了一個前端過程(也是一個 Ant 腳本),它運行樣式表,將輸入文檔轉(zhuǎn)換成 Ant 的 build 文件。如果在這個局部腳本中沒有涉及那些步驟,那些步驟就使用缺省的定義。

這個過程可以用下面的公式來表示:

局部目標(biāo) + 缺省目標(biāo) + 樣式表 = build 腳本

局部目標(biāo)包含在輸入轉(zhuǎn)換過程的主要 XML 文件中。轉(zhuǎn)換過程從次要輸入文檔中讀取缺省目標(biāo),將結(jié)果合并,并在合并的過程中指明對局部腳本的引用。
清單 1 顯示了 Ant 中的 <style>任務(wù),它負責(zé)運行轉(zhuǎn)換過程。

清單 1. Ant 的 style 任務(wù)

<style in="${local_targets}"
    out="${build_script}"
    style="${style_sheet}"
    force="yes">
 <param name="defaults" expression="${default_targets}"/>
</style>

缺省的“targets”文檔不是真正的 Ant 腳本。其中并不包含 <project> 標(biāo)簽,只是通過 <default> 標(biāo)簽將 Ant 目標(biāo)按照每一種缺省情況分組。這樣每一組目標(biāo)就可以定義一個獨立的步驟(見清單 2)。

  清單 2. 構(gòu)建 defaults XML 示例

<defaults>
?。糳efault name="init">
 <!--
=========================================================================
    Target: init
   Purpose: Common initialization target.
=========================================================================
-->
<target name="init">
<!-- This is where my default initialization tasks would be found ... -->
  
?。?target>
 
    
    </default>
?。?-- Additional defaults go here ... -->
    
   ?。?defaults>

如果要進行一般性的功能增強,只需對缺省目標(biāo),或是樣式表進行修改。由于所有的過程都引用同一份缺省目標(biāo)或樣式表,因此所作的改動會在運行過程中自動應(yīng)用于所有的腳本。維護工作中還剩下一個問題需要考慮,即局部腳本覆蓋了通用步驟中的某個增強特性的情況。然而,如果對設(shè)計進行細心地管理,根據(jù)我們對步驟的定義,那些可能會被覆蓋的步驟應(yīng)該不會包含任何缺省的行為。

例 2: 用 XSL 查看 Ant 腳本

有一個問題我經(jīng)常會遇到,即,必須去理解和修改別人寫的腳本。腳本中經(jīng)常會充斥著由本該去寫源代碼的人編寫的構(gòu)建過程。再加上缺乏文檔,甚至某些文檔還會產(chǎn)生誤導(dǎo),這些腳本就更加聲名狼藉了。

好的文檔是無法取代的,如果沒有這樣的文檔,只要能用一種抽象的方式瀏覽整個過程,那么也可以抵消一些負面影響。只要您知道一些引用關(guān)系,然后在腦海中建立一個框架,這些就可以指引您繼續(xù)研究了。如果有了好的瀏覽器,您就可以看到一幅概念的視圖,可以自由地瀏覽,而不必擔(dān)心忘記前后關(guān)系。您可以不僅可以看見森林,還可以看見一棵棵樹。

如果您第一次看見一個很大的 Ant 腳本,您很可能會被它嚇退。即使您對這個腳本很熟悉,也要花很多時間才能確定需要修改的地方在哪里。所有的 XML 文檔,包括 Ant 腳本在內(nèi),都是高度結(jié)構(gòu)化的。只要有 XSLT,您就可以將 Ant 腳本的這種結(jié)構(gòu)化特性轉(zhuǎn)換成 HTML 文檔,這樣文檔就變得更加容易閱讀和理解。您可以用 XSL 過濾掉無關(guān)緊要的信息,只留下重要的元素。

如果您使用的瀏覽器支持 XSL 樣式表(比如 Microsoft 的 Internet Explorer 6),您甚至可以使您的 Ant 腳本永久保持這樣的特性。沒有混亂的場面,也不要大驚小怪,您只需要直接打開 Ant 腳本,就可以在瀏覽器中查看結(jié)果了。Ant 在執(zhí)行的過程中會忽略額外的處理指令,這樣您就沒有必要在一開始就單獨生成 HTML 文件。

眼見為實

第一個步驟是開發(fā)樣式表,用于將 Ant 腳本轉(zhuǎn)換成 HTML。樣式表可以很簡單,也可以很詳盡,這取決于您的意愿。不論好與壞,這里就是我開發(fā)的樣式表了,它能夠滿足我在查看 Ant 腳本時的基本需求:

◆ 提供內(nèi)容列表,方便用戶迅速地找到腳本中相應(yīng)的節(jié)

◆ 對使用到的所有屬性和目標(biāo)都按字母排序并分組

◆ 在目標(biāo)及其所依賴的部分之間提供導(dǎo)航鏈接

◆ 顯示構(gòu)造出某個特定目標(biāo)的任務(wù)

如果您對 HTML 或者是 JavaScript 比較熟悉,那么毫無疑問,您對于格式化和顯示數(shù)據(jù)的方式肯定有更富創(chuàng)造性的見解。

您準(zhǔn)備好樣式表之后,可將其放在某個瀏覽器能夠訪問的地方??梢允窃?HTTP 服務(wù)器上,或是在共享設(shè)備上,只要方便就可以了。最后一步是向 Ant 腳本中加入指令。這些指令告訴瀏覽器在顯示該文檔的時候使用您的樣式表。否則,您只能看到五顏六色的原始 XML 代碼。千萬別眨眼!不然就忘記這一步了。您準(zhǔn)備好了么?請將清單 3 中高亮顯示的部分拷貝到 Ant 腳本的最上面,然后用您的樣式表的位置替換 href 屬性的值。

清單 3. 樣式表處理指令

<?xml version="1.0"?>
    
   ?。?xml-stylesheet type="text/xsl"
  href="./examples/example2/ant2html.xsl"?>
<project name="Example2" default="main" basedir=".">
?。?-- The rest of the Ant script goes here. -- >
</project>

這樣就處理完了。

正如前面一個例子里所講的,因為樣式表是與數(shù)據(jù)(在這里是 Ant 腳本)分開的,您不管如何增強樣式表,都沒有必要對腳本進行修改。只要將修改過的樣式表部署好,所有的用戶立即就能用到新的樣式。

如果您能夠瀏覽格式化之后的 Ant 腳本,您也許會想,為什么我沒有用框架讓瀏覽變得簡單些呢?從一個樣式表中生成多個框架可沒有您想象的那么簡單,需要用腳本語言實現(xiàn)(如 JavaScript)。不過我們還是可以實踐一下。我加入了同一個 Ant 腳本的第二個實例,這次用 一個可以生成框架的樣式表來格式化。這個樣式表用到了 JavaScript、MSXML、和 ActiveX 控件,因此要求用 Microsoft Internet Explorer 作為瀏覽器。Jeni Tennison 的書(參閱 參考資料)中第 14 章對于完成這個例子會有特別的幫助。

#p#

例 3: 用 XSL 擴展 Ant

Ant 的語法與其他所有的指令集相似,都不能表達某些特定的概念。雖然 Ant 對依賴關(guān)系、引用關(guān)系以及繼承關(guān)系都處理得很好,但是卻不支持最基本的循環(huán)。原有的標(biāo)簽集沒有提供任何可以反復(fù)執(zhí)行一組任務(wù)的手段。

問題

請考慮一個很簡單的問題。假設(shè)您正在構(gòu)建的一個發(fā)布版本支持八種語言:德語、英語、法語、意大利語、日語、韓語、葡萄牙語以及西班牙語。與特定語言相關(guān)的文件必須要用其本國代碼表示,這就要求對所有與特定語言有關(guān)的屬性文件都運行 Ant 的 native2ascii 任務(wù)(參閱 參考資料)。這聽起來用循環(huán)挺合適的,是吧?

下面是解決這一問題的三種方案:

解決方案 1: 暴力方法

暴力方法就是反復(fù)編寫任務(wù)代碼,直到需要的次數(shù)。這種方法可以達到目標(biāo),對于次數(shù)較少的迭代而言也還不錯。但是如果循環(huán)變得更大,迭代的次數(shù)很多,那么維護這段代碼就成問題了。每一塊重復(fù)的代碼都使得程序邏輯中出現(xiàn)錯誤的幾率增加。在本例中,任何修改(如增加新的屬性文件)都要放大八倍。清單 4 顯示了使用這種方法的情況。請注意,黑體標(biāo)識的部分強調(diào)了每一組代碼之間的細微區(qū)別。

清單 4. 暴力方法

<target name="convert_native_encodings">
?。糿ative2ascii encoding="
    
    Cp850" src="${basedir}/src" dest="${basedir}/export">
 ?。糹nclude name="**/
    
    *_de.properties/>
?。?native2ascii>
?。糿ative2ascii encoding="
    
    Cp850" src="${basedir}/src" dest="${basedir}/export">
 ?。糹nclude name="**/
    
    *_en.properties/>
 </native2ascii>
?。糿ative2ascii encoding="
    
    Cp850" src="${basedir}/src" dest="${basedir}/export">
  <include name="**/
    
    *_es.properties/>
?。?native2ascii>
 <native2ascii encoding="
    
    Cp850" src="${basedir}/src" dest="${basedir}/export">
 ?。糹nclude name="**/
    
    *_fr.properties/>
 </native2ascii>
?。糿ative2ascii encoding="
    
    Cp850" src="${basedir}/src" dest="${basedir}/export">
 ?。糹nclude name="**/
    
    *_it.properties/>
?。?native2ascii>
?。糿ative2ascii encoding="
    
    SJIS" src="${basedir}/src" dest="${basedir}/export">
 ?。糹nclude name="**/
    
    *_ja.properties/>
?。?native2ascii>
 <native2ascii encoding="
    
    KSC5601" src="${basedir}/src"
    dest="${basedir}/export">
 ?。糹nclude name="**/
    
    *_ko.properties/>
?。?native2ascii>
?。糿ative2ascii encoding="
    
    Cp850" src="${basedir}/src"
    dest="${basedir}/export">
 ?。糹nclude name="**/
    
    *_pt_BR.properties/>
 </native2ascii>
</target>

解決方案 2: <for> 標(biāo)簽

更好的解決方案是給 Ant 提供一個 <for> 標(biāo)簽。經(jīng)過恰當(dāng)設(shè)計的擴展機制可以增強語言的功能。清單 5 顯示了這種解決方案的情況。然而,這種方法并不是沒有一點兒缺陷。首先,它要求對 Ant 的工作原理有比較深入的理解,這樣才能實現(xiàn)新的標(biāo)簽。第二個問題同樣是維護的問題,這個問題也更值得關(guān)注。在運行的時候 Ant 必須能夠訪問支持新標(biāo)簽的類。這就要求使用一個獨立的 .jar 文件,或者對 Ant 重新打包。每一個運行這段腳本的系統(tǒng)都需要訪問新的標(biāo)簽。

清單 5. 一種更好的方法

<!-- Iterate over each language code -->
<target name="convert_native_encodings">
<loadproperties srcFile="encodings.properties"/>
    
   ?。糵or token="%lang%"
     iterate-over="de, en, es, fr, it, ja, ko, pt_BR">
  <native2ascii encoding="
    
    ${encoding.%lang%}" src="${basedir}/src"
     dest="${basedir}/export">
   <include name="**/
    
    *_%lang%.properties"/>
  </native2ascii>
    
   ?。?for>
</target>

encodings.properties 文件的用處是創(chuàng)建從語言代碼到編碼單元的映射:

清單 6. 編碼映射

# File: encodings.properties
encoding.de=Cp850
encoding.en=Cp850
encoding.es=Cp850
encoding.fr=Cp850
encoding.it=Cp850
encoding.ja=SJIS
encoding.ko=KSC5601
encoding.pt_BR=Cp850

解決方案 3: 使用 XSLT

最后一種方案和第二種方案一樣,也是要擴展 Ant 語言,但是不會引起維護的問題。我這次沒有在 Ant 內(nèi)部創(chuàng)建新的 Java 類來擴展 for 循環(huán),而是用 XSLT 完成同樣的工作。得到的結(jié)果是可以在 Ant 中運行的腳本。樣式表僅僅將 <for> 標(biāo)簽展開為一系列的任務(wù),這一點又類似于第一種方法。

這種轉(zhuǎn)換所用的樣式表十分簡單明了。缺省的模板輸出的 XML 與輸入的一模一樣,我們也沒有必要進行任何修改。只有當(dāng)出現(xiàn) <for> 標(biāo)簽的時候才會有不一樣的輸出。您可以查看這次轉(zhuǎn)換采用的完整 樣式表 。

有一點值得關(guān)注一下,即,最初的輸入并不是有效的 Ant 腳本;它的輸出才是有效的 Ant 腳本。當(dāng)您發(fā)布程序構(gòu)建的結(jié)果時,只需要發(fā)布最后得到的腳本即可。這個腳本是完全合法的 Ant 腳本,大部分開發(fā)人員不需要使用樣式表,直接運行得到的腳本就可以了。

結(jié)束語:新與舊總是相對的

我希望您認為這些信息是有用的,不管是直接使用,還是點燃您自己的思維火花。我在許多方面都只是在重新表述一種很陳舊的想法。自從最早的編譯語言時代開始,人們就已經(jīng)在編譯之前用模板對源代碼進行預(yù)處理了。即便是今天,這仍然是一種功能強大的技術(shù)。

針對這項技術(shù)還可以研究和開發(fā)更多的應(yīng)用程序。我最后留給您一些建議,目的只是為了讓“Ant(螞蟻)”能繼續(xù)翩翩起舞。請盡情享受其中的快樂吧!

您可以考慮用樣式表根據(jù)其他的 XML 數(shù)據(jù)文件生成 Ant 腳本。比如說,我們所寫的很多 Java 代碼都是通過一種插件架構(gòu)來打包和發(fā)布的。這就要求包中具有 plugin.xml 文件。要將插件組裝進來,會用到一些基本的 Ant 任務(wù)( <javac> 、 <jar> 、等等)。為什么不利用 XSLT,把 plugin.xml 這個描述文件轉(zhuǎn)換成構(gòu)建插件的 Ant 腳本呢?

假設(shè)您希望在構(gòu)建過程執(zhí)行的時候?qū)崟r地獲得其狀態(tài),比如說實時更新某個 Web 頁面。有一種實現(xiàn)的方法是為 Ant 編寫一個日志任務(wù),在每一個目標(biāo)開始或結(jié)束的時候執(zhí)行更新。同樣,這樣就要求深入理解 Ant,并具有某些 Java 技能。還有一種簡單點兒的方法,我們可以用 XSLT 在每一個目標(biāo)開始或者結(jié)束的時候插入一項探測任務(wù)(probe task)。這些探測任務(wù)起到了跟蹤點的作用,用已有的 Ant 任務(wù),通過將數(shù)據(jù)寫入文件的方式來獲取狀態(tài)。

【編輯推薦】

  1. 在ASP.NET中使用Treeview控件和XML
  2. 如何利用Scala簡化XML處理
  3. 如何使用C#與XML創(chuàng)建動態(tài)分層菜單
責(zé)任編輯:楊鵬飛 來源: developerWorks
相關(guān)推薦

2009-02-04 08:52:55

動態(tài)頁面XMLXSL

2011-08-29 14:56:44

APC冗余供電

2011-05-18 14:07:59

XSL

2023-07-09 09:23:46

Java 21編程

2019-08-23 17:33:02

WindowsWindows 10電腦

2011-04-18 17:07:51

2010-01-08 10:26:45

2010-02-06 17:17:50

Ubuntu 8.10

2010-01-12 18:00:30

Visual C++

2021-05-21 09:34:40

React React 17前端

2023-09-26 00:24:44

VisualStudio視圖

2013-06-28 14:38:02

2010-05-10 09:21:46

2012-07-26 09:46:52

Hyper-VVMM 2012

2010-03-02 10:59:04

2009-02-24 18:45:32

思科虛擬化SAN

2010-08-20 08:59:27

MongoDB

2013-02-19 14:22:07

BT CONTACT

2009-02-09 09:38:41

新特性MySQL 6.0MySQL

2014-07-17 15:03:31

點贊
收藏

51CTO技術(shù)棧公眾號