从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