從XSLT 2.0開始,據我所知(糾正我,如果我錯了),在異常處理語言中沒有本機機制。處理XSLT異常的技巧
我有一些樣式表試圖對指定的輸入文檔塊進行一些處理,而其他所有內容都是不變的。在我開始爲給定的塊創建輸出之前,我很難檢測到罕見的特殊情況。這些非常罕見,當我遇到它們時,我想要做的就是取消這個塊上的處理,並且不改變它。某種異常處理是按順序進行的,但XSLT對此幫助不大。我不想在這裏混入Java或其他語言。
我有一個可行的解決方案如下所述,但我想知道其他方法。你們都有更好的方式來做這樣的事情嗎?
下面是我談論的那種場景的一個例子。這裏是一個輸入文件:
<doc>
<block>some text, just copy.</block>
<!-- the following table should have B substituted for a -->
<table>
<tr><td>a</td><td>b</td><td>c</td></tr>
<tr><td>b</td><td>a</td><td>c</td></tr>
<tr><td>b</td><td>c</td><td>a</td></tr>
</table>
<block>some more text, just copy.</block>
<!-- the following table should be copied unaltered because of the presence of an x -->
<table>
<tr><td>a</td><td>b</td><td>c</td></tr>
<tr><td>b</td><td>a</td><td>x</td></tr>
<tr><td>b</td><td>c</td><td>a</td></tr>
</table>
</doc>
我想查看每個表,並用'B'替換所有的單元格值'a'。但是,如果表中某處有'x',我想只修改表格而不修改。我知道在這種情況下,我可以在桌上做一個tr/td[.='x']
測試來發現這種情況。但在實際情況中,提前測試條件並不容易。
下面是一些XSLT不佔例外:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="table">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates mode="inner"/>
</xsl:copy>
</xsl:template>
<xsl:template mode="inner" match="td">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:choose>
<xsl:when test=". = 'a'">
<xsl:value-of select="'B'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
<xsl:template mode="inner" match="@*|node()" priority="-10">
<xsl:copy>
<xsl:apply-templates mode="inner" select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()" priority="-10">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
的輸出是:
<doc>
<block>some text, just copy.</block>
<!-- the following table should have B substituted for a -->
<table>
<tr><td>B</td><td>b</td><td>c</td></tr>
<tr><td>b</td><td>B</td><td>c</td></tr>
<tr><td>b</td><td>c</td><td>B</td></tr>
</table>
<block>some more text, just copy.</block>
<!-- the following table should be copied unaltered because of the presence of an x -->
<table>
<tr><td>B</td><td>b</td><td>c</td></tr>
<tr><td>b</td><td>B</td><td>x</td></tr>
<tr><td>b</td><td>c</td><td>B</td></tr>
</table>
</doc>
它確實在第二個表中的換人,我不想。
我的當前的解決方案是要做到這一點:
- 散發出每個表成可變的,而不是直接進入輸出
- 如果發生異常,發出
<EXCEPTION/>
標籤 - 每個表進行處理後,查看
<EXCEPTION/>
標籤的變量。 - 如果發生異常,請複製原始表格,否則複製變量的內容。
下面是修改後的代碼:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="table">
<xsl:variable name="result">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates mode="inner"/>
</xsl:copy>
</xsl:variable>
<xsl:choose>
<xsl:when test="$result//EXCEPTION">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template mode="inner" match="td">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:choose>
<xsl:when test=". = 'a'">
<xsl:value-of select="'B'"/>
</xsl:when>
<xsl:when test=". = 'x'">
<EXCEPTION/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
<xsl:template mode="inner" match="@*|node()" priority="-10">
<xsl:copy>
<xsl:apply-templates mode="inner" select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()" priority="-10">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
和正確的輸出:
<doc>
<block>some text, just copy.</block>
<!-- the following table should have B substituted for a -->
<table>
<tr><td>B</td><td>b</td><td>c</td></tr>
<tr><td>b</td><td>B</td><td>c</td></tr>
<tr><td>b</td><td>c</td><td>B</td></tr>
</table>
<block>some more text, just copy.</block>
<!-- the following table should be copied unaltered because of the presence of an x -->
<table>
<tr><td>a</td><td>b</td><td>c</td></tr>
<tr><td>b</td><td>a</td><td>x</td></tr>
<tr><td>b</td><td>c</td><td>a</td></tr>
</table>
</doc>
這裏沒有例外的東西。這是關於副作用自由說明性範式的美妙之處。所有可能會陷入副作用的功能都有一個可怕的測試。在這裏,您針對不同的元素模式有不同的過程。正如你所寫的,只要有可能使用模式匹配,就去做吧。可能有些情況下,這是困難的或不是最佳的。然後,以臨時結果樹爲基礎的兩步處理就是你的例子。 – 2010-09-23 23:25:43
@ Steven-Ourada,@ Nick-Jones和@Alejandro:好問題(+1)。看到我的答案是一個*非常簡單*的解決方案,不需要try/catch機制:)對於非常複雜的情況,例外可能真的很有用,您必須等待XSLT 3.0。 – 2010-09-25 17:20:49