XSL提供兩種元素來讓你指派值到變量上:
<xsl:variable>和
<xsl:param>。它們享用共同的命名空間和語法,都使用
$name
來引用變量。這兩個元素最主要的不同是
param's
的默認值能夠被模板調(diào)用的
<xsl:with-param>所取代,就如上面最后一個例子所示。
<xsl:param name="cols">1</xsl:param> <xsl:variable name="segnum" select="position()"/>
在上面兩個元素中,
param
和
variable
的名字都是通過
name
屬性來指定的,可以看到
param
的名字是
cols
,
variable
的名字是
segnum
。它們的值可以通過兩種方式來提供,參數(shù)的例子是通過元素的內(nèi)容值“1”來賦值的,而變量的例子是通過
select
屬性值來賦值的,這個屬性值是一個表達式的結果,而元素本身并沒有內(nèi)容值。
對于新接觸XSL的用戶來說變量的特性有點古怪,當你給一個變量賦值后,你就不能在它的應用周期內(nèi)改變它的值,如果這樣做會報錯。所以你不能像在使用其它編程語言那樣對變量進行動態(tài)存儲,變量在它的應用周期內(nèi)持有的是固定值,并在應用周期結束時銷毀。這個特性是在設計XSL時就決定了,因為XSL是模板驅(qū)動而非流程驅(qū)動的。這意味著它沒有固定的執(zhí)行順序,所以你無法依賴一個能夠改變值的變量。要想正確的使用變量,你必須理解變量的周期是如何定義的。
如果一個變量定義在所有模板的外部,那么它就被認為是一個全局變量,它對所有模板都生效。全局變量的值是固定不變的,也不能被任何模板所重新賦值。但是你可以在模板內(nèi)創(chuàng)建一個與全局變量同名的本地變量,然后賦予其它的值。本地變量只能在其自己的應用周期內(nèi)起作用。
定義在模板里的本地變量只會在它被允許的周期內(nèi)生效,也就是對在它之后的同胞和后裔有效。要想理解這個周期,你必須明白XSL指令其實就是純粹的XML元素,并內(nèi)嵌在XML家族層級結構中。它們通常是指父級、子級、同級、祖先級和后裔級。在XML家族層級中,給一個變量賦值就像發(fā)布一個公告給你希望聽到家族成員一樣。你只能把公告發(fā)布給比你年齡低的同級(包括你自己)和它們的后裔級,也就是說定義在你前面的年長的同級將不會聽到公告,更不用說你的父級和祖先了。如果你發(fā)布不同的公告內(nèi)容但是用相同的公告名給相同的被通知成員,那將出現(xiàn)錯誤,(言外之義,你重新給變量賦值了)。請記住這里的家族并不是你的文檔元素,而只是在你
stylesheet
中的XSL指令。手工編寫
stylesheet
將對你跟蹤周期很有幫助,XSL元素縮進和嵌套將幫助你理解周期。下面的代碼片段來自DocBook stylesheet中的
pi.xsl
文件,舉例說明兩個變量周期的不同。
1 <xsl:template name="dbhtml-attribute"> 2 ... 3 <xsl:choose> 4 <xsl:when test="$count>count($pis)"> 5 <!-- not found --> 6 </xsl:when> 7 <xsl:otherwise> 8 <xsl:variable name="pi"> 9 <xsl:value-of select="$pis[$count]"/> 10 </xsl:variable> 11 <xsl:choose> 12 <xsl:when test="contains($pi,concat($attribute, '='))"> 13 <xsl:variable name="rest" select="substring-after($pi,concat($attribute,'='))"/> 14 <xsl:variable name="quote" select="substring($rest,1,1)"/> 15 <xsl:value-of select="substring-before(substring($rest,2),$quote)"/> 16 </xsl:when> 17 <xsl:otherwise> 18 ... 19 </xsl:otherwise> 20 </xsl:choose> 21 </xsl:otherwise> 22 </xsl:choose> 23 </xsl:template>
變量
pi
的周期開始于第8行,也就是模板定義它的位置,結束于第20行它最后一個同級兄弟結束的地方
[1]。變量
rest
的周期開始于13行,結束與15行。幸運的是,15行的輸出表達式趕在周期結束前使用了變量值。
讓我們來看看當在變量的周期內(nèi)使用
<xsl:apply-templates/>會如何?被應用的模板內(nèi)會得到變量值嗎?答案是否定的。因為被應用的模板生效周期并沒有真正的在變量周期內(nèi),它在
stylesheet
的其它地方退出,并不是在變量的低齡同級和后裔內(nèi)退出。
要想傳值給一個模板,你可以使用
<xsl:with-param/>傳遞一個參數(shù)。這種參數(shù)傳遞通常被用在使用
<xsl:call-templates/>調(diào)用指定模板,盡管你也可以使用
<xsl:apply-templates/>調(diào)用模板,但是通常被調(diào)用的模板希望傳入一個與
<xsl:param/>定義同名的參數(shù)。這樣就可以在模板內(nèi)使用這個參數(shù)值。任何傳入的參數(shù)名如果在模板內(nèi)沒有被定義將被忽略處理。
下面參數(shù)傳遞的例子來自
docbook.xsl
:
<xsl:call-template name="head.content"> <xsl:with-param name="node" select="$doc"/> </xsl:call-template>
上面一個命名為
head.content
的模板被調(diào)用,在調(diào)用周期內(nèi)傳遞了一個名為
node
的參數(shù),參數(shù)值是變量
$doc
。上面被調(diào)用的模板看上去會是下面的樣子:
<xsl:template name="head.content"> <xsl:param name="node" select="."/> ...
模板期望一個參數(shù)是因為模板定義中聲明了一個
<xsl:param/>,并且名字和傳入?yún)?shù)名相同。模板內(nèi)的
<xsl:param/>提供了一個默認值,如果傳入的參數(shù)名沒有與其匹配,那么將在模板內(nèi)使用默認值。