À partir de XSLT 2.0, pour autant que je sache (corrigez-moi si je me trompe), il n'y a pas de mécanisme natif dans le langage de gestion des exceptions.Techniques de gestion des exceptions XSLT
J'ai quelques feuilles de style qui tentent de faire un traitement sur des morceaux spécifiques d'un document d'entrée, en copiant tout le reste inchangé. Il y a des conditions exceptionnelles rares que je ne peux pas facilement détecter avant que je commence à produire la production pour un morceau donné. Celles-ci sont suffisamment rares pour que, lorsque je les rencontre, tout ce que je veux faire est d'annuler le traitement sur ce morceau et de l'émettre sans modification. Une sorte de gestion des exceptions est en ordre, mais XSLT n'aide pas beaucoup. Je ne veux pas avoir Java ou une autre langue dans le mix ici.
J'ai une solution réalisable décrite ci-dessous, mais je m'interroge sur d'autres approches. Avez-vous tous une meilleure façon de faire quelque chose comme ça?
Voici un exemple du genre de scénario dont je parle. Voici un document d'entrée:
<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>
Je souhaite parcourir chaque table et remplacer toutes les valeurs de cellule 'a' par 'B'. Cependant, s'il y a un 'x' quelque part dans la table, je veux juste copier la table non modifiée. Je sais que dans ce cas, je pourrais juste faire un test tr/td[.='x']
sur la table pour découvrir cette condition. Dans le cas réel, cependant, il n'est pas si facile de tester à l'avance pour la condition.
Voici quelques XSLT qui ne tient pas compte de l'exception:
<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>
La sortie de c'est:
<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>
Il a fait les substitutions dans la deuxième table, que je ne vouloir.
Ma solution actuelle est de le faire:
- émettons chaque table dans une variable au lieu de directement dans la sortie
- Si l'exception se produit, émettent une étiquette
<EXCEPTION/>
- Après chaque table est traitée , parcourez la variable pour la balise
<EXCEPTION/>
. - Si l'exception s'est produite, copiez la table d'origine, sinon copiez le contenu de la variable.
Voici le code modifié:
<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>
Et la sortie correcte:
<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>
Ici, il n'y a pas d'exception. C'est la beauté du paradigme déclaratif sans effet secondaire. Toutes les fonctions qui peuvent tomber dans les effets secondaires ont un test aviable. Ici vous avez un processus différent pour les différents schémas d'éléments. Comme vous l'avez écrit, à chaque fois qu'il est possible d'utiliser la correspondance de motifs, faites-le. Il peut y avoir des cas où cela est difficile ou pas optimal. Ensuite, un processus en deux étapes sur les arbres de résultats temporaires est le chemin, comme votre exemple. –
@ Steven-Ourada, @ Nick-Jones et @Alejandro: Bonne question (+1). Voir ma réponse pour une solution * très simple * qui n'a pas besoin d'un mécanisme try/catch :) Pour les cas * très complexes * où les exceptions peuvent vraiment être utiles, vous devez attendre XSLT 3.0. –