XSLT异常处理技术

时间:2010-09-23 22:45:04

标签: xslt exception-handling

从XSLT 2.0开始,据我所知(如果我错了,请纠正我),异常处理语言中没有本机机制。

我有一些样式表尝试在输入文档的指定块上进行一些处理,复制其他所有未更改的内容。在开始为给定块生成输出之前,我无法轻易检测到罕见的异常情况。这些是非常罕见的,当我遇到它们时,我想要做的就是取消对这个块的处理并且不加改变地发出它。某种异常处理是有序的,但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>

我想查看每个表并将所有单元格值'a'替换为'B'。但是,如果表格中有某个'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>

它在第二个表中进行了替换,我不想这样做。

我目前的解决方案是:

  1. 将每个表发送到变量而不是直接发送到输出
  2. 如果发生异常,请发出<EXCEPTION/>标记
  3. 处理完每个表后,请查看<EXCEPTION/>标记的变量。
  4. 如果发生异常,请复制原始表,否则复制变量的内容。
  5. 以下是修改后的代码:

    <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>
    

2 个答案:

答案 0 :(得分:1)

如果您可以等待XSLT 2.1,那么将会有try / catch表达式

答案 1 :(得分:1)

提供的示例非常简单,不需要任何异常处理功能。

mode 属性是您的朋友

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output omit-xml-declaration="yes"/>

 <xsl:template match="node()|@*" mode="#default copy">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*" mode="#current"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="table[tr/td[.='x']]">
  <xsl:apply-templates select="." mode="copy"/>
 </xsl:template>

 <xsl:template match="td/text()[.='a']">B</xsl:template>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<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>

产生了想要的正确结果

<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>

如果确实需要例外(我们还需要查看一个好的用例),它们将成为XSLT 3.0 的标准。