XSLT 2.0 的新特性 (轉)

worldblog發表於2007-12-12
XSLT 2.0 的新特性 (轉)[@more@]xslt2,xslt, name=keys>

XSLT 2.0 的新特性

關鍵字: XSLT, XML
原作:2002.4.10, to:fwjsoft@.com.cn">onestab 譯自

本文將看看最新的中所列出的XSLT2.0的一些新特性,當然,假定你已經熟悉XSLT/1.0的基本知識。

XSLT 2.0 和 XPath 2.0

XSLT 2.0 與 XPath 2.0 攜手並肩。之所以將它們分開描述,是因為 XPath 2.0 也可用於XSLT之外的環境,比如XQuery 1.0。但是對於XSLT來說,它們是互相關聯的。你不能在XSLT 1.0 中使用 XPath 2.0,或者在 XSLT 2.0 中使用 XPath 1.0。(至少到目前為止,還沒有這種組合的提議。)

你也許會問:XSLT 1.1 發生了什麼?XSLT 1.1 已經取消了。的說法是在2001年8月,.com/read.?item=1163">實際上在幾個月前,XSLT工作組中止了XSLT 1.1,集中力量開發XSLT和XPath 2.0,將XSLT 1.1 的前期要求轉到XSLT 2.0。

歡迎到來

許多的XSLT使用者在很大程度上參與了新版XSLT的制訂過程。就像許多語言的第一版一樣,不經過實踐的檢驗,這個語言的哪些擴充套件被證明是最重要的往往不很清楚。自從1999年11月16日XSLT 1.0 成了以後,顯然在某些方面缺少的功能應當在下一個版本中包括進來,本文我們將從下面四個方面看看XSLT 2.0:

  • 從結果樹片斷(result tree fragments)到節點集(node-sets)的轉化
  • 有多個輸出的文件
  • 對分組的內在支援
  • 使用者定義(以XSLT實現)

RTF的末日

在XSLT 1.0 中結果樹片斷(Result Tree Fragment,RTF)型別很像節點集,實際上卻是個二等公民。當你使用xsl:variable構建一個臨時樹的時候,得到的就是RTF。問題是你不能使用XPath訪問這個樹的內容,除非你使用一個供應商提供的擴充套件函式,通常是node-set()之類,來把這個RTF轉化成一類節點集(含有一個根節點)。這種RTF資料型別的存在本來是為了減少實現時的限制,但由於幾乎所有的XSLT都提供諸如node-set()之類的擴充套件函式,這種考慮顯得有些不切實際。不管怎樣,突破這種限制的呼聲總會越來越明顯,因為把複雜的變換分解成一系列簡單的變換非常重要。

不知道你有沒有猜出來,XSLT 2.0 為RTF開啟了這個門。現在當你使用xsl:variable建立一個臨時樹,這個變數的值就是個真正的節點集。事實上,用XPath 2.0 的術語來講,它是個真正的節點序列(true node sequence),包含一個 document node (這是一個XPath 2.0 的名稱,也就是XPath 1.0 的" node")。在這個序列上你可以使用XPath表示式深入到這棵樹,對它應用模板(template)等等,就像使用其它源一樣。有了XLST 2.0 就不再需要node-set()之類的擴充套件函式。

允許多個輸出文件

許多XSLT 1.0 處理器所提供的另一個擴充套件就是多個輸出文件,這種擴充套件被證明非常有用,對具有多個頁面的網站的靜態生成尤其如此。問題在於這個擴充套件功能不是標準的。每個處理器完成這種擴充套件的元素都不一樣,例如 saxon:output, xt:document等等。

XSLT 2.0 使用 xsl:result-document元素提供了多個輸出文件的一個標準方法。下面的樣式表例子構建了多個輸出文件,一個“主要結果檔案”和幾個“次級結果檔案”。主要結果檔案以,次級結果檔案以純文字方式儲存。


xsl:document href 屬性用來為相應的輸出檔案指定一個URI。對於許多處理器來說,這意味著以該檔名儲存檔案。而format屬性用來引用一個已命名的指定輸出。在這裡,它指向以textFormat命名的xsl:output元素。

上例中的XHTML輸出方式也是在XSLT 2.0中新引入的,這裡勿須贅言。

簡化的分組

XSLT 1.0 沒有對分組的內在支援。特定的分組問題無疑可使用各種技巧解決,例如/muenchian.html">Muenchian方法,但是這種解決方法相當複雜難懂。對XSLT 2.0 的要求之一就是必須要簡化分組,就像我們在下例中所看到的,這種方法能滿足要求。

出現在 Requirements document 和XSLT 2.0 工作草案的這個例子是關於把下面簡單XML文件中的城市列表,


轉換為如下所示的以國家進行分組的HTML表格:

Country City List Population
italy milan, venice 6
france paris, lyon 9
germany munich 4

這種轉換的難點在於生成最後三行(如粗體所示)。下面是XSLT1.0的一種解決方案:

,


在上例中,對每個特定的國家,我們首先要用下面的XPath表示式找出它的第一個城市:

cities/city[not(@country = preceding::*/@country)]


然後,對每個分組,為了獲得每個國家的城市名字列表以及該國的總人口,我們需要再回頭引用該組的所有其他成員,這兩種情況我們不得不作一些額外的工作,因為只能用下面的表示式才能引用到當前的分組:

../city[@country = current()/@country]


顯然這不是個理想的局面,因為這種額外的程式碼往往是錯誤之源。 使用 xsl:for-each-group, XSLT 2.0 為你的大多數分組問題提供了答案。下面就是XSLT2.0對這個問題的解決辦法(粗體表示新特性):

for-each-group select="cities/city" group-by="@country"> separator=", "/>


在上例中,xsl:for-each-group 作為XPath的取值上下文的一部分,對"current group"進行初始化,當前的分組是一個簡單序列。一旦我們使用group-by屬性設定好分組,以後就可以使用current-group()函式引用當前的分組。這就完全消除了XSLT1.0方案中的額外開銷。

注意xsl:value-of中的separator屬性。這個屬性的存在是為了告訴處理器不只是要輸出這個序列中的第一個元素的string值(XSLT1.0是如此作的),而是要按順序輸出該序列中所有元素的值。separator屬性的取值為一個可選的字串,用作輸出中每個字串的分隔符。為了與XSLT1.0相容,如果沒有指定separator屬性,只輸出該序列中的一個成員的值。

最後,根據xsl:for-each-group的三個屬性的取值,可以解決不同的分組問題:group-by(如上面所示),goup-adjacent(用於根據文當中的節點順序的相鄰關係進行分組,例如將inline的元素轉化為塊級(block)的元素),以及group-start-with(根據序列中元素的(patterns)分組)。這些方法的例子可以在最新的XSLT2.0工作草案的""中找到。

XSLT2.0引入了一個新特性,就是允許定義他們自己的函式,並可以在Xpath表示式中使用。這是個非常強大的功能,無疑是非常有用的。樣式函式(Stylesheet functions)是用xsl:function元素定義的。這個元素必須指定一個name屬性。它包含0個或多個xsl:param元素,然後是0個或多個xsl:variable元素,後面是唯一的xsl:result元素。這種嚴格的內容模型看起來是個限制,但是你會發現XSLT2.0的真正強大之處就在於可定義xsl:result元素的select屬性。你可能會想到,XPath2.0具備有條件表示式(if...then)和迭代(iterative)(列舉?)表示式(for...return)。

就像下面例子(直接取於最新的工作草案)所示,許多工作是在xsl:resultselect屬性中完成的。這個樣式表了使用者自定義的一個遞迴函式str:reverse()來輸出字串"MAN BITES DOG"。


如果你迫不及待地想試試這些新東西,Michael Key已經發布了forge/#F7.0" target=_top>Saxon 7.0,包含一個“實現XSLT2.0和XPath2.0的嘗試”。它實現了XSLT2.0和XPath2.0的一些新特性,特別值得關注的是這些特性看起來非常穩定。我對本文中的每個例子都作了測試,正如所期待的那樣,Saxon 7.0 能夠全部執行這些例子。

XSLT2.0很大程度上仍然處於起草階段,所以要預先指出,從目前階段到成為推薦標準中間,有些東西可能會發生變化。目前,鼓勵大家瀏覽說明檔案並將他們的觀點傳送到 xsl-editors@w3.org。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992041/,如需轉載,請註明出處,否則將追究法律責任。

相關文章