xsl-list
[Top] [All Lists]

RE: [xsl] Trying to find following sibling that ends in punctuation

2006-11-04 11:10:28
Michael here is the function but it has worked perfectly(or 
as perfectly as can be) in other instances.

Let's walk through it and see what it does if the argument is an empty
sequence.

    <xsl:function name="f:f_StringEndsWith" as="xs:string">

        <!-- p_String to test -->
        <xsl:param name="p_String" />

There's no "as" attribute: it might be a good idea to add one. You'll have
to decide whether to use xs:string or xs:string? - ie whether an empty
sequence is allowed or not. 

        <!-- get the last character -->
        <xsl:variable name="l_LastCharacter" 
select="substring($p_String, string-length($p_String), 1)" />

If the param is (), this variable will be "" (the zero length string)

        <!-- get the last two characters -->
        <xsl:variable name="l_LastTwoCharacter" 
select="substring($p_String, string-length($p_String) - 1, 2)" />

If the param is (), this variable will be "" (the zero length string)

        <!-- . : ! ? -->
        <xsl:variable name="l_LastCharacterIs" select="if 
(matches($l_LastCharacter, 
'[&#46;]|[&#58;]|[&#33;]|[&#63;]')) then 'punct' else 'noPunct'" />

If the param is () there will be no match, so the value will be "noPunct"

        <!-- ." !" ?" .) !) ?) -->
        <!--xsl:variable name="l_LastTwoCharacterAre" 
select="if (matches($l_LastTwoCharacter,
'[&#46;&#34;]|[&#33;&#34;]|[&#63;&#34;]|[&#46;&#41;]|[&#33;&#4
1;]|[&#63;&#41;]'))
then 'punct' else 'noPunct'" /-->

If the param is () there will be no match, so the value will be "noPunct"

        <!-- the above failed in a couple of instances and so 
the var and choose below works. it is in longhand for ease of 
maintaining -->
        <!-- ." !" ?" .) !) ?) -->
        <xsl:variable name="l_LastTwoCharacterAre">
            <xsl:choose>
                <xsl:when test="$l_LastTwoCharacter = 
'&#46;&#34;'"><xsl:value-of select="'punct'" /></xsl:when>
                <xsl:when test="$l_LastTwoCharacter = 
'&#33;&#34;'"><xsl:value-of select="'punct'" /></xsl:when>
                <xsl:when test="$l_LastTwoCharacter = 
'&#63;&#34;'"><xsl:value-of select="'punct'" /></xsl:when>
                <xsl:when test="$l_LastTwoCharacter = 
'&#46;&#41;'"><xsl:value-of select="'punct'" /></xsl:when>
                <xsl:when test="$l_LastTwoCharacter = 
'&#33;&#41;'"><xsl:value-of select="'punct'" /></xsl:when>
                <xsl:when test="$l_LastTwoCharacter = 
'&#63;&#41;'"><xsl:value-of select="'punct'" /></xsl:when>
                <xsl:otherwise><xsl:value-of select="'noPunct'" 
/></xsl:otherwise>
            </xsl:choose>
        </xsl:variable>

This is horrible. If your code doesn't work, find out why, don't just add
another version of the same logic! 

In fact, the best way of testing whether your variable $l_LastTwoCharacter =
is equal to one of these strings is simply:

test="($l_LastTwoCharacter = ('.&quot;', '!&quot;', '?&quot;', '.)', '!)',
'?)'))"

        <xsl:choose>
            <xsl:when test="($l_LastCharacterIs = 'punct') or 
($l_LastTwoCharacterAre = 'punct')"><xsl:value-of select="'punct'" 
/></xsl:when>
            <xsl:otherwise><xsl:value-of select="'noPunct'" 
/></xsl:otherwise>
        </xsl:choose>

It looks as if my theory was correct. When you call the function with (), it
will return "noPunct", and therefore your recursive template will recurse
for ever.

Note also, you should be using <xsl:sequence> rather than <xsl:value-of> in
this code. There's no reason to be creating text nodes when you only want
strings.

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


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--