[xsl] help with recursive function

Subject: [xsl] help with recursive function
From: Mario Madunic <hajduk@xxxxxxxx>
Date: Tue, 6 May 2008 09:13:32 -0700
Hi,

I'm having a problem with a recursive function in 2.0.

I'm iterating through the value of a node that is tokenized on spaces. I
normalize the 'word' to lower-case and remove an 's if it exists. Then check it
against a library xml file (spellingBee.xml), if the 'word' isn't listed then
just upper-case the first letter and leaving the rest as is; otherwise replace
the 'word' with the corrected spelling in the spellingBee.xml. Finish by
concatenating new 'word' with the value of g_AposS. That was simple enough to
create but I decided to take it one step further and check the current 'word'
for a simple set of delimiters (-/\); doing this to keep down the number of
entries in spellingBee.xml. Then start ripping it apart into two pieces: before
the delimiter and after the delimiter. The 'word' before the delimiter would be
checked against spellingBee.xml and the rules mentioned above would be applied.
The bit after the delimiter would be tossed back into the function by calling
the function again. That is when I receive the following error message:

[xslt]
[xslt]
[xslt] original headline :: MEET THE BEATLES
ABC's-A.B.C./A.b.c.'s-ABC\abc's\nbc/n.b.c.'s
[xslt]
[xslt]
[xslt] e:\XSLT\cleanUp.xsl:259: Fatal Error! A sequence of more than one item is
not allowed as the first argument of concat()
[xslt] Failed to process null


input XML node

<head>MEET THE BEATLES ABC's-A.B.C./A.b.c.'s-ABC\abc's\nbc/n.b.c.'s</head>



called in cleanUp.xsl

<xsl:variable name="l_TokenizedString" select="tokenize($l_HeadTemp, ' ')" />

<xsl:for-each select="$l_TokenizedString">
  <!-- line 259 mentioned in error message -->
  <xsl:value-of select="concat(f:f_UpperLowerCaseFix(.), if (not(position() =
last())) then ' ' else '')" />
</xsl:for-each>



spellingBee.xml looks like the following

<fixCase>
  <word>
    <lowerCase>abc</lowerCase>
    <corrected>ABC</corrected>
  </word>
  <word>
    <lowerCase>a.b.c.</lowerCase>
    <corrected>A.B.C.</corrected>
  </word>
</fixCase>



The function itself

  <xsl:function name="f:f_UpperLowerCaseFix">

    <xsl:param name="p_String" />

    <!-- this variable actually exists in a global variables file and is only
defined here for posting on XSLT mailing list -->
    <xsl:variable name="g_AposS">'s</xsl:variable>

    <xsl:variable name="l_Delimiter">
      <xsl:choose>
        <xsl:when test="contains($p_String, '-')"><xsl:value-of select="'-'"
/></xsl:when>
        <xsl:when test="contains($p_String, '/')"><xsl:value-of select="'/'"
/></xsl:when>
        <xsl:when test="contains($p_String, '\')"><xsl:value-of select="'\'"
/></xsl:when>
        <xsl:otherwise><xsl:value-of select="'none'" /></xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$l_Delimiter = 'none'">

        <xsl:variable name="l_String" select="lower-case(if
(ends-with($p_String, $g_AposS)) then substring-before($p_String, $g_AposS) else
$p_String)" />
        <xsl:variable name="l_AposS" select="if (ends-with($p_String, $g_AposS))
then $g_AposS else ''" />

        <xsl:choose>
          <xsl:when
test="doc('../../supXML/spellingBee.xml')/fixCase//lowerCase[. = $l_String]">
            <xsl:value-of
select="concat(doc('../../supXML/spellingBee.xml')/fixCase/word//corrected[preceding-sibling::*[.
= $l_String]], $l_AposS)" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="concat(upper-case(substring($l_String, 1, 1)),
substring($l_String, 2, string-length($l_String)), $l_AposS)" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>

      <xsl:otherwise>

        <xsl:variable name="l_StringBeforeDelimiter"
select="substring-before(lower-case($p_String), $l_Delimiter)" />
        <xsl:variable name="l_StringAfterDelimiter"
select="substring-after(lower-case($p_String), $l_Delimiter)" />

        <xsl:variable name="l_String" select="if
(ends-with($l_StringBeforeDelimiter, $g_AposS)) then
substring-before($l_StringBeforeDelimiter, $g_AposS) else
$l_StringBeforeDelimiter" />
        <xsl:variable name="l_AposS" select="if
(ends-with($l_StringBeforeDelimiter, $g_AposS)) then $g_AposS else ''" />

        <xsl:choose>
          <xsl:when
test="doc('../../supXML/spellingBee.xml')/fixCase//lowerCase[. = $l_String]">
            <xsl:value-of
select="concat(doc('../../supXML/spellingBee.xml')/fixCase/word//corrected[preceding-sibling::*[.
= $l_String]], $l_AposS, $l_Delimiter)" />
            <xsl:value-of select="f:f_UpperLowerCaseFix($l_StringAfterDelimiter)" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="concat(upper-case(substring($l_String, 1, 1)),
substring($l_String, 2, string-length($l_String)), $l_AposS, $l_Delimiter)" />
            <xsl:value-of select="f:f_UpperLowerCaseFix($l_StringAfterDelimiter)" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>

  </xsl:function>

The desired output from the sample node above should look like

input: MEET THE BEATLES ABC's-A.B.C./A.b.c.'s-ABC\abc's\nbc/n.b.c.'s
output: Meet The Beatles ABC's-A.B.C./A.B.C.'s-ABC\ABC's\nbc/n.b.c.'s


Any help will be appreciated.

Marijan (Mario) Madunic

Current Thread