Re: [xsl] How to convert a recursive function to a loop, using XSLT 2.0?

Subject: Re: [xsl] How to convert a recursive function to a loop, using XSLT 2.0?
From: "Syd Bauman s.bauman@xxxxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 10 May 2019 13:35:30 -0000
Presuming your input has been validated so that only proper hex
values for XML Unicode characters occur inside <Byte>, why not just
treat it as a sequence of codepoints?

   <xsl:variable name="numSeq"
                 select=".//Byte/text()/xs:integer(f:hexToDec(.))"
                 as="xs:integer+"/>
   <xsl:variable name="codepoints"
                 select="for $n in $numSeq return
                           if ( $n eq 0 )
                           then 9216
                           else $n" as="xs:integer+"/>
   <xsl:variable name="string" select="codepoints-to-string($codepoints )"/>
   <xsl:for-each select="tokenize( $string,'&#x2400;')">
     <String><xsl:value-of select="."/></String>
   </xsl:for-each>

Note that NULL = 0 = &#x00; is converted to SYMBOL FOR NULL = 9216 =
&#x2400; because NULL is not a valid XML character. You could use
any character that is guaranteed not to occur in the input.

You would need to write a hex-to-integer converter, or grab one off
StackOverflow

This would not work of course, if <Byte> represented actual bytes
rather than characters. (I.e., if EURO SIGN were represented as
<Byte>E2</Byte><Byte>82</Byte><Byte>AC</Byte> instead of
<Byte>20AC</Byte>.)

> My input file consists of a sequence (sourceSeq) of <Byte> elements
> representing a sequence of null-terminated strings. I want to
> create a function that returns a sequence of <String> elements. For
> example, with this sourceSeq:
> 
> <Byte>48</Byte>
> <Byte>69</Byte>
> <Byte>00</Byte>
> <Byte>4A</Byte>
> <Byte>69</Byte>
> <Byte>6C</Byte>
> <Byte>6C</Byte>
> <Byte>00</Byte>
> 
> the function should return:
> 
> <String>Hi</String>
> <String>Jill</String>
> 
> The strings are of variable length.
> 
> I do not know how many null-terminated strings are in sourceSeq.
> However, I do know the total number (total-size) of <Byte> elements
> within sourceSeq containing the null-terminated strings.
> 
> Below is a recursive way to implement the function. Unfortunately,
> total-size can be quite large, which means the function recurses
> many times, resulting in a "Too many nested function calls" error.
> Is there an iterative way to implement the function? /Roger
> 
> <xsl:function name="f:make-string-table-entries" as="element(String)*">
>     <xsl:param name="total-size" as="xs:integer" />
>     <xsl:param name="current-size" as="xs:integer" />
>     <xsl:param name="current-position" as="xs:integer" />
>     <xsl:param name="sourceSeq" as="element(Byte)*" />
>     
>     <xsl:choose>
>         <xsl:when test="$current-size ge $total-size" />
>         <xsl:otherwise>
>             <xsl:variable name="string" select="f:make-element-from-null-terminated-string('String', $current-position, $sourceSeq)" as="element(String)"/>
>             <xsl:sequence select="$string" />
>             <xsl:variable name="length" select="string-length($string/text()) + 1"/>  <!-- add 1 for the null byte -->
>             <xsl:sequence select="f:make-string-table-entries($total-size, xs:integer($current-size+$length), xs:integer($current-position+$length), $sourceSeq)" />
>         </xsl:otherwise>
>     </xsl:choose>
>     
> </xsl:function>

-- 
 Syd Bauman, NRP  (he/him/his)
 Senior XML Programmer/Analyst
 Northeastern University Women Writers Project
 s.bauman@xxxxxxxxxxxxxxxx or
 Syd_Bauman@xxxxxxxxxxxxxxxx

Current Thread