4

我正在尝试在 XSLT 1.0 中对 17 位数字进行模数 11 检查。但是,它似乎总是给出错误的输出。

我能找到的唯一信息是在这篇文章中,但是没有找到解决方案。

我过去曾为 Luhn 检查器使用 XSLT 模板,我意识到这与模数检查的工作方式不同,但我想知道是否有人知道可以计算大数模数的 XSLT 模板?

4

2 回答 2

3

有一个纯 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$n这在使用 XSLT 2.0 并具有asxs:integer或时很有用xs:decimal

  3. 另一种选择是使用 Saxon.NET XSLT 2.0 处理器或任何其他实现大整数运算的 XSLT 2.0 处理器。那么解决方案就是使用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
于 2012-01-11T13:11:55.267 回答
2

这是因为在 MSXML 中,数字类型等同于 .NETDouble数据类型,其精度为 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

我认为您可以使用 C# 或 JScript 扩展 XSLT,因为 MSXML 支持这一点。

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

于 2012-01-11T10:17:03.473 回答