Search code examples
xmlxsltjava-8saxonxalan

XSL error: format-number picture: Passive character must not appear between active characters in a sub-picture


There is a need to read numbers and format it.

Input:

<InitialReading>500</InitialReading>
<InitialReading>620,25</InitialReading>
<InitialReading>1 200,5</InitialReading>
<InitialReading>1 100</InitialReading>

XSL:

<xsl:call-template name="formatNumber3">
    <xsl:with-param name="number"
                        select="format-number(number(InitialReading/translate(., ',', '.')), '# ###0.000')"/>
</xsl:call-template>
<xsl:template name="formatNumber3">
    <xsl:param name="number"/>
    <xsl:call-template name="formatNumber">
        <xsl:with-param name="number" select="$number"/>
        <xsl:with-param name="format" select="'# ##0,000'"/>
    </xsl:call-template>
</xsl:template>
<xsl:decimal-format name="SUM_FORMAT" grouping-separator=" " decimal-separator=","/>
<xsl:template name="formatNumber">
    <xsl:param name="number"/>
    <xsl:param name="format"/>
    <xsl:if test="normalize-space($number)">
        <xsl:value-of select="format-number(number(normalize-space($number)), $format, 'SUM_FORMAT')"/>
    </xsl:if>
</xsl:template>

Expected output:

<p>500,000</p>
<p>620,250</p>
<p>1 200,500</p>
<p>1 100,000</p>

Update:

select="format-number(number(InitialReading/translate(., ',', '.')), '##0.000')" print NaN for the last 2 values. All other values rendered correctly.

The solution needs to be compatible with saxon and xalan implementations.

Update 2:

After careful investigation it turned out that the whitespace character was actually &nbsp; or &#160;.

Thanks for help from @Martin Honnen and @Michael Ka, the working snippet looks like:

<xsl:variable name="number" select="number(translate(., ', &#160;', '.'))"/>
        <xsl:value-of select="format-number($number, '# ##0,000', 'SUM_FORMAT')"/>

Solution

  • The following works for me with both XSLT 1 and 3 processor:

      <xsl:decimal-format name="SUM_FORMAT" 
        grouping-separator=" " 
        decimal-separator=","/>
    
      <xsl:template match="InitialReading">
          <xsl:variable name="number"
            select="number(translate(., ', ', '.'))"/>
          <p>Parsed value : <xsl:value-of select="$number"/></p>
          <p>Formatted value: <xsl:value-of select="format-number($number, '# ##0,000', 'SUM_FORMAT')"/></p>
      </xsl:template>
    

    Output at https://xsltfiddle.liberty-development.net/6rexjhV/2:

    <p>Parsed value : 500</p>
        <p>Formatted value: 500,000</p>
    <p>Parsed value : 620.25</p>
        <p>Formatted value: 620,250</p>
    <p>Parsed value : 1200.5</p>
        <p>Formatted value: 1 200,500</p>
    <p>Parsed value : 1100</p>
        <p>Formatted value: 1 100,000</p>
    
    
    Parsed value : 500
    
    Formatted value: 500,000
    
    Parsed value : 620.25
    
    Formatted value: 620,250
    
    Parsed value : 1200.5
    
    Formatted value: 1 200,500
    
    Parsed value : 1100
    
    Formatted value: 1 100,000