1 前言
在第1章中,我們用一個簡單的XSLT樣式表作爲例子介紹了XSLT的概要。當然,XSLT所擁有的元素並不僅限於xsl:template、xsl:apply-templates、xsl:value-of。爲了實行轉換,XSLT準備了各種各樣的元素。本章將以最常用的元素爲中心舉例說明。
另外,本文中並不準備介紹元素的全部屬性。詳情請參見W3C標準的原文[1]及譯文[2]等。
在XSLT中經常會用到一種被稱爲XPath的描述方法。首先從XPath的概要開始介紹。
2 XPath是什麼?
XPath是樹結構的一種描述方法。在創建XSL樣式表時經常使用XPath。
2.1 樹結構
XML文檔表示的數據組成數結構。用XLST進行轉換,也就是從源文檔的樹(源樹)生成轉換後的樹(目標樹)的意思。這個轉換以樹結構的節點爲基礎來進行。
節點有幾種,主要爲:
- 表示根的“根節點”
- 表示元素的“元素節點”
- 表示屬性的“屬性節點”
- 表示文本的“文本節點”
- 表示註釋的“註釋節點”
使用像這樣的各種各樣的節點來表示樹的位置的描述方法稱爲XPath。
2.2 XPath表達式
創建XSLT樣式表時經常使用的XPath表達式如表1所示。所謂的上下文節點,就是由上下文構成的節點,可以理解爲“處理對象”。另外,今後會出現“當前節點”的概念,可以理解爲“被選中的節點”。 1
描述類似於UNIX的路徑描述。例如,
<html> <body> <a href="sample.html">示例</a> <ul> <li>項目A</li> <li>項目B</li> </ul> </body></html>
中,表示元素a的XPath表達式爲
/html/body/a
此外,若表示a元素的href屬性,則爲
/html/body/a/@href
表中a[表達式]是符合表達式的a項目的意思,例如表示第一個li項目時使用
/html/body/ul/li[1]
3 定義樣式表的元素
XSLT樣式表使用XML文檔的格式創建。因此,必須要遵從XML文檔的描述規則。XML文檔中必須存在的元素只有根元素。在XSLT樣式表中的根元素就是xsl:stylesheet元素。基本代碼如下所示:
<xsl:stylesheet version = "版本號"> <!-- 內容: (xsl:import*, 頂層元素) --></xsl:stylesheet>
4 模板規則
XSLT樣式表可以說是模板規則的集合。
4.1 模板規則的定義
模板規則使用xsl:template元素進行定義。它的屬性包括match、name、priority和mode。其中最重要的是match屬性,該屬性規定了節點的樣式。若沒有指定name屬性的話,就必須指定match屬性。基本的代碼如下所示。
<xsl:template match = "樣式" name = "名稱"> <!-- 內容: (xsl:param*, 模板) --></xsl:template>
name屬性將在調用命名模板時使用。關於命名模版將在後面講述。
4.2 應用模板規則
我們使用xsl:apply-template元素來應用模板規則。它包含select和mode屬性。基本的代碼如下所示:
<xsl:apply-templates select = "節點集合表達式"> <!-- 內容: (xsl:sort | xsl:with-param)* --></xsl:apply-templates>
後面將講到的排序操作等之外的情況下該元素不需要內容,因此空元素標記可以寫成以下的形式:
<xsl:apply-templates select="節點集合表達式"/>
未指定select屬性時,當前節點爲所有的子節點。
通常,僅在處理當前節點的子孫節點時使用該元素。這樣就不會發生無法終了的無限循環。不能定義如下例所示的無限循環模版:
<xsl:template match="x"> <xsl:apply-templates select="."/></xsl:template>
4.3 命名模版
帶有name屬性的模板規則可以通過模版名稱來調用。
<xsl:call-template name = "名稱"> <!-- 內容: xsl:with-param* --></xsl:call-template>
例如,定義下例所示的模板規則時,
<xsl:template name="hello"> 你好</xsl:template>
可以以下面的方式調用:
<xsl:call-template name="hello"/>
輸出爲:
你好
4.4 匹配衝突
某個指定的表達式可能會出現多個匹配結果。這時根據優先度來決定應用哪個模板。定義模板規則時可通過設置priority屬性來顯式地指定模板優先度。如未指定,將採用默認優先度。關於默認優先度的計算方法請參見參考文獻[1]。一般來說限制性強的表達式優先度較高。例如“a”的優先度要高於“*”。
4.5 內嵌模版規則
內嵌模板規則即爲默認模板規則,不匹配任何模板規則的節點將由它來處理。這種機制保證了即使在不定義任何模板規則的情況下,模版處理也能遞歸地進行下去。
應用於元素節點和根節點的內嵌模板規則如下所示。
<xsl:template match="*|/"> <xsl:apply-templates/></xsl:template>
應用於文本節點和屬性節點的內嵌模板規則如下所示。
<xsl:template match="text()|@*"> <xsl:value-of select="."/></xsl:template>
對於其他節點(如註釋節點等)不做任何處理。
這種模板規則將把文本節點內容全部輸出。將代碼1所示的XSLT樣式表應用到某個XML文檔上之後,將生成以doc爲根節點、文本節點爲內容的XML文檔。
<?xml version="1.0"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <doc> <xsl:apply-templates/> </doc> </xsl:template></xsl:stylesheet>
5 輸出
雖然稱爲“輸出”,但實際的意思是“生成目標樹的節點”。可以使用源樹生成節點,也可以直接生成節點。
5.1 取出文本
xsl:value-of元素可以將指定的節點的值作爲字符串來輸出。必須要指定select屬性。
<xsl:value-of select = "字符串表達式"/>
指定的樹種包含其它元素時,文本節點以外的節點將被忽略,僅輸出文本。例如,
<p>.com時代的<b>IT</b>雜誌</p>
對該樹應用
<xsl:value-of select="p"/>
時,輸出爲
.com時代的IT雜誌
選擇當前節點可以使用“.”。若將
<a href="http://www.gihyo.co.jp"> 技術評論公司</a>
作爲當前節點,那麼
<xsl:value-of select="."/>的URL是<xsl:value-of select="@href"/>。
的輸出爲
技術評論公司的URL是http://www.gihyo.co.jp。
5.2 節點複製
xsl:value-of元素將節點的值轉換爲字符串。與此相對,xsl:copy-of元素將複製節點,節點中包含的子元素原封不動。基本的代碼如下所示。
<xsl:copy-of select = "表達式"/>
例如、
<p>.com時代的<b>IT</b>雜誌</p>
對此應用
<xsl:copy-of select="p"/>
的話,輸出爲
<p>.com時代的<b>IT</b>雜誌</p>
5.3 屬性值模板
例如,想由
<link> <title>技術評論公司</title> <url>http://www.gihyo.co.jp/</url></link>
生成如下的HTML鏈接時,
<a href="http://www.gihyo.co.jp/"> 技術評論公司</a>
可以定義如下的模板規則。
<xsl:template match="link"> <a href="{url}"> <xsl:value-of select="title"/> </a></xsl:template>
5.4 生成文本
xsl:text元素可以生成文本節點。由於生成文本時直接將文本寫出即可,所以一般情況下該元素不使用。但是若需要令輸出的轉義字符失效的話就需要使用該元素。基本代碼如下所示。
<xsl:text disable-output-escaping = "yes" | "no"> <!-- 內容: #PCDATA --></xsl:text>
通過disable-output-escaping屬性可以指定輸出轉義字符是否無效。默認值是no。指定爲on時,
<xsl:text disable-output-escaping="yes"> <</xsl:text>
的輸出爲
<
5.5 生成註釋
需要生成註釋時可以使用xsl:comment元素。
<xsl:commwnt>這裏是註釋。</xsl:comment>
的輸出如下所示。
<!--這裏是註釋。-->
5.6 複製
複製當前節點可以使用xsl:copy元素。屬性和子節點不會被自動複製。基本代碼如下所示。
<xsl:copy> <!-- 內容:模板 --></xsl:copy>
例如,將沒有屬性的上下文元素屬性原樣輸出,可以使用如下的模板規則。
<xsl:template match="content"> <xsl:copy> <xsl:value-of select="."/> </xsl:copy></xsl:template>
若需要遞歸地複製所有節點,可以使用如下的模板規則。
<xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy></xsl:template>
5.7 生成元素
需要生成元素時可以使用xsl:element元素。通常,只要將需要生成的元素直接寫出即可,不必使用xsl:element元素。該元素僅在需要動態生成元素時纔有必要使用。基本代碼如下所示。
<xsl:element name = "生成元素的名稱"> <!-- 內容: 模板 --></xsl:element>
例如,若要由
<heading> <text>這是標題。</text> <size>2</size></heading>
生成HTML標題(h元素),則可以使用如下的模板規則。
<xsl:template match="heading"> <xsl:element name="{concat('h', size)}"> <xsl:value-of select="text"/> </xsl:element></xsl:template>
concat()是字符串連接函數。從size元素中取出值並將其連接在“h”之後構成元素名。輸出如下所示。
<h2>這是標題。</h2>
5.8 生成屬性
需要生成屬性時可以使用xsl:attribute元素。與生成元素的情況相同,通常只需要將需要生成的屬性直接寫出即可,不需使用xsl:attribute元素。該元素僅在需要動態生成屬性等場合纔有必要使用。基本代碼如下所示。
<xsl:attribute name = "生成屬性的名稱"> <!-- 內容:模板 --></xsl:attribute>
<link> <title>技術評論公司</title> <url>http://www.gihyo.co.jp/</url></link>
生成如下的HTML鏈接時,
<a href="http://www.gihyo.co.jp/"> 技術評論社</a>
可以定義如下的模板規則。
<xsl:template match="link"> <a> <xsl:attribute name="href"> <xsl:value-of select="url"/> </xsl:attribute> <xsl:value-of select="title"/> </a> </xsl:template>
5.9 添加編號
需要輸出整數值時可以使用xsl:number元素。基本代碼如下所示。
<xsl:number level = "源樹的級別" count = "表達式" from = "表達式" value = "數值表達式" format = "表示格式的字符串" />
首先看看最簡單的例子。
<items> <item>A</item> <item>D</item> <item>B</item> <item>C</item></items>
對該XML文檔定義如下的模板規則。
<xsl:template match="items"> <xsl:copy> <xsl:apply-templates select="item"/> </xsl:copy></xsl:template><xsl:template match="item"> <xsl:copy> <xsl:number/> <xsl:text> </xsl:text> <xsl:value-of select="."/> </xsl:copy></xsl:template>
生成結果如下所示。
<items> <item>1 A</item> <item>2 D</item> <item>3 B</item> <item>4 C</item></items>
省略value屬性時,則根據源樹內當前節點的位置來輸出數值。由於這個原因,若使用後面將要講到的排序元素的話,即如果定義如下所示的模板規則的話,
<xsl:template match="items"> <xsl:copy> <xsl:for-each select="item"> <xsl:sort select="."/> <xsl:copy> <xsl:number/> <xsl:text> </xsl:text> <xsl:value-of select="."/> </xsl:copy> </xsl:for-each> </xsl:copy></xsl:template>
輸出結果將如下所示。
<items> <item>1 A</item> <item>3 B</item> <item>4 C</item> <item>2 D</item></items>
需要按照排序結果的順序來添加編號的話,則須按照如下方式指定value屬性。position()函數返回正在處理的上下文節點的位置。
<xsl:number value="position()"/>
可以使用level屬性、count屬性、from屬性來控制編號方法。count屬性設置應當被編號的節點。level屬性設置作爲編號對象的源樹的級別。可指定的級別有single、multiple、any三種,默認值爲single。
例如,有下面這種層次結構的XML文檔。
<chapter title="第一章"> <section title="第一節"> <subsection title="第一部分"> </subsection> </section> <section title="第二節"> <subsection title="第二部分"> </subsection> <subsection title="第三部分"> </subsection> </section></chapter>
將xsl:number元素的level屬性設置爲single,即將如下的模板規則應用於該文檔,
<xsl:template match="chapter|section|subsection"> <xsl:apply-templates select="@title"/> <xsl:apply-templates select="*"/></xsl:template><xsl:template match="@title"> <xsl:number level="single" count="chapter|section|subsection"/> <xsl:text> </xsl:text> <xsl:value-of select="."/><br/></xsl:template>
轉換結果如下所示。
1 第一章<br/>1 第一節<br/>1 第一部分<br/>2 第二節<br/>1 第二部分<br/>2 第三部分<br/>
也就是輸出在兄弟節點中當前節點的位置。設置level屬性爲multiple時,轉換結果如下所示。
1 第一章<br/>1.1 第一節<br/>1.1.1 第一部分<br/>1.2 第二節<br/>1.2.1 第二部分<br/>1.2.2 第三部分<br/>
編號與single相同,但是增加了父節點的編號。設置level屬性爲any時,轉換結果如下所示。
1 第一章<br/>2 第一節<br/>3 第一部分<br/>4 第二節<br/>5 第二部分<br/>6 第三部分<br/>
也就是按照符合count指定的表達式的節點的順序輸出序號。
from屬性設置計數開始的位置。例如,考慮如下的XML文檔。從邏輯上看,各個節點之間有父子關係,但是在源樹中各個節點是並列關係。
<h1>大標題一</h1><h2>中標題一</h2><h3>小標題一</h3><h2>中標題二</h2><h3>小標題二</h3><h3>小標題三</h3>
下面使用from屬性設置計數開始的節點。
<xsl:template match="h1"> <xsl:number/> <xsl:text> </xsl:text> <xsl:value-of select="."/><br/></xsl:template><xsl:template match="h2"> <xsl:number level="any" count="h1"/> <xsl:text>.</xsl:text> <xsl:number level="any" from="h1" count="h2"/> <xsl:text> </xsl:text> <xsl:value-of select="."/><br/></xsl:template><xsl:template match="h3"> <xsl:number level="any" count="h1"/> <xsl:text>.</xsl:text> <xsl:number level="any" from="h1" count="h2"/> <xsl:text>.</xsl:text> <xsl:number level="any" from="h2" count="h3"/> <xsl:text> </xsl:text> <xsl:value-of select="."/><br/></xsl:template>
轉換結果如下所示。
1 大標題一<br/>1.1 中標題一<br/>1.1.1 小標題一<br/>1.2 中標題二<br/>1.2.1 小標題二<br/>1.2.2 小標題三<br/>
使用format屬性設置輸出文字的格式。默認的格式爲“1”,即輸出數字。用於表示格式的字符串如表2所示。