明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

XML的顯示——XSL樣式單

[摘要]XML文檔的一大特點是可以向多種格式的文檔進行轉換。比如,從一種邏輯結構的XML向另一種邏輯結構的XML轉換,或是轉換為可瀏覽的HTML文檔等。這種XML文檔的數(shù)據格式轉換功能由可擴展樣式單語言(XSL)完成。 北京郵電大學 張劍 ---------------------------------...
XML文檔的一大特點是可以向多種格式的文檔進行轉換。比如,從一種邏輯結構的XML向另一種邏輯結構的XML轉換,或是轉換為可瀏覽的HTML文檔等。這種XML文檔的數(shù)據格式轉換功能由可擴展樣式單語言(XSL)完成。


北京郵電大學 張劍

--------------------------------------------------------------------------------


一、XML文檔轉換原理
數(shù)據格式轉換的重要思想是要把XML文檔視為一種樹結構,轉換的過程就是從源樹生成結果樹的過程。XSL樣式單定義了源樹和結果樹中對應部分的轉換規(guī)則,每條規(guī)則中包含了一個模板,并對應著一種模式。模板定義了轉換的結果,而模式則規(guī)定了需要進行轉換的元素或屬性對象。
XML中引用XSL的語法格式如下:
<?xml-stylesheet type=“text/xsl” href=“Employees.xsl” ?>
如果在聲明部分引用了多個XSL樣式單,則只有第一個樣式單會生效,其余的都會被忽略掉。
XSL的格式轉換功能在復雜的電子商務解決方案中大有用武之地。比如,A公司和B公司都是生產機器零件的廠家,在貨物清單中都包含了產品序列號以及質量等級評分。A公司的文件格式如下:
<Order>
<OrderItem>
<ItemID>12980-235</ItemID>
<Quantity>200</Quantity>
</OrderItem>
</Order>
而B公司的文件格式有所不同,相關信息都出現(xiàn)在元素的屬性中:
<Order>
<OrderLine PartNo=“12980-235” NumRequired=“200”/>
</Order>
這樣,雖然兩個公司的產品完全一樣,但由于文檔格式的差異給雙方的貿易往來設置了障礙。而使用XSL樣式單可以輕松地把A公司的文檔轉換成B公司的格式,反之亦然。
二、XML文檔轉換步驟
XML文檔的轉換過程分為兩步:
● 首先是根據XML文檔構造源樹,然后根據XSL規(guī)則將源樹轉換為結果樹。目前,這種轉換協(xié)議已經日趨完善,并從XSL中獨立出來,成為W3C正式推薦的標準,稱為XSLT(XSL Transformations);
● 生成結果樹后,就可以對其進行解釋,產生一種適合顯示、打印或是播放的格式,這一步稱為格式化(Formatting)。
XSL處理器負責實現(xiàn)轉換過程。首先,XML文檔被解析成DOM樹存放在內存中,接著對文檔進行分析,每一個DOM樹中的節(jié)點都會與一個模式相比較,當二者匹配時,就會按照模板中定義的規(guī)則進行轉換,否則繼續(xù)往下匹配。如此循環(huán),直至整個文檔處理完畢。
三、XSL文檔標準格式
XSL文檔的標準格式如下:
<xsl:stylesheet xmlns:xsl=“http://www.w3.org/TR/WD-xsl”>
template rule i
output template
</xsl:stylesheet>
XSL文檔本身是格式良好的XML文檔,所以在書寫時要注意標簽的匹配問題。<xsl:stylesheet>既是XSL的聲明語句,也是根元素,必須位于文件的首部。通常也要利用xmlns屬性指明XSL的名稱空間。樣式單中所有的模板規(guī)則都由標簽<xsl:temlplate>標明。模板規(guī)則可以說明處理的對象(元素/屬性)、處理的方式或是轉換的結果。此時,我們可以把該標簽類似地理解為編程語言中函數(shù)的概念。
四、XSL的語法結構
XSL的邏輯語法結構包括循環(huán)和條件判斷。這兩種結構使用戶能夠靈活地書寫轉換規(guī)則。循環(huán)判斷是通過<xsl:for-each>元素實現(xiàn)的,它的可選屬性包括select和order-by。循環(huán)結構能夠遍歷整個結果集合,而不必針對每一條結果都單獨書寫轉換規(guī)則。它的標準語法格式為:
<xsl:for-each select=“pattern” order-by=“patternlist”>
......
</xsl:for-each>
條件判斷結構分為if語句和Case語句兩種形式。if語句是簡單地對條件進行判斷,結果為真就執(zhí)行條件內部的規(guī)則,因此可以把if條件與簡單的布爾表達式聯(lián)合使用。下面這個例子就是對薪水超過100萬元的職員輸出“Overpaid employee”信息:
<xsl:if match=“.[Salary $gt$ 1000000]”>
Overpaid employee
</xsl:if>
Case語句是對多種情況的分支判斷。該語句包括<xsl:choose>、<xsl:when>和<xsl:otherwise>三個元素。下面的例子是對薪水不足1萬元的職員輸出“No tax”,對超過5萬元的職員輸出“High tax rate”,對介于其間的職員輸出“Normal tax rate”信息:
<xsl:choose>
<xsl:when match=“.[Salary $lt$ 10000]”>
No tax </xsl:when>
<xsl:when match=“.[Salary $gt$ 50000]”>
High tax rate </xsl:when>
<xsl:otherwise> Normal tax rate </xsl:otherwise>
</xsl:choose>
五、XSL的模板規(guī)則
<xsl:template>標簽內的文本內容描述了轉換結果的形式,稱為輸出模板。屬性match的取值把模板規(guī)則與指定的元素或屬性相比較,只有匹配的DOM節(jié)點才會被處理,其余的節(jié)點將被忽略。整個過程中最先匹配的是樹的根節(jié)點,根節(jié)點用“/”表示:
<xsl:template match=“/”>
output template for root element
</xsl:template>
然后匹配其他節(jié)點,此時,只要在引號中指明要處理的元素對象名稱即可。如果在引號中出現(xiàn)的是“*”,那么表示該規(guī)則適用于所有的未單獨指定處理的元素節(jié)點。比如下例中的第二個模板就表示要處理除<Employee>元素之外的所有節(jié)點:
<xsl:template match=“Employee”>
output template
</xsl:template>
 
<xsl:template match=“*”>
output template
</xsl:template>
此外,XSL中還可以使用路徑指示符來指定一些特殊位置的元素與模板相匹配!//”代表任意深度位置,如<xsl:template match=“//Employee”>用來匹配文檔中任何位置的<Employee>元素;而如果是<xsl:template match=“Employee//Name”>,則表明是匹配<Employee>元素的后繼節(jié)點中所有<Name>元素。另外一個路徑指示符是“/”,表示直接的父子節(jié)點關系。將剛才例子中的“//”換為“/”,就意味著匹配的是<Employee>元素子節(jié)點中的<Name>元素。
很顯然,某些樹節(jié)點在XSL中可能會對應多個模板,在這種情況下,只有最后一個對應模板會生效,前面的模板規(guī)則都會被XSL處理器忽略掉。
一、XSL模板的使用
XSL在輸出模板中描述輸出格式,這些格式可以是各種字符串、標簽符號、節(jié)點值或者是一些XSL語法結構,如條件判斷、循環(huán)處理等。在許多應用場合中,輸出模板中需要使用節(jié)點的取值,此時可以根據需要使用<xsl:value-of>元素輸出節(jié)點值,最直接的使用方式是<xsl:value-of />,這樣可以輸出當前節(jié)點及其所有后繼節(jié)點的取值。而如果僅僅是想輸出指定節(jié)點的取值,可以利用select屬性進行限定(select屬性可以是任意合法的路徑表達式):
<xsl:value-of select = “Name” />
<xsl:value-of select = “//Employee” />
上述第一個表達式匹配的對象是當前節(jié)點的所有子節(jié)點中名稱為<Name>的元素,第二個表達式匹配的對象則是當前節(jié)點中所有后繼節(jié)點中名為<Employee>的元素。注意: 在XSL樣式單中必須有一個模板規(guī)則與根元素相匹配。
在確定了模板規(guī)則與元素相匹配之后,就可以激活模板,這項任務由<xsl:apply-templates>元素完成。它和<xsl:templates>元素相結合就如同編程中的函數(shù)調用:前者是調用指令,而后者就是函數(shù)體。對于不同的元素需要調用不同的模板進行處理。為了激活樣式單中的模板規(guī)則,要在根元素模板規(guī)則中使用<xsl:apply-templates>元素,這樣就會層層作用使整個樣式單文件生效:
<xsl:template match=“/”>
<xsl:apply-templates /></xsl:template>
直接使用<xsl:apply-templates>元素表示不加區(qū)分地對當前節(jié)點的所有子節(jié)點應用模板,而在select屬性中書寫匹配式則能夠限定作用對象:
<xsl:stylesheet xmlns:xsl=“http://www.w3.org/TR/WD-xsl”>
<xsl:template match=“/”>
<xsl:apply-templates select=“//Employee” />
</xsl:template>
<xsl:template match=“Employee”><P>
<xsl:apply-templates select=“Name” />
<xsl:apply-templates select=“Salary” />
</P></xsl:template>
<xsl:template match=“Name”>
<SPAN style=“font-size:36pt”>
<xsl:value-of /> </SPAN></xsl:template>
<xsl:template match=“Salary”>
<I><xsl:value-of /></I></xsl:template>
</xsl:stylesheet>
上述第一個模板與XML文檔的根元素相匹配,并對根節(jié)點以下的所有<Employee>元素應用模板規(guī)則。然后,一旦遇到<Employee>標簽,就插入一個<P>標簽作為空白段落,接著對<Name>元素和<Salary>元素分別應用模板規(guī)則。最后,經過轉換顯示的結果是36磅字體的職員名字和用斜體字表示的職員薪水。
二、XSL的擴展規(guī)則
1. 路徑指示符
除了前面介紹的“//”和“/”路徑指示符,以及統(tǒng)配符“*”,還有幾個符號可以用來對模板的匹配對象進行限制:
● 當前節(jié)點指示符為“.”;
● 父節(jié)點指示符為“..”;
● 屬性指示符為“@”。
上述“@”表示對指定元素中的某個屬性進行匹配,如<xsl:apply-templates select=“Employee/@ID” />語句表示對<Employee>元素中的<ID>屬性應用模板規(guī)則。
2. 過濾匹配符
除了路徑指示符之外,還可以對作用對象進行條件過濾或是排序,以進一步調整應用效果。過濾時,一般是以子元素(或屬性)是否存在(或其取值)為標準:
● 子元素存在:即//Employee[Salary]存在,選擇含有<Salary>子元素的所有<Employee>元素;
● 子元素取值:即Employee[Salary > 25000],選擇含有<Salary>子元素,且Salary取值大于25000的所有<Employee>元素;
● 屬性存在: 即Employee[@ID]存在,選擇含有<ID>屬性的<Employee>元素;
● 屬性取值: 即Employee[@ID =“1234”],選擇所有屬性ID值為1234的<Employee>元素。
3. 其他擴展過濾
其他的一些附加功能的過濾符,按功能分為:比較操作符、布爾操作符和集合索引。
比較操作符的書寫格式和功能如下所示:
操作符 功能
$eq$ 等于
$ne$ 不等
$lt$ 小于
$le$ 小于或等于
$gt$ 大于
$ge$ 大于或等于

需要說明的是:表格中的操作符在比較字符時對大小寫是敏感的,如果要忽略大小寫的不同含義,在每個操作符前面加上前綴字母“i”即可,如“$ieq”。
布爾操作符書寫格式和功能說明如下:
操作符 功能
$and$ 邏輯與
$or$ 邏輯或
$not$ 取非

對過濾的結果可以通過集合索引進行再過濾。例如,Employee[Salary][2]就是選擇第2個含有<Salary>子元素的所有<Employee>元素。此外,XSL還提供了集合索引函數(shù)供用戶使用:index方法表示過濾結果的索引號,end方法表示最后一個過濾結果。使用方法如下所示:
Employee[index() $lt$ 2]
Employee[end()]
上述第一個表達式的選擇結果是<Employee>元素的第1和第2個子元素,第二個表達式的選擇結果是<Employee>元素的最后一個子元素。在缺省狀態(tài)下,模板規(guī)則對元素的匹配順序是按照節(jié)點在XML文檔中出現(xiàn)的前后次序排定的。但在特定的應用場合中,可能需要對原有的順序進行調整,此時需要使用order-by屬性。使用方法如下所示:
<xsl:apply-templates select=“//Employee” order-by=“+Name”/>
<xsl:apply-templates select=“//Employee”
order-by=“number(Salary)”/>
上述第一個例子表示應按姓名的字母升序排列,比如“Bob”應當排在“Tom”之前,而第二個例子則表示按照薪水的多少對職員進行排序。