Начиная с 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". Однако если где-то в таблице есть «х», я хочу просто скопировать таблицу без изменений. Я знаю, что в этом случае я мог бы просто провести тест 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>