其他人已經解釋如何變量是不可變的 - 有在XSLT沒有賦值語句(如一般而言,純函數式編程語言)。
我有迄今爲止提出的解決方案的替代方案。它避免了參數傳遞(在XSLT中冗長而醜陋 - 即使我承認這一點)。
在XPath,你可以簡單地計算它之前<section>
元素的當前數量:
<xsl:template name="section">
<span class="title" id="title-{1 + count(preceding-sibling::section)}">
<xsl:value-of select="title"/>
</span>
</xsl:template>
(注:空格代碼格式化不會出現在你的結果,因爲只有空白文本節點因此不要強迫將指令放在同一行上)
這種方法的一大優點(與使用position()
相反)是它僅依賴於當前節點,而不依賴於當前節點在當前節點列表上。如果您以某種方式更改了處理過程(例如,<xsl:for-each>
不僅處理了部分,而且還處理了其他一些元素),那麼position()
的值將不再需要與文檔中<section>
元素的位置相對應。另一方面,如果您使用上面的count()
,那麼它將始終對應於每個元素的位置。這種方法減少了與代碼的其他部分的耦合,這通常是非常好的事情。
count()的替代方法是使用<xsl:number>
指令。這是默認的行爲將在同一水平線上,這恰好是你想要的號碼的所有名稱相似的元素:
<xsl:template name="section">
<xsl:variable name="count">
<xsl:number/>
</xsl:variable>
<span class="title" id="title-{$count}">
<xsl:value-of select="title"/>
</span>
</xsl:template>
這是一個權衡冗長(無需額外的變量聲明,如果你仍然想使用屬性值模板花括號),但只是稍微如此,因爲它也極大地簡化了XPath表達式。
還有更多的改進空間。雖然我們已經取消了對當前節點列表的依賴,但仍然依賴於當前節點。這本身並不是一件壞事,但從模板看當前節點是什麼並不明顯。我們所知道的是該模板被命名爲「section
」;要確切知道正在處理的內容,我們必須查看我們的代碼中的其他地方。但即便如此,情況也不一定如此。
如果你曾經感覺到一起使用<xsl:for-each>
和<xsl:call-template>
(如你的例子),退後一步,並找出如何使用<xsl:apply-templates>
來代替。
<xsl:template match="/doc">
<xsl:apply-templates select="section"/>
</xsl:template>
<xsl:template match="section">
<xsl:variable name="count">
<xsl:number/>
</xsl:variable>
<span class="title" id="title-{$count}">
<xsl:value-of select="title"/>
</span>
</xsl:template>
這不僅是方法更簡潔(<xsl:apply-templates/>
取代了<xsl:for-each>
和<xsl:call-template/>
),但它也立即變得明確當前節點是什麼。您只需查看match
屬性,即刻知道您正在處理的元素爲<section>
,並且您要計算的元素爲<section>
。
有關如何使用模板規則(即<xsl:template>
屬性具有match
屬性)的簡明說明,請參閱"How XSLT Works"。
非常感謝你!這篇文章和回答非常有幫助 – anpatel 2012-01-25 22:07:58
不客氣!很高興你發現它很有用。 – 2012-02-03 18:27:47
對不起,埃文,但這是一個非常低效的解決方案(O(N^2))。使用參數傳遞的解決方案只能是O(N)。所有這些關於「冗長」的討論都只是這個 - 冗長而沒有提到關於效率的字眼。如果您提到所提議的解決方案的時間複雜性並將其與其他可能的解決方案進行比較,則可以使讀者更有用。由於這些原因,我認爲這個答案屬於輕型教程類型,不適用於生產工作。 – 2012-07-26 03:44:28