XSLT exception handling methods

As in XSLT 2.0, as far as I know (correct me if Im wrong), theres no built-in mechanism in the language for handling exceptions.

I have several stylesheets that are trying to do some processing on certain pieces of the input document, copying everything else unchanged. There are rare exceptional conditions that I cannot detect before I begin to make a conclusion for a given piece. They are rare enough that when I come across them, all I want to do is cancel the processing on this piece and fix it unchanged. Some exception handling is fine, but XSLT doesn't help much. I do not want to get Java or another language in the mix here.

I have a workable solution, described below, but I'm curious about other approaches. Do you have a better way to do something like this?

Here is an example of the scenario I'm talking about. Here is the input document:

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

I want to look at each table and replace all the values โ€‹โ€‹of cell โ€œaโ€ with โ€œB. However, if theres somewhere in the table, I just want to copy the table without changes. I know that in this case I could just do the tr/td[.='x'] test tr/td[.='x'] in the table to detect this condition. In the real case, however, it is not so simple to check in advance for the condition.

Here is some XSLT that does not take exception into account:

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

Result:

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

This was done by substitutions in the second table, which I do not want.

My current solution is to do this:

  • Extract each table to a variable, not directly to the output file
  • If an exception occurs, emit the <EXCEPTION/>
  • After processing each table, review the variable for the <EXCEPTION/> .
  • If an exception occurs, copy the source table, otherwise copy the contents of the variable.

Has a modified code:

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

And the correct conclusion:

 <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> 
+4
source share
2 answers

If you can wait for XSLT 2.1 then there will be try / catch expressions

+1
source

The above example is very simple and does not need any exception handling capabilities.

The mode attribute is your friend :

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

when this conversion is applied to the provided XML document :

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

required, the correct result is obtained :

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

If exceptions are really needed (we still need to see a good use case), they will be standard in XSLT 3.0 .

+1
source

All Articles