{"id":523,"date":"2010-09-23T16:17:28","date_gmt":"2010-09-23T22:17:28","guid":{"rendered":"http:\/\/www.ourada.org\/blog\/?p=523"},"modified":"2010-09-23T16:17:28","modified_gmt":"2010-09-23T22:17:28","slug":"xslt-exceptions","status":"publish","type":"post","link":"https:\/\/www.ourada.org\/blog\/archives\/523","title":{"rendered":"XSLT exceptions"},"content":{"rendered":"<p>As of XSLT 2.0, and as-far-as-I-know-correct-me-if-I&#8217;m-wrong, there&#8217;s no native mechanism in the language for exception handling. (<strong>Update:<\/strong> although that&#8217;s still true, I should have looked at <a href=\"http:\/\/www.w3.org\/TR\/xslt-21\/#try-catch\">2.1<\/a> or <a href=\"http:\/\/www.saxonica.com\/documentation\/extensions\/instructions\/catch.html\">Saxon&#8217;s extension<\/a>. Though I&#8217;m still going with this method because I don&#8217;t have 2.1 and I&#8217;m not using the EE version of Saxon.)<\/p>\n<p>I have some stylesheets that attempt to do some processing on specified chunks of an input document, copying everything else unaltered. There are rare exceptional conditions that I can&#8217;t easily detect before I start producing output for a given chunk. These are rare enough that when I encounter them, all I want to do is cancel processing on this chunk and emit it unaltered. Some sort of exception handling is in order, but XSLT doesn&#8217;t help very much.<\/p>\n<p>Here&#8217;s an example of the sort of scenario I&#8217;m talking about. Here&#8217;s an input document:<br \/>\n[xml]<br \/>\n&lt;doc&gt;<br \/>\n\t&lt;block&gt;some text, just copy.&lt;\/block&gt;<br \/>\n\t&lt;!&#8211; the following table should have B substituted for a &#8211;&gt;<br \/>\n\t&lt;table&gt;<br \/>\n\t\t&lt;tr&gt;&lt;td&gt;a&lt;\/td&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n\t\t&lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;a&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n\t\t&lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;td&gt;a&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n\t&lt;\/table&gt;<br \/>\n\t&lt;block&gt;some more text, just copy.&lt;\/block&gt;<br \/>\n\t&lt;!&#8211; the following table should be copied unaltered because of the presence of an x &#8211;&gt;<br \/>\n\t&lt;table&gt;<br \/>\n\t\t&lt;tr&gt;&lt;td&gt;a&lt;\/td&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n\t\t&lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;a&lt;\/td&gt;&lt;td&gt;x&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n\t\t&lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;td&gt;a&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n\t&lt;\/table&gt;<br \/>\n&lt;\/doc&gt;<br \/>\n[\/xml]<\/p>\n<p>I want to look through each table and replace all cell values &#8216;a&#8217; with &#8216;B&#8217;. However, if there&#8217;s an &#8216;x&#8217; somewhere in the table, I want to just copy the table unmodified. I know that in this case, I could just do a <code>tr\/td[.='x']<\/code> test on the table to discover this condition. In the real case, though, it&#8217;s not so easy to test ahead of time for the condition.<\/p>\n<p>Here&#8217;s some XSLT that doesn&#8217;t account for the exception:<br \/>\n[xslt]<br \/>\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br \/>\n&lt;xsl:stylesheet version=&quot;2.0&quot;<br \/>\n\txmlns:xsl=&quot;http:\/\/www.w3.org\/1999\/XSL\/Transform&quot;&gt;<\/p>\n<p>\t&lt;xsl:template match=&quot;table&quot;&gt;<br \/>\n\t\t&lt;xsl:copy&gt;<br \/>\n\t\t\t&lt;xsl:copy-of select=&quot;@*&quot;\/&gt;<br \/>\n\t\t\t&lt;xsl:apply-templates mode=&quot;inner&quot;\/&gt;<br \/>\n\t\t&lt;\/xsl:copy&gt;<br \/>\n\t&lt;\/xsl:template&gt;<\/p>\n<p>\t&lt;xsl:template mode=&quot;inner&quot; match=&quot;td&quot;&gt;<br \/>\n\t\t&lt;xsl:copy&gt;<br \/>\n\t\t\t&lt;xsl:copy-of select=&quot;@*&quot;\/&gt;<br \/>\n\t\t\t&lt;xsl:choose&gt;<br \/>\n\t\t\t\t&lt;xsl:when test=&quot;. = &#8216;a&#8217;&quot;&gt;<br \/>\n\t\t\t\t\t&lt;xsl:value-of select=&quot;&#8217;B&#8217;&quot;\/&gt;<br \/>\n\t\t\t\t&lt;\/xsl:when&gt;<br \/>\n\t\t\t\t&lt;xsl:otherwise&gt;<br \/>\n\t\t\t\t\t&lt;xsl:value-of select=&quot;.&quot;\/&gt;<br \/>\n\t\t\t\t&lt;\/xsl:otherwise&gt;<br \/>\n\t\t\t&lt;\/xsl:choose&gt;<br \/>\n\t\t&lt;\/xsl:copy&gt;<br \/>\n\t&lt;\/xsl:template&gt;<\/p>\n<p>\t&lt;xsl:template mode=&quot;inner&quot; match=&quot;@*|node()&quot; priority=&quot;-10&quot;&gt;<br \/>\n\t\t&lt;xsl:copy&gt;<br \/>\n\t\t\t&lt;xsl:apply-templates mode=&quot;inner&quot; select=&quot;@*|node()&quot;\/&gt;<br \/>\n\t\t&lt;\/xsl:copy&gt;<br \/>\n\t&lt;\/xsl:template&gt;<\/p>\n<p>\t&lt;xsl:template match=&quot;@*|node()&quot; priority=&quot;-10&quot;&gt;<br \/>\n\t\t&lt;xsl:copy&gt;<br \/>\n\t\t\t&lt;xsl:apply-templates select=&quot;@*|node()&quot;\/&gt;<br \/>\n\t\t&lt;\/xsl:copy&gt;<br \/>\n\t&lt;\/xsl:template&gt;<br \/>\n&lt;\/xsl:stylesheet&gt;<br \/>\n[\/xslt]<\/p>\n<p>The output of that is:<br \/>\n[xml]<br \/>\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;doc&gt;<br \/>\n    &lt;block&gt;some text, just copy.&lt;\/block&gt;<br \/>\n    &lt;!&#8211; the following table should have B substituted for a &#8211;&gt;<br \/>\n    &lt;table&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;B&lt;\/td&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;B&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;td&gt;B&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n    &lt;\/table&gt;<br \/>\n    &lt;block&gt;some more text, just copy.&lt;\/block&gt;<br \/>\n    &lt;!&#8211; the following table should be copied unaltered because of the presence of an x &#8211;&gt;<br \/>\n    &lt;table&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;B&lt;\/td&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;B&lt;\/td&gt;&lt;td&gt;x&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;td&gt;B&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n    &lt;\/table&gt;<br \/>\n&lt;\/doc&gt;<br \/>\n[\/xml]<\/p>\n<p>(it did the substitutions in the second table, which I don&#8217;t want.)<\/p>\n<p>My current solution is to do this:<\/p>\n<ol>\n<li>Emit each table into a variable instead of directly into the output<\/li>\n<li>If the exception occurs, emit an &lt;EXCEPTION\/&gt; tag<\/li>\n<li>After each table is processed, look through the variable for the &lt;EXCEPTION\/&gt; tag.<\/li>\n<li>If the exception happened, copy the original table, else copy the contents of the variable.<\/li>\n<\/ol>\n<p>Here&#8217;s the modified code and output:<br \/>\n[xslt]<br \/>\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br \/>\n&lt;xsl:stylesheet version=&quot;2.0&quot;<br \/>\n    xmlns:xsl=&quot;http:\/\/www.w3.org\/1999\/XSL\/Transform&quot;&gt;<\/p>\n<p>    &lt;xsl:template match=&quot;table&quot;&gt;<br \/>\n        &lt;xsl:variable name=&quot;result&quot;&gt;<br \/>\n            &lt;xsl:copy&gt;<br \/>\n                &lt;xsl:copy-of select=&quot;@*&quot;\/&gt;<br \/>\n                &lt;xsl:apply-templates mode=&quot;inner&quot;\/&gt;<br \/>\n            &lt;\/xsl:copy&gt;<br \/>\n        &lt;\/xsl:variable&gt;<br \/>\n        &lt;xsl:choose&gt;<br \/>\n            &lt;xsl:when test=&quot;$result\/\/EXCEPTION&quot;&gt;<br \/>\n                &lt;xsl:copy-of select=&quot;.&quot;\/&gt;<br \/>\n            &lt;\/xsl:when&gt;<br \/>\n            &lt;xsl:otherwise&gt;<br \/>\n                &lt;xsl:copy-of select=&quot;$result&quot;\/&gt;<br \/>\n            &lt;\/xsl:otherwise&gt;<br \/>\n        &lt;\/xsl:choose&gt;<br \/>\n    &lt;\/xsl:template&gt;<\/p>\n<p>    &lt;xsl:template mode=&quot;inner&quot; match=&quot;td&quot;&gt;<br \/>\n        &lt;xsl:copy&gt;<br \/>\n            &lt;xsl:copy-of select=&quot;@*&quot;\/&gt;<br \/>\n            &lt;xsl:choose&gt;<br \/>\n                &lt;xsl:when test=&quot;. = &#8216;a&#8217;&quot;&gt;<br \/>\n                    &lt;xsl:value-of select=&quot;&#8217;B&#8217;&quot;\/&gt;<br \/>\n                &lt;\/xsl:when&gt;<br \/>\n                &lt;xsl:when test=&quot;. = &#8216;x&#8217;&quot;&gt;<br \/>\n                    &lt;EXCEPTION\/&gt;<br \/>\n                &lt;\/xsl:when&gt;<br \/>\n                &lt;xsl:otherwise&gt;<br \/>\n                    &lt;xsl:value-of select=&quot;.&quot;\/&gt;<br \/>\n                &lt;\/xsl:otherwise&gt;<br \/>\n            &lt;\/xsl:choose&gt;<br \/>\n        &lt;\/xsl:copy&gt;<br \/>\n    &lt;\/xsl:template&gt;<\/p>\n<p>    &lt;xsl:template mode=&quot;inner&quot; match=&quot;@*|node()&quot; priority=&quot;-10&quot;&gt;<br \/>\n        &lt;xsl:copy&gt;<br \/>\n            &lt;xsl:apply-templates mode=&quot;inner&quot; select=&quot;@*|node()&quot;\/&gt;<br \/>\n        &lt;\/xsl:copy&gt;<br \/>\n    &lt;\/xsl:template&gt;<\/p>\n<p>    &lt;xsl:template match=&quot;@*|node()&quot; priority=&quot;-10&quot;&gt;<br \/>\n        &lt;xsl:copy&gt;<br \/>\n            &lt;xsl:apply-templates select=&quot;@*|node()&quot;\/&gt;<br \/>\n        &lt;\/xsl:copy&gt;<br \/>\n    &lt;\/xsl:template&gt;<br \/>\n&lt;\/xsl:stylesheet&gt;<br \/>\n[\/xslt]<\/p>\n<p>[xml]<br \/>\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;doc&gt;<br \/>\n    &lt;block&gt;some text, just copy.&lt;\/block&gt;<br \/>\n    &lt;!&#8211; the following table should have B substituted for a &#8211;&gt;<br \/>\n    &lt;table&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;B&lt;\/td&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;B&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;td&gt;B&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n    &lt;\/table&gt;<br \/>\n    &lt;block&gt;some more text, just copy.&lt;\/block&gt;<br \/>\n    &lt;!&#8211; the following table should be copied unaltered because of the presence of an x &#8211;&gt;<br \/>\n    &lt;table&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;a&lt;\/td&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;a&lt;\/td&gt;&lt;td&gt;x&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n        &lt;tr&gt;&lt;td&gt;b&lt;\/td&gt;&lt;td&gt;c&lt;\/td&gt;&lt;td&gt;a&lt;\/td&gt;&lt;\/tr&gt;<br \/>\n    &lt;\/table&gt;<br \/>\n&lt;\/doc&gt;<br \/>\n[\/xml]<\/p>\n<p>It works, but I&#8217;m still wondering if there&#8217;s a better approach&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As of XSLT 2.0, and as-far-as-I-know-correct-me-if-I&#8217;m-wrong, there&#8217;s no native mechanism in the language for exception handling. (Update: although that&#8217;s still true, I should have looked at 2.1 or Saxon&#8217;s extension. Though I&#8217;m still going with this method because I don&#8217;t have 2.1 and I&#8217;m not using the EE version of Saxon.) I have some stylesheets [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-523","post","type-post","status-publish","format-standard","hentry","category-general","author-admin"],"_links":{"self":[{"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/posts\/523","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/comments?post=523"}],"version-history":[{"count":0,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/posts\/523\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/media?parent=523"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/categories?post=523"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ourada.org\/blog\/wp-json\/wp\/v2\/tags?post=523"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}