基礎篇: XSLT快速參考

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文檔。

代碼1: builtin.xsl
<?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 屬性值模板

需要生成屬性值時,可以使用大括號{}將表達式括起來。2

例如,想由

<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">  &lt;</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>

例如 ,若想由 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>    <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所示。

我們上面的例子中爲了在xsl:number元素之後加一個空格,不得不使用了xsl:text元素。實際上只要將format屬性設置爲“1 ”就可以了。level屬性爲multiple的情況下也可以指定類似於“1.A.I”這樣的格式。
發佈了26 篇原創文章 · 獲贊 5 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章