我的 XSLT 中有一個遞回函式。它旨在識別元素的“鏈”,其中鏈被定義為具有 start(n 1)=end(n) 的元素序列,例如:
<!-- first chain starts here -->
<event start="T0" end="T1">doo</event>
<event start="T1" end="T2">doo</event>
<event start="T2" end="T3">doo</event>
<!-- first chain ends here -->
<event start="T4" end="T5">doo</event>
<event start="T5" end="T6">doo</event>
我正在使用以下遞回函式:
<!-- returns latest event that is connected to the given event through an uninterrupted chain of other events -->
<xsl:function name="exmaralda:last-endpoint-of-segment-chain">
<xsl:param name="event"/>
<xsl:choose>
<xsl:when test="not($event/following-sibling::event) or exmaralda:timeline-position($event/following-sibling::event[1]/@start)>exmaralda:timeline-position($event/@end)">
<xsl:value-of select="$event/@end"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="exmaralda:last-endpoint-of-segment-chain($event/following-sibling::event[1])"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
只要事件序列不太長(它們通常包含不超過 10 個元素),這種方法就可以正常作業。但是,如果它們的長度超過某個值,則轉換會引發錯誤“XSLT 中的嵌套函式呼叫過多”。我已經讀過,為了避免這種情況,遞回函式應該是尾遞回的。但是,我不明白為什么我的遞回沒有那個屬性。任何人都可以看到這里可能有什么問題嗎?
我使用 Saxon 9he 作為 XSL 引擎。
uj5u.com熱心網友回復:
您的函式不是尾遞回的原因是尾遞回函式必須按原樣回傳遞回呼叫的結果,無需進一步處理。您的呼叫請求進一步處理:xsl:value-of指令要求將結果轉換為文本節點。
Saxon 有時會發現您并不真正想要這種轉換,但只有在您宣告函式結果的型別時才能這樣做。
因此,您應該對代碼進行兩項改進,這兩項都是標準的良好編碼實踐:(a) 使用xsl:sequence而不是xsl:value-of回傳函式結果,以及 (b) 使用as屬性 on xsl:functionandxsl:param宣告函式引數和結果的型別。
此外,正如 Martin 指出的那樣,在有意義的地方使用xsl:for-each-grouporxsl:iterate而不是遞回函式是一個好主意:它通常使代碼更具可讀性并且通常更有效。
uj5u.com熱心網友回復:
假設 XSLT 3(從 9.8 開始支持)它似乎可以識別您可以使用的“鏈” group-adjacent:
<xsl:template match="events">
<xsl:copy>
<xsl:for-each-group select="event" composite="yes" group-adjacent="@end => substring-after('T') => xs:integer() - position(), @start => substring-after('T') => xs:integer() - (position() 1)">
<chain>
<xsl:sequence select="current-group()"/>
</chain>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
https://xsltfiddle.liberty-development.net/nbspVax
在 XSLT 中使用 可以實作更通用和更精確的宣告性分組實作break-when,目前由 SaxonCS 支持,希望很快由 Saxon 11 支持:
<xsl:template match="events">
<xsl:copy>
<xsl:for-each-group select="event" break-when="$next/@start => substring-after('T') => xs:integer() gt $group[last()]/@end => substring-after('T') => xs:integer()">
<chain>
<xsl:sequence select="current-group()"/>
</chain>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/389013.html
