XSLT мод проверка на большие числа - PullRequest
4 голосов
/ 11 января 2012

Я пытаюсь выполнить проверку модуля 11 в XSLT 1.0 для 17-значного числа.Однако, кажется, что это всегда дает неправильный вывод.

Единственная информация, которую я смог найти об этом, была в этом посте , однако, никакого решения не было найдено.

В прошлом я использовал шаблон XSLT для проверки Luhn, я понимаю, что это работает не так, как проверка модуля, но мне было интересно, знал ли кто-нибудь о шаблоне XSLT, который может вычислять модули больших чисел?

Ответы [ 2 ]

3 голосов
/ 11 января 2012

Существует чистое решение XSLT 1.0, которое вычисляет $n mod 11 для целых чисел $n любого размера :

<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>

Когда это преобразование применяется к следующему документу XML :

<t>12345678901234567</t>

желаемый правильный результат (12345678901234567 mod 11) получается :

9

Примечание :

  1. Это решение можно легко обобщить для вычисления $n mod $m для любого целого числа $m - просто передайте $m в качестве второго параметра.

  2. Другим обобщением является передача в качестве параметра предела, выше которого $n mod $m нельзя вычислить напрямую с помощью оператора mod. Это может быть полезно при использовании XSLT 2.0 и $n в качестве xs:integer или xs:decimal.

  3. Другой альтернативой является использование процессора Saxon.NET XSLT 2.0 или любого другого процессора XSLT 2.0, который реализует арифметику Big Integer. Тогда решение состоит в том, чтобы просто использовать оператор mod:

....

<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>

Когда это преобразование применяется с Saxon 9.1.07 к тому же XML-документу (выше), получается тот же правильный результат:

9
2 голосов
/ 11 января 2012

Это потому, что в MSXML тип чисел эквивалентен типу данных .NET Double, который имеет точность 15-16 цифр.Попробуйте этот пример:

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);

Вывод:

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

Я думаю, вы можете расширить XSLT с помощью C # или JScript, поскольку MSXML поддерживает это.*http://msdn.microsoft.com/en-us/library/533texsx(v=VS.100).aspx, http://msdn.microsoft.com/en-us/magazine/cc302079.aspx

...