XSLT: all in one

1.XSLT的概念

我們首先來澄清一個概念,大家可能聽說過XSL(eXtensible Stylesheet Language),XSL和我們這裏說的XSLT從狹義上理解是一樣的,而按照W3C的標準,XSLT的說法更嚴格些,因此我們在文章中統一使用XSLT的稱法。它們之間具體的關係我們會在下面講述。

1.1 什麼是XSLT

XSLT的英文標準名稱爲eXtensible Stylesheet Language Transformation。根據W3C的規範說明書(http://www.w3.org/TR/xslt),最早設計XSLT的用意是幫助XML文檔(document)轉換爲其它文檔。但是隨着發展,XSLT已不僅僅用於將XML轉換爲HTML或其它文本格式,更全面的定義應該是:

XSLT是一種用來轉換XML文檔結構的語言。

1.2 爲什麼要用XSLT

我們已經知道,XML是一種電腦程序間交換原始數據的簡單而標準的方法。它的成功並不在於它容易被人們書寫和閱讀,更重要的是,它從根本上解決了應用系統間的信息交換。因爲XML滿足了兩個基本的需求:

(1).將數據和表達形式分離。就象天氣預報的信息可以顯示在不同的設備上,電視,手機或者其它。

(2).在不同的應用之間傳輸數據。電子商務數據交換的與日俱增使得這種需求越來越緊迫。

爲了使數據便於人們的閱讀理解,我們需要將信息顯示出來或者打印出來,例如將數據變成一個HTML文件,一個PDF文件,甚至是一段聲音;同樣,爲了使數據適合不同的應用程序,我們必須有能夠將一種數據格式轉換爲另一種數據格式,比如需求格式可能是一個文本文件,一個SQL語句,一個HTTP信息,一定順序的數據調用等。而XSLT就是我們用來實現這種轉換功能的語言。將XML轉換爲HTML,是目前XSLT最主要的功能。

1.3 XSLT的歷史

想很多其他XML家族成員一樣,XSLT是由W3C起草和制定的。它的主要發展歷程如下:

.1995年由James Clark提議;

.1997年8月正式提案爲XSL;

.1998年5月由Norman Walsh完成需求概要;

.1998年8月18日XSL草案發布;

.1999年11月16日正式發佈XSL 1.0推薦版本。

目前,XSLT仍然在快速的發展中,XSLT1.1的草案已經可以在W3C網站(http://www.w3.org/TR/xslt11)上看到。

1.4 什麼是XPath

XPath是XSLT的重要組成部分,我們將在第四章講解它的詳細語法。那麼XPath是什麼呢?我們首先來了解一下XSL系列的"家族"關係。如下圖:

 

XSL在轉換XML文檔時分爲明顯的兩個過程,第一轉換文檔結構;其次將文檔格式化輸出。這兩步可以分離開來並單獨處理,因此XSL在發展過程中逐漸分裂爲XSLT(結構轉換)和XSL-FO(formatting objects)(格式化輸出)兩種分支語言,其中XSL-FO的作用就類似CSS在HTML中的作用。而我們這裏重點討論的是第一步的轉換過程,也就是XSLT。

另外,在學習XML時我們已經知道XML是一個完整的樹結構文檔。在轉換XML文檔時可能需要處理其中的一部分(節點)數據,那麼如何查找和定位XML文檔中的信息呢,XPath就是一種專門用來在XML文檔中查找信息的語言。XPath隸屬XSLT,因此我們通常會將XSLT語法和XPath語法混在一起說。

用一種比較好理解的解釋:如果將XML文檔看作一個數據庫,XPath就是SQL查詢語言;如果將XML文檔看成DOS目錄結構,XPath就是cd,dir等目錄操作命令的集合。

1.5 XSLT和CSS的比較

CSS同樣可以格式化XML文檔,那麼有了CSS爲什麼還需要XSLT呢?因爲CSS雖然能夠很好的控制輸出的樣式,比如色彩,字體,大小等,但是它有嚴重的侷限性,就是:

(1) CSS不能重新排序文檔中的元素;

(2) CSS不能判斷和控制哪個元素被顯示,哪個不被顯示;

(3) CSS不能統計計算元素中的數據;

換句話說,CSS只適合用於輸出比較固定的最終文檔。CSS的優點是簡潔,消耗系統資源少;而XSLT雖然功能強大,但因爲要重新索引XML結構樹,所以消耗內存比較多。

因此,我們常常將它們結合起來使用,比如在服務器端用XSLT處理文檔,在客戶端用CSS來控制顯示。可以減少響應時間。

1.6 XSLT和IE5

在XSLT草案發布不久,微軟就在IE4中提供了支持XSL功能的預覽版本,到IE5.0發佈時,正式全面支持XSLT,可是由於IE5發佈的比XSLT1.0標準時間早,因此在IE5.0中支持的XSTL功能和XSLT 1.0略有不同。(呵呵~~XML推行的主要原因之一就是解決HTML過分依賴瀏覽器的問題,現在微軟又想標新立異?)。好在微軟的IE5.5中執行的標準已經和W3C的XSLT1.0基本相近。但令人頭疼的是IE5.0已經發行了幾百萬套,您使用的XSLT很可能不能被客戶的瀏覽器正確執行。目前XSLT 1.1仍在發展中,W3C及有關組織也在和微軟協商爭取獲得統一。

2 用XPath精確定位節點元素

在利用XSL進行轉換的過程中,匹配的概念非常重要。在模板聲明語句 xsl:template match = ""和模板應用語句xsl:apply-templates select = "" 中,用引號括起來的部分必須能夠精確地定位節點。具體的定位方法則在XPath中給出。

之所以要在XSL中引入XPath的概念,目的就是爲了在匹配XML文檔結構樹時能夠準確地找到某一個節點元素。可以把XPath比作文件管理路徑:通過文件管理路徑,可以按照一定的規則查找到所需要的文件;同樣,依據XPath所制定的規則,也可以很方便地找到XML結構文檔樹中的任何一個節點,顯然這對XSLT來說是一個最最基本的功能。


XPath數據類型

XPath可分爲四種數據類型:

節點集(node-set)
節點集是通過路徑匹配返回的符合條件的一組節點的集合。其它類型的數據不能轉換爲節點集。
布爾值(boolean)
由函數或布爾表達式返回的條件匹配值,與一般語言中的布爾值相同,有true和 false兩個值。布爾值可以和數值類型、字符串類型相互轉換。
字符串(string)
字符串即包含一系列字符的集合,XPath中提供了一系列的字符串函數。字符串可與數值類型、布爾值類型的數據相互轉換。
數值(number)
在XPath中數值爲浮點數,可以是雙精度64位浮點數。另外包括一些數值的特殊描述,如非數值NaN(Not-a-Number)、正無窮大infinity、負無窮大-infinity、正負0等等。number的整數值可以通過函數取得,另外,數值也可以和布爾類型、字符串類型相互轉換。
其中後三種數據類型與其它編程語言中相應的數據類型差不多,只是第一種數據類型是XML文檔樹的特有產物。

XPath節點類型

另外,由於XPath包含的是對文檔結構樹的一系列操作,因此搞清楚XPath節點類型也是很必要的。回憶一下第二章中講到的XML文檔的邏輯結構,一個XML文件可以包含元素、CDATA、註釋、處理指令等邏輯要素,其中元素還可以包含屬性,並可以利用屬性來定義命名空間。相應地,在XPath中,將節點劃分爲七種節點類型:

根節點(Root Node)
根節點是一棵樹的最上層,根節點是唯一的。樹上其它所有元素節點都是它的子節點或後代節點。對根節點的處理機制與其它節點相同。在XSLT中對樹的匹配總是先從根節點開始。
元素節點(Element Nodes)
元素節點對應於文檔中的每一個元素,一個元素節點的子節點可以是元素節點、註釋節點、處理指令節點和文本節點。可以爲元素節點定義一個唯一的標識id。元素節點都可以有擴展名,它是由兩部分組成的:一部分是命名空間URI,另一部分是本地的命名。
文本節點(Text Nodes)
文本節點包含了一組字符數據,即CDATA中包含的字符。任何一個文本節點都不會有緊鄰的兄弟文本節點,而且文本節點沒有擴展名。
屬性節點(Attribute Nodes)
每一個元素節點有一個相關聯的屬性節點集合,元素是每個屬性節點的父節點,但屬性節點卻不是其父元素的子節點。這就是說,通過查找元素的子節點可以匹配出元素的屬性節點,但反過來不成立,只是單向的。再有,元素的屬性節點沒有共享性,也就是說不同的元素節點不共有同一個屬性節點。
對缺省屬性的處理等同於定義了的屬性。如果一個屬性是在DTD聲明的,但聲明爲 #IMPLIED,而該屬性沒有在元素中定義,則該元素的屬性節點集中不包含該屬性。
此外,與屬性相對應的屬性節點都沒有命名空間的聲明。命名空間屬性對應着另一種類型的節點。
命名空間節點(Namespace Nodes)
每一個元素節點都有一個相關的命名空間節點集。在XML文檔中,命名空間是通過保留屬性聲明的,因此,在XPath中,該類節點與屬性節點極爲相似,它們與父元素之間的關係是單向的,並且不具有共享性。
處理指令節點(Processing Instruction Nodes)
處理指令節點對應於XML文檔中的每一條處理指令。它也有擴展名,擴展名的本地命名指向處理對象,而命名空間部分爲空。
註釋節點(Comment Nodes)
註釋節點對應於文檔中的註釋。


一個XML文檔樹

我們來構造一棵XML文檔樹,作爲後面舉例的依託:


 <A id="a1">
   <B id="b1">
  <C id="c1">
    <B name="b"/>
    <D id="d1"/>
    <E id="e1"/>
    <E id="e2"/>
  </C>
   </B>
   <B id="b2"/>
   <C id="c2">
  <B/>
  <D id="d2"/>
  <F/>
   </C>
   <E/>
 </A>
 


以下將要介紹一些XPath中節點匹配的基本方法。


路徑匹配

路徑匹配與文件路徑的表示相仿,比較好理解。有以下幾個符號:

(1)用“/”指示節點路徑
如“/A/C/D” 表示節點"A"的子節點"C"的子節點"D",即id值爲d2的D節點, “/”表示根節點。

(2)用“//” 表示所有路徑以"//"後指定的子路徑結尾的元素
如“//E” 表示所有E元素,結果是所有三個E元素,如“//C/E”表示所有父節點爲C的E元素,結果是id值爲e1和e2的兩個E元素 。

(3)用“*” 表示路徑的通配符
如“/A/B/C/*”表示 A元素→B元素→C元素下的所有子元素,即name值爲b的B元素、 id值爲d1的D元素和id值爲e1和e2的兩個E元素
“/*/*/D”表示上面有兩級節點的D元素,匹配結果是id值爲d2的D元素 ,如“//*”表示所有的元素。

位置匹配

對於每一個元素,它的各個子元素是有序的。

如:/A/B/C[1]表示A元素→B元素→C元素的第一個子元素,得到name值爲b的B元素

/A/B/C[last()]表示A元素→B元素→C元素的最後一個子元素,得到id值爲e2的E元素

/A/B/C[position()>1]表示A元素→B元素→C元素之下的位置號大於1的元素,得到id值爲d1的D元素和兩個具有id值的E元素


屬性及屬性值

在XPath中可以利用屬性及屬性值來匹配元素,要注意的是,元素的屬性名前要有"@"前綴。例如:

//B[@id]表示所有具有屬性id的B元素,結果爲id值爲b1和b2的兩個B元素

//B[@*]表示所有具有屬性的B元素,結果爲兩個具有id屬性的B元素和一個具有name屬性B元素

//B[not(@*)]表示所有不具有屬性的B元素,結果爲A元素→C元素下的B元素

//B[@id="b1"] id值爲b1的B元素,結果爲A元素下的B元素


親屬關係匹配

XML文檔可歸結爲樹型結構,因此任何一個節點都不是孤立的。通常我們把節點之間的歸屬關係歸結爲一種親屬關係,如父親、孩子、祖先、後代、兄弟等等。在對元素進行匹配時,同樣可以用到這些概念。例如:

//E/parent::* 表示所有E節點的父節點元素,結果爲id值爲a1的A元素和id值爲c1的C元素

//F/ancestor::* 表示所有F元素的祖先節點元素,結果爲id值爲a1的A元素和id值爲c2的C元素

/A/child::* 表示A的子元素,結果爲id值爲b1、b2的B元素,id值爲c2的C元素,以及沒有任何屬性的E元素

/A/descendant::* 表示A的所有後代元素,結果爲除A元素以外的所有其它元素

//F/self::* 表示所有F的自身元素,結果爲F元素本身

//F/ancestor-or-self::* 表示所有F元素及它的祖先節點元素,結果爲F元素、F元素的父節點C元素和A元素

/A/C/descendant-or-self::* 表示所有A元素→C元素及它們的後代元素,結果爲id值爲c2的C元素、該元素的子元素B、D、F元素

/A/C/following-sibling::* 表示A元素→C元素的緊鄰的後序所有兄弟節點元素,結果爲沒有任何屬性的E元素

/A/C/preceding-sibling::* 表示A元素→C元素的緊鄰的前面所有兄弟節點元素,結果爲id值爲b1和b2的兩個B元素

/A/B/C/following::* 表示A元素→B元素→C元素的後序的所有元素,結果爲id 爲b2的B元素、無屬性的C元素、無屬性的B元素、id爲d2的D元素、無屬性的F元素、/無屬性的E元素。

/A/C/preceding::* 表示A元素→C元素的前面的所有元素,結果爲id爲b2的B元素、id爲e2的E元素、id爲e1的E元素、id爲d1的D元素、name爲 b的B元素、id爲c1的C元素、id爲b1的B元素


條件匹配

條件匹配就是利用一些函數的運算結果的布爾值來匹配符合條件的節點。常用於條件匹配的函數有四大類:節點函數、字符串函數、數值函數、布爾函數。例如last()、position()等等,這裏我們就不再贅述。

以上這些匹配方法中,用得最多的還要數路徑匹配。在上一章樣式表的例子中,無論是在語句<xsl:template match="學生花名冊">中,還是在語句 <xsl:value-of select="名字"/>中,都是依靠給出相對於當前路徑的子路徑來定位節點的。

3. XQuery ,可以參考w3cChina "XQuery 1.0:XML查詢語言 工作草案-1".

3.1 什麼是XQuery(from:http://www.woodpecker.org.cn:9081/doc/XML/tutor/x-xquery/x-xquery/index3.html

 XML Query(XQuery)是在 XML 數據中搜索特定信息的功能強大的新方法。與 XPath 2.0 的起源相同,XQuery 的某些方面 — 如傳統的 XPath 表達式 — 看上去很熟悉,而其它方面(如 FLWR 和條件語句)則是全新的。爲了幫助消除解釋問題,XQuery 工作組創建了“XML Query Use Cases”文檔(請參閱參考資料,它提供了樣本查詢及其預期的結果。本教程中的示例都基於爲該文檔創建的樣本數據。

XQuery 是 XML 規範和 W3C 建議書之間相互關係的優秀示例。XQuery 工作組與 XSL 工作組還一起負責 XPath 2.0 工作草案,XPath 2.0 將包括許多爲 XQuery 開發的功能。

除了對 XPath 的增強外,XQuery 還允許您通過嵌套類 SQL 的子句來創建複雜查詢,以及通過將 XML 構造器直接包括在輸出中來創建複雜結果。本章概述了 XQuery 的這些方面,然後將更詳細地討論每個方面。

3.2 XPath 2.0 增強

 對 XPath 的增強通常分成四種類別:

序列:XPath 1.0 通常返回節點集,而 XPath 2.0 返回序列。如序列中討論的那樣,序列與節點集相似,但提供了更多的能力。節點集和序列之間最重要的差異之一是:與序列不同,節點集是無序的。每個 XPath 2.0 表達式都返回一個序列,即使它是隻有一項的序列。
數據類型:XPath 1.0 理解四種數據類型:node-sets、strings、booleans 和 numbers。XPath 2.0 不僅包含對 XML Schema 內置數據類型的支持,而且還包含對用戶定義的數據類型的支持。
增強的函數集:XPath 2.0 包括用於操作數據的函數,就象 1.0 一樣。它還包括相當健壯的序列比較支持,如檢查節點是否等於特定的深度或選擇兩個序列的交集或並集的能力。
多個數據源:XPath 2.0 包含顯式地爲表達式設置數據源的能力,這使將多個數據源中的數據合併到單個查詢成爲可能。

3.3 FLWR 語句
 FLWR 是 FOR-LET-WHERE-RETURN 的縮寫,它描述了典型 XQuery 的結構。在 FLWR 語句中,數據被綁定到變量,然後,後續步驟使用該變量。例如,使用下面的語句:

for $book in
document("http://www.bn.com/bib.xml")//book 
let $title := $book/title 
where $book/publisher = 'Addison-Wesley' 
return 
  
<bookInfo> 
        { $title } 
</bookInfo> 
該語句返回原始文檔中每個 book 元素的 bookInfo 元素,其中 book 元素的 publisher 子元素爲 Addison-Wesley。每個 bookInfo 元素都有 title 子元素,如下所示:
<bookInfo>
  <title>TCP/IP Illustrated</title>
</bookInfo>
<bookInfo>
  <title>Advanced Programming in the Unix environment</title>
</bookInfo>

3.4 構造器
 構造器是創建 XML 元素和屬性、CDATA 節、註釋,或處理 XQuery 表達式結果內部指令的方法。XQuery 建議書描述了兩種構造器,它們允許直接創建元素,而不是由 XSLT template 元素間接創建。第一種是典型的構造器,它只是將結果嵌入到元素或其它構造中,如下面的表達式中說明的那樣:<books>  
{  
    for $book in input()/bib/book 
    return 
        <itemInfo> 
            { $book/title } 
            { $book/price } 
        </itemInfo> 
}  
</books> 
第二種稱爲計算構造器,因爲它允許創建名稱由表達式結果決定的元素。3.5 序列 序列相對於節點集的主要優勢之一在於序列是有序的。實際上,XPath 1.0 表達式可以根據文檔次序挑選節點,而 XPath 2.0 瞭解序列本身的次序。例如,下面的語句輸出任何操作的文本,這些操作發生在一個操作的第一個過程的第一個和第二個“缺口(incision)”之間。<critical_sequence>
 {
  let $proc := document("/XQuery/docs/SEQ/report1.xml")
                         
  //section[section.title="Procedure"][1]
  for $n in $proc//node()
  where $n follows ($proc//incision)[1]
    and $n precedes ($proc//incision)[2]
  return $n/text()
}
</critical_sequence>


序列不僅只確定節點出現的次序,而且在如何組合它們及它們是如何交互的方面也起到很重要的作用。

3.5 函數
 XQuery 提供了定義函數的能力,這些函數隨後可在其它表達式中使用。例如:define function summary(element employee* $emps)  
   returns element dept* 
{  
   for $d in distinct-values($emps/deptno) 
   let $e := $emps[deptno = $d] 
   return 
      <dept> 
         {$d} 
         <headcount> {count($e)} </headcount> 
         <payroll> {sum($e/salary)} </payroll> 
      </dept> 
}  
      
summary(document("acme_corp.xml")//employee[location = "Denver"]) 
有了這種能力,不僅可以使用由 XPath 2.0 預先定義的函數,而且可以根據需要定義您自己的函數。3.6多個數據源 XQuery 的最主要優勢之一是,它能夠通過爲特定的表達式顯式地指定數據源來合併來自多個數據源的輸入。例如,下面的查詢:<result>  
  { 
    for $i in  document("items.xml") //item_tuple 
    let $b :=  document("bids.xml") //bid_tuple[itemno= $i/itemno] 
    where contains($i/description, "Bicycle")
    return 
        <item_tuple> 
            { $i/itemno } 
            { $i/description } 
            <high_bid>{ max(for $z in $b/bid return decimal($z)) }</high_bid> 
        </item_tuple> 
    sortby(itemno) 
  } 
</result> 
將文件 items.xml 中的信息與另一個文件 bids.xml 中的信息進行比較。結果包含來自兩個文件的信息。

4. 關於xslt的W3C Recommendation,可以參考:http://www.w3.org/TR/xslt

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/nomad2/archive/2007/01/19/1487983.aspx

發佈了18 篇原創文章 · 獲贊 11 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章