RE: [xsl] sorting and 0 div boolean

Subject: RE: [xsl] sorting and 0 div boolean
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Tue, 14 Feb 2006 18:47:44 -0000
This "0 div boolean" is a cunning David Carlisle special device to simulate
a conditional expression. It stops working in 2.0 because numeric literals
such as "0" or "1" are now interpreted as integers rather than doubles, and
integer division by zero is a hard error, whereas double division by zero
returns infinity, which you can use in a cunning way as an argument to
substring().

The way forward depends on whether you want to move to a pure 2.0 solution,
or to have a solution that works under both releases. For a solution that
works under both versions, the simplest approach is to change the literal 0
to number("0") which gives you a double zero under both versions. 

For a 2.0 solution, we need to reverse engineer the expression

>      <xsl:sort select="concat(
          substring(substring-after(.,' '), 
                    0 div boolean($stop-words
               [starts-with(translate(current(), $uppercase, $lowercase), 
                  concat(translate(., $uppercase, $lowercase), ' '))])), 
                     substring(., 0 div not 
                         ($stop-words[starts-with(translate(current(),
$uppercase, $lowercase), 
              concat(translate(., $uppercase, $lowercase), ' '))])))"/> 

which is a bit of a monster.

Basically, substring(X, 0 div boolean(B)) means

if (B) then X else ""

So I think the above expression reduces to

      <xsl:sort select="concat(
          if ($stop-words[starts-with(lower-case(current()),
concat(lower-case(.), ' '))]) 
            then substring-after(.,' ') 
            else '', 
          if ($stop-words[starts-with(lower-case(current()),
concat(lower-case(.), ' '))]) 
            then '' 
            else .)"/> 

which in turn reduces to

      <xsl:sort select="
          if ($stop-words[starts-with(lower-case(current()),
concat(lower-case(.), ' '))]) 
            then substring-after(.,' ') 
            else ."/>

I'd encourage you not to use Saxon 7.7, however. The specs were pretty
unstable at the time 7.7 came out, and it's now about 10 releases out of
date. Go straight to 8.6.1.

Michael Kay
http://www.saxonica.com/

> -----Original Message-----
> From: Susan Campbell [mailto:SCampbell@xxxxxxxxxxxxxxx] 
> Sent: 14 February 2006 18:24
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] sorting and 0 div boolean
> 
> This code worked but now it doesn't work.   We had a software upgrade
> and our processor is contained within the other software.  
> When the sort
> worked we were using Saxon 6.4.2.  We're now using Saxon 7.7. 
>  This code
> still works in the old version, but not in the new.  This code now
> returns a parse error, "Division by zero."  I read the FAQ about
> 'Division by zero' but format-number doesn't help me here. 
> 
> Is there another way to sort this and ignore the stop words I 
> have here?
> The problem section of my xsl is here, followed by a snippet 
> of the xml
> I'm trying to transform.
> Thanks,
> Susan Campbell
> scampbell@xxxxxxxxxxxxxxx
> 
> <xsl:stylesheet
>    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0"
>    xmlns:sw="http://my.stopwords/sw";
>    exclude-result-prefixes="sw">
> 
> <sw:stop>
>    <word>the</word>
>    <word>a</word>
>    <word>an</word>
> </sw:stop>
> 
> <xsl:variable name="stop-words"
> select="document('')/xsl:stylesheet/sw:stop/word"/>
> <xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'"/>
> <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUV'"/>
> 
> <xsl:template match="/">
> <xsl:call-template name="header"/>
>      <xsl:for-each select="//section-02/title">
>      <xsl:sort select="concat(substring(substring-after(.,' '), 0 div
> boolean
>              ($stop-words[starts-with(translate(current(), $uppercase,
> $lowercase), 
>              concat(translate(., $uppercase, $lowercase), ' '))])),
> substring(., 0 div not
>              ($stop-words[starts-with(translate(current(), $uppercase,
> $lowercase), 
>              concat(translate(., $uppercase, $lowercase), ' 
> '))])))"/> 
>           <xsl:if test="position() = 1">
>           <xsl:call-template name="section-02">
>              <xsl:with-param name="header" select="'header'"/>
>           </xsl:call-template>
>        </xsl:if>
>        <xsl:call-template name="section-02"/>
>     </xsl:for-each>
> </xsl:template>
> </xsl:stylesheet>
> 
> 
> The XML section I'm trying to sort looks like this;.
> <section-02>
> <title>The African American review.</title>
> <arrivals>2</arrivals>
> </section-02>
> 
> <section-02>
> <title>Agricultural research /</title>
> <arrivals>8</arrivals>
> </section-02>
> 
> <section-02>
> <title>The American biology teacher.</title>
> <arrivals>5</arrivals>
> </section-02>
> 
> <section-02>
> <title>The American journal of nursing.</title>
> <arrivals>6</arrivals>
> </section-02>
> 
> <section-02>
> <title>Air &amp; space Smithsonian.</title>
> <arrivals>2</arrivals>
> </section-02>
> 
> <section-02>
> <title>An American Story.</title>
> <arrivals>20</arrivals>
> </section-02>

Current Thread