2014-03-25 49 views
4

我喜歡認爲我對XSLT有很好的把握,但以下回避我: 爲什麼xsl:param無法從被稱爲模板的明確聲明?換句話說,如果我叫B模版從模板:關於呼叫模板的參數中的「上下文」的含義

樣式表1

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="/" name="A"><!--This template is named "A" for convenience only.--> 
     <xsl:param name="hello" select="hello "/> 
     <xsl:param name="world" select="world!"/> 
     <xsl:call-template name="B"/> 
    </xsl:template> 

    <xsl:template name="B"> 
     <xsl:value-of select="concat($hello,$world)"/> 
    </xsl:template> 

</xsl:stylesheet> 

爲什麼B模版不會自動採用模板的參數作爲背景的一部分嗎?我的理由如下。

顯然,調用模板不以任何方式影響的背景下:

選定<xsl:template>與沒有變化的背景下評價:它使用相同的上下文項,上下文位置和上下文大小調用模板


現在,是什麼 「背景」 實際上意味着在XSLT,以上PREC isely,是否被認爲是上下文的一部分?間形成的上下文中的東西是:

  • 所有變量聲明(xsl:variablexsl:param),它們在其中表達被評爲點範圍,因爲所述靜態上下文
  • 的值的一部分

    :在範圍上的所有變量,如動力方面

的一部分,這使我相信,下面的樣式表等於我已經展示了第一個

樣式表2

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="/" name="A"> 
     <xsl:param name="hello" select="hello "/> 
     <xsl:param name="world" select="world!"/> 
     <xsl:value-of select="concat($hello,$world)"/> 
    </xsl:template> 

</xsl:stylesheet> 

但是obvously,只有第二個是正確的,而第一個產生約缺少變量聲明兩個錯誤。爲什麼必須在調用的模板中明確聲明參數,如果模板調用不會更改上下文並且參數被視爲上下文的一部分?

爲清楚:

  • 我知道如何修改第一個樣式表與xsl:with-param和參數聲明 - 這是不是我要求的。
  • 我知道XSLT 2.0中的tunnel parameters - 你不必解釋它們或者建議它們作爲替代。我不是要求在模板中使用參數的方式,但是他們沒有聲明 - 我想知道爲什麼他們不能在第一時間使用。

1我的重點。請參閱XSLT 2.0程序員參考,Michael Kay,第273頁。
2參見規範here的相關部分或參考Michael Kay的XSLT 2.0程序員參考,頁面84f。

回答

4

優秀的問題,好的問。

您期望的行爲在具有動態範圍的語言中會很自然。但XSLT對變量使用詞法作用域,而不是動態作用域。

你問現在,「上下文」在XSLT中究竟意味着什麼,或者更確切地說,是一個被認爲是上下文的一部分的參數呢?

簡短回答:是的,參數是靜態上下文的一部分,用於其範圍內的表達式(並且缺失是關於樣式表中其他地方表達式的靜態上下文的事實);它的值是其範圍內表達式的動態上下文的一部分。並且(至關重要的)xsl:call-template指令確實會影響評估表達式的上下文。

較長的答案:具體細節請參見the XSLT 2.0 spec。規範告訴我們,在section 2.5中,上下文分爲兩部分:靜態上下文和動態上下文。 Section 5.4提供全部細節; section 5.4.1將「範圍內變量」列爲靜態上下文的一個組件。

變量的作用域規則在section 9.7中給出。關鍵的一點是:

局部變量綁定元素後面的所有兄弟姐妹和他們的後代,但有兩個例外可見:它是不可見在它被另一個變量綁定陰影的任何區域,它是在以變量綁定元素的兄弟節點xsl:fallback指令爲根的子樹中不可見。

您遇到的明顯矛盾很大程度上依賴於「調用模板不影響上下文」的前提。儘管事實上你擁有非常好的權威,但這個前提並不正確。

section 10.1,規範說「xsl:call-template指令不會改變焦點。」它並不是說該指令不會影響上下文。

在你引用Michael Kay的書的段落中,我認爲術語「上下文」最適合作爲「上下文項」或「動態上下文」的縮寫。即使在閱讀時,句子也不完全正確:因爲上下文的dynamic variables組件不同,被調用模板中的動態上下文與調用模板中的動態上下文不完全相同。我認爲你必須在這裏削減MK一些鬆懈:所討論的段落與他的書的XSLT 1.0版本基本不變,而在XSLT 1.0中,在討論上下文時沒有明確表示,變量和參數給名稱。但我認爲可以公平地說,你已經在MK可能希望在下一次修訂中改變的書中找到了一些東西。

+0

優秀的答案 - 我一直在等待的那個:-)。 –

0

調用另一個模板不會改變上下文;但它確實會更改範圍。您不再處於調用模板中,因此在調用模板中聲明的變量不適用於當前調用模板。

+0

我指的是表達式的「上下文」,無論正在處理的文檔如何,該表達式都有明確的定義。您能否指出我的推理中存在的缺陷:範圍內的參數被認爲是上下文的一部分,「call-template」被「評估爲不改變上下文」。那麼,爲什麼我不能使用調用模板的參數,而沒有在被調用的模板中再次顯式聲明它們? –

+0

換句話說,你是說範圍不是傳遞給被調用模板的上下文的一部分。爲什麼不,規則是什麼?如果你能找到解釋它的規範的一部分,我將不勝感激。 –

+0

我只是編輯了我答案的那一部分。無論如何,我相信調用模板中定義的參數並不在被調用模板的「範圍內」。看起來你所指的背景的定義對於這種情況來說過於寬泛。 –

2

您需要區分contextfocushttp://www.w3.org/TR/xslt20/#dt-focus。當您使用call-template時,焦點不會更改,請參閱http://www.w3.org/TR/xslt20/#element-call-template其中說「與xsl:apply-templates不同,xsl:call-template指令不會更改焦點。」。

+0

你能詳細說明一下嗎?你的意思是'call-template'確實不會改變焦點,但總體上來說會改變上下文嗎?那麼,如何解釋上下文的其他組件(如當前模式或當前模板規則(不屬於焦點))在被調用的模板中保持不變? –

+0

是的,'呼叫模板'不會改變焦點,是的,評估所選模板的上下文在某些方面與呼叫模板的不同。當前模式和當前模板規則不變,因爲[5.4.4]節(http://www.w3.org/TR/xslt20/#additional-dynamic-context)中的規則在調用模板中爲它們分配了相同的值和被調用的命名模板。 –

5

http://www.w3.org/TR/xslt20/#static-context

的調查範圍內的變量由可變結合元件 是在範圍爲包含元素定義(參見9個變量和 參數)。

http://www.w3.org/TR/xslt20/#dt-variable-binding-element

The two elements xsl:variable and xsl:param are referred to as variable-binding elements 

所以,纔可以使用,你必須約束他們,使他們在靜態情況下可用的變量,否則你的XSLT程序將無法編譯。


只有綁定它們時,參數纔在範圍內。爲什麼?因爲它是這樣設計的。

所選<xsl:template>與不改變 上下文中計算:它使用相同的上下文項,上下文位置和上下文 大小與調用模板

上面的語句不是100%準確。使用xsl:call-template會保留一些dynamic context(如上下文項,上下文位置和上下文大小),但會更改從靜態上下文的範圍內變量中獲取的變量值。 每個XPath表達式都有一個靜態和動態的上下文。在XSLT中,表達式的靜態上下文取決於包含和封閉的元素。


的XPath約focus

動態上下文的前三個組分(上下文項,上下文位置和上下文大小)被稱爲表達式的焦點。焦點使處理器能夠跟蹤表達式正在處理哪些項目。

XSLT約focus

當順序構造進行評價時,所述處理器跟蹤哪些物品正在被一組隱變量的裝置處理統稱爲焦點。

當你調用xsl:call-template你正在評估一個順序構造。因爲,與xsl:apply-templatesxsl:for-each不同,xsl:call-template不會更改正在處理的項目,焦點沒有變化。

但是,您正在評估的序列構造函數是一個不同的模板,並且由於模板不嵌套在XSLT中,因此模板內使用的XPath表達式具有與另一個模板中使用的表達式不同的範圍內變量。當您使用xsl:for-each時,這不是問題,它會改變焦點但保留範圍內的變量。

在XSLT中,表達式的靜態上下文取決於包含和封閉的元素。

+0

您能否準確回答我所要求的答案?也就是說,爲什麼調用模板不會影響上下文並且參數是上下文的一部分,爲什麼調用模板中的參數在被調用模板中不可用而又沒有顯式重新聲明它們。 –

+0

你對邁克爾凱的評論有什麼理解:「選定的[命名的] 是否被評估爲」不改變上下文「? –

+0

@MathiasMüller更新了我的回答 –

3

恐怕您從XSLT 2.0 Prog Ref引用的段落不夠精確;它使用「上下文」作爲「動態上下文」的快捷方式。編寫這樣一本書會帶來危險,如果你的寫作過於精確和迂腐,就很難像實際的語言規範那樣閱讀,而如果你偷工減料,那些追求精確性的人可能會被誤導。關鍵在於變量引用只能引用在範圍內(靜態)的變量。被調用的模板(它定義了哪些變量在範圍內)的靜態上下文當然完全不同於調用模板指令的靜態上下文。

+0

感謝您的回答。當然,我並不打算批評你的書,而是要理解XSLT的內部工作原理。我是否正確地認爲,當調用模板的參數通過'with-param'傳遞給被調用模板並在那裏聲明時,它會被添加到被調用模板的靜態上下文中? –