Re: [xsl] XSLT 3.0 try/catch doubts

Subject: Re: [xsl] XSLT 3.0 try/catch doubts
From: "Mukul Gandhi gandhi.mukul@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 25 Feb 2019 09:58:42 -0000
Hi Mike,
    Thanks for a detailed explanation about my XSLT use case. I've now
tried new ways of using XSLT try/catch syntax, and below are my new
examples where try/catch appear to be more useful in the context of my
examples. I'm using Saxon 9.9.

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<test>
   <val>5</val>
   <val>4</val>
   <val>3</val>
   <val>0</val>
   <val>2</val>
   <val>0</val>
   <val>1</val>
</test>

Stylesheet 1:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";

                         xmlns:err="http://www.w3.org/2005/xqt-errors";
                         xmlns:fn="http://xslt-functions";
                         xmlns:xs="http://www.w3.org/2001/XMLSchema";
                         exclude-result-prefixes="err fn xs"
                         version="3.0">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
       <result>
          <xsl:for-each select="test/val">
             <xsl:copy-of select="fn:div(5, ., position())"/>
          </xsl:for-each>
       </result>
    </xsl:template>

    <xsl:function name="fn:div" as="element()">
       <xsl:param name="numerator" as="xs:integer"/>
       <xsl:param name="denominator" as="xs:integer"/>
       <xsl:param name="pos" as="xs:integer"/>

       <xsl:try>
          <xsl:sequence>
     <div num="{$numerator}" denom="{$denominator}"><xsl:value-of
select="$numerator div $denominator"/></div>
          </xsl:sequence>
          <xsl:catch errors="*">
             <xsl:sequence>
       <error val_pos="{$pos}" document="{$err:module}" code="{$err:code}"
description="{$err:description}" location="line:{$err:line-number},
col:{$err:column-number}" />
     </xsl:sequence>
  </xsl:catch>
       </xsl:try>
    </xsl:function>

</xsl:stylesheet>

The above stylesheet, when applied to the input XML document, produces
following output,

<?xml version="1.0" encoding="UTF-8"?>
<result>
   <div num="5" denom="5">1</div>
   <div num="5" denom="4">1.25</div>
   <div num="5" denom="3">1.666666666666666667</div>
   <error val_pos="4"
          document="file:/E:/saxon/../foo.xsl"
          code="err:FOAR0001"
          description="Integer division by zero"
          location="line:26, col:0"/>
   <div num="5" denom="2">2.5</div>
   <error val_pos="6"
          document="file:/E:/saxon/../foo.xsl"
          code="err:FOAR0001"
          description="Integer division by zero"
          location="line:26, col:0"/>
   <div num="5" denom="1">5</div>
</result>

The above output is, what I wanted to achieve (i.e either emit the "div"
tag if div operation is successful, or emit an "error" tag if div by 0
error occurs). For each iteration of loop, my numerator is fixed (its also
non zero, and 5 in my example) and denominator is variable (it can be zero.
that div error I want to catch via try/catch, and continue processing
subsequent items in the loop).
I would have been more happy, if an error message could show line numbers
of the offending nodes from input XML document. For that, Saxon's extension
function line-number(..) seems to do the job well.

Below is another stylesheet (Stylesheet 2) processing things a little
differently, and working on the same input XML document,

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";

                         xmlns:err="http://www.w3.org/2005/xqt-errors";
                         xmlns:fn="http://xslt-functions";
                         xmlns:xs="http://www.w3.org/2001/XMLSchema";
                         exclude-result-prefixes="err fn xs"
                         version="3.0">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
       <result>
          <xsl:try>
             <xsl:for-each select="test/val">
                <xsl:copy-of select="fn:div(5, .)"/>
             </xsl:for-each>
             <xsl:catch errors="*">
  <error document="{$err:module}" code="{$err:code}"
description="{$err:description}" location="line:{$err:line-number},
col:{$err:column-number}" />      </xsl:catch>
          </xsl:try>
       </result>
    </xsl:template>

    <xsl:function name="fn:div" as="element()">
       <xsl:param name="numerator" as="xs:integer"/>
       <xsl:param name="denominator" as="xs:integer"/>

       <xsl:sequence>
  <div num="{$numerator}" denom="{$denominator}"><xsl:value-of
select="$numerator div $denominator"/></div>
       </xsl:sequence>
    </xsl:function>

</xsl:stylesheet>

In the above stylesheet, I use the try/catch at a higher level (I enclose
the for-each loop within a try/catch). I get following output with this
XSLT transformation,

<?xml version="1.0" encoding="UTF-8"?>
<result>
   <error document="file:/E:/saxon/../foo1.xsl"
          code="err:FOAR0001"
          description="Integer division by zero"
          location="line:29, col:0"/>
</result>

This is expected. The transformation concludes after first failure, and
roll backs previous successful outcomes.

I'm happy with what I've learnt.

On Sat, Feb 23, 2019 at 11:37 PM Michael Kay mike@xxxxxxxxxxxx <
xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:

> Division by zero is a dynamic error, but if the operands are constants,
> then most processors will be able to detect it statically, because
> evaluating constant subexpressions is a very simple optimization.
>
> So what do the rules say about dynamic errors? The detailed rules are in
> B'2.14 https://www.w3.org/TR/xslt-30/#errors -- which doesn't actually
> mention try/catch.
>
> The key paragraph is
>
> <quote>
> An implementation may signal a dynamic error before any source document is
> available, but only if it can determine that the error would be signaled
> for every possible source document and every possible set of parameter
> values. For example, some circularity errors fall into this category: see
> 9.11 Circular Definitions.
> </quote>
>
> This isn't quite as rigorous as it might be. In your second example, there
> are clearly source documents for which the error will never be raised
> dynamically (those where count(/test/hello) is zero) and therefore it must
> not be raised statically. In the first example, the error will always be
> raised so long as the match="/" template is executed, that is, if
> evaluation starts in the unnamed mode; that leaves some scope for
> interpretation of exactly what the above paragraph is supposed to mean
> (should it be read as saying "and for every possible initial mode"?). Also
> the cited paragraph isn't really clear as to what "would be signaled"
> means: if an error happens, but is not reported because it is caught by
> try/catch, then is it "signaled" for the purpose of this rule? The whole
> thing is a bit fuzzy round the edges.
>
> What's happening in Saxon, though, is quite wrong. Saxon goes to great
> lengths to avoid raising the error statically; however the optimizer
> somehow rewrites the logic so that the constant expression (1 div 0) is
> evaluated outside the try/catch and the error therefore occurs at run-time,
> but isn't caught. I'll pursue that as a bug, even though the spec is a
> little fuzzy.
>




--
Regards,
Mukul Gandhi

alt address : mukulgandhi@xxxxxxx

Current Thread