Search code examples
xmlxslt-1.0msxml6

XSLT 1.0 compile error with named template


I am trying to handle a space issue with the Phone number and faxNumber elements in my XML.

The elements are:

<PhoneNumber>0870 6071352</PhoneNumber>
<FaxNumber>01722 422301</FaxNumber>

but they can also be:

0870 6071352

so I need to remove the leading and trailing spaces, keep the space between any numbers, and output the result formatted to a fixed length of 71 characters using leading spaces.

so I am trying to write a named template that will remove the spaces then pad the output with leading spaces to a fixed length of 71 characters.

here is my defined template but it doesn't compile - I get an error Expression expected <- and I can't find out what is missing or wrong

<!-- format the phone number with no spaces and output to 71 characters with leading spaces -->
<xsl:template name="FormattedPhoneFaxNumber">
    <xsl:param name="text"/>
    <xsl:choose>
      <xsl:when test="contains($text,' ')">
        <xsl:value-of select="substring-before($text,' ')"/>
        <xsl:value-of select=""/>
        <xsl:call-template name="FormattedPhoneFaxNumber">
          <xsl:with-param name="text" select="substring-after($text,' ')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="substring(concat('                                                                       ', $text), 1, 71)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

can anyone show me where I am going wrong?

The reason I need to do this is because I have to handle the element being empty, having leading or trailing spaces as well as the value, or just the value, and we need to output two fiwlds with leading spaces to a max length of 71 characters.


Solution

  • Remove the line:

    <xsl:value-of select=""/>
    

    The select attribute should be an XPath expression, and an empty string is not a valid expression.

    But you don't actually need the recursive template at all, if you want to remove spaces from a string you can do it using translate(theString, ' ', ''), and you may want to add a normalize-space to handle other whitespace characters like tabs. For example, the following stylesheet

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      <xsl:output method="text" />
    
      <xsl:template name="FormattedPhoneFaxNumber">
          <xsl:param name="text"/>
          <xsl:variable name="noSpaces" select="translate(normalize-space($text), ' ', '')" />
          <!-- using fewer spaces for this example, but in your real case use 71 -->
          <xsl:value-of select="substring(concat('                            ',
              $noSpaces), string-length($noSpaces) + 1)"/>
      </xsl:template>
    
      <xsl:template match="/">
        <xsl:for-each select="*/*">
          <xsl:text>>>></xsl:text>
          <xsl:call-template name="FormattedPhoneFaxNumber">
            <xsl:with-param name="text" select="." />
          </xsl:call-template>
          <xsl:text>&lt;&lt;&lt;&#10;</xsl:text>
        </xsl:for-each>
      </xsl:template>
    </xsl:stylesheet>
    

    when run on the following XML document

    <root>
      <num>   </num>
      <num>0123  456 7890   </num>
      <num>&#9;212-345 6789</num><!-- &#9; is a tab character -->
      <num/>
    </root>
    

    produces the correct result

    >>>                            <<<
    >>>                 01234567890<<<
    >>>                 212-3456789<<<
    >>>                            <<<
    

    In particular empty elements produce completely blank strings of the correct length.