Question

I'm trying to do a modulus 11 check in XSLT 1.0 for a 17 digit number. However, it always seems to give the wrong output.

The only information I've been able to find about this, was in this post, however, no solution was found.

I have in the past used an XSLT template for a Luhn checker, I realise that this works differently to a modulus check but I was wondering if anyone was aware of an XSLT template which can calculate moduluses of large numbers?

Was it helpful?

Solution

There is a pure XSLT 1.0 solution which calculates $n mod 11 for integer $n of any size:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/*">
     <xsl:call-template name="mod11"/>
 </xsl:template>

 <xsl:template name="mod11">
  <xsl:param name="pN" select="."/>

  <xsl:choose>
   <xsl:when test="not($pN > 9999999999999999)">
     <xsl:value-of select="$pN mod 11"/>
   </xsl:when>
   <xsl:otherwise>
      <xsl:variable name="vLen" select="string-length($pN)"/>

      <xsl:variable name="vLen1" select="$vLen -1"/>

      <xsl:variable name="vPart1" select=
          "substring($pN, 1, $vLen1)"/>

      <xsl:variable name="vPart2" select=
          "substring($pN, $vLen1 +1)"/>

      <xsl:variable name="vMod1">
       <xsl:call-template name="mod11">
         <xsl:with-param name="pN" select="$vPart1"/>
       </xsl:call-template>
      </xsl:variable>

      <xsl:variable name="vMod2" select="$vPart2 mod 11"/>

      <xsl:value-of select="(10*$vMod1 + $vMod2) mod 11"/>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document:

<t>12345678901234567</t>

the wanted correct result (12345678901234567 mod 11) is produced:

9

Do note:

  1. This solution can easily be generalized to calculate $n mod $m for any integer $m -- just pass $m as a second parameter.

  2. Another generalization is to pass as parameter the limit above which $n mod $m cannot be calculated directly using the mod operator. This can be useful when using XSLT 2.0 and having $n as either xs:integer or xs:decimal.

  3. Another alternative is to use the Saxon.NET XSLT 2.0 processor or any other XSLT 2.0 processor that implements Big Integer arithmetics. Then the solution is just to use the mod operator:

....

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*">
     <xsl:value-of select="xs:integer(.) mod 11"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied with Saxon 9.1.07 on the same XML document (above), the same correct result is produced:

9

OTHER TIPS

That is because in MSXML number type is equivalent of .NET Double datatype, which has precision of 15-16 digits. Try this sample:

double d = 123456789012345678;
Console.WriteLine("{0:f}", d);
Console.WriteLine("{0:f}", d + 1);
Console.WriteLine("{0:f}", d % 3);

long l = 123456789012345678;
Console.WriteLine(l);
Console.WriteLine(l + 1);
Console.WriteLine(l % 3);

Output:

123456789012346000,00
123456789012346000,00
2,00
123456789012345678
123456789012345679
0

I think you can extend XSLT with C# or JScript, because MSXML supports this.

Reference: http://msdn.microsoft.com/en-us/library/533texsx(v=VS.100).aspx, http://msdn.microsoft.com/en-us/magazine/cc302079.aspx

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top