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