2011-01-07 5 views
3

Можно ли написать функцию XSLT, которая может выполнять базовую проверку IBAN Mod-97?Подтвердить IBAN с помощью XSLT 2.0?

Из Википедии:
1. Переместите четыре начальных символа в конец строки.
2. Замените каждую букву в строке двумя цифрами, тем самым расширяя строку, где A = 10, B = 11, ..., Z = 35.
3. Интерпретировать строку как десятичные целой и вычислить остаток от этого числа на деление на 97.

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

Спасибо.

+0

Хороший вопрос, +1. См. Мой ответ для полного и простого решения. :) –

ответ

4

Это преобразование:

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

<xsl:template match="text()"> 
    <xsl:sequence select="my:isIBAN(.)"/> 
</xsl:template> 

<xsl:function name="my:isIBAN" as="xs:boolean"> 
    <xsl:param name="pString" as="xs:string"/> 

    <xsl:variable name="vDigits" select= 
    "string-join(
       (for $vStarting4 in substring($pString, 1,4), 
        $vRest in substring($pString, 5), 
        $vNewString in concat($vRest,$vStarting4), 
        $vLen in string-length($vNewString), 
        $i in 1 to $vLen 
        return 
        my:code(substring($vNewString,$i,1)) 
       ), 
       '' 
       ) 
    "/> 

    <xsl:sequence select="xs:integer($vDigits) mod 97 eq 1"/> 
</xsl:function> 

<xsl:function name="my:code" as="xs:string"> 
    <xsl:param name="pChar" as="xs:string"/> 

    <xsl:sequence select= 
    "if(string-length($pChar) ne 1 or not(contains($vCaps, $pChar))) 
    then $pChar 
    else 
     xs:string 
     (string-to-codepoints($pChar) - string-to-codepoints('A') +10) 
    "/> 
</xsl:function> 
</xsl:stylesheet> 

при нанесении на этом XML-документ:

<t>GB82WEST12345698765432</t> 

производит разыскиваемого, правильный результат:

true 

Примечание:: Функция my:isIBAN() может быть реализована как одно выражение XPath 2.0. Я не представил его по соображениям удобочитаемости.

+0

+1 Хороший ответ. (Похоже, мы оба прочитали один и тот же Wiki articule, ja!) –

+0

+1 для вас обоих. 2.0 является предельным. – Flack

2

Просто для удовольствия (я не видел, что @Dimitre уже ответил)

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:local="http://localhost/"> 
    <xsl:template match="IBAN[local:validate(.)]"> 
     <xsl:text>Validated IBAN</xsl:text> 
    </xsl:template> 
    <xsl:function name="local:validate"> 
     <xsl:param name="pIBAN" as="xs:string"/> 
     <xsl:sequence select="xs:integer(
           codepoints-to-string(
            for $n in string-to-codepoints(
               concat(
                substring(
                 $pIBAN, 
                 5 
                ), 
                substring(
                 $pIBAN, 
                 1, 
                 4 
                ) 
               ) 
              ) 
            return if ($n > 64) 
              then string-to-codepoints(
                string(
                 $n - 55 
                ) 
               ) 
              else $n 
           ) 
          ) mod 97 eq 1"/> 
    </xsl:function> 
</xsl:stylesheet> 

С этим входом:

<IBAN>GB82WEST12345698765432</IBAN> 

Выход:

Validated IBAN 

EDIT: Лучше один лайнер.

+0

+1 за хороший ответ. Я намеренно не произвел ни одного выражения - для лучшей читаемости. –

+0

@Dimitre: Мне нравится ваше объявление переменной XPath 2.0 «внутри» выражение, кстати ...;) –

+0

@Alejandro: Да, это мое основное оружие в написании почти любого XSLT 2.0 как (обычно одно) XPath выражение (ы). Единственный случай, который вы все еще должны использовать '', - это когда значение для переменной является последовательностью. В XPath 3.0 это ограничение умирает, поскольку оно позволяет использовать предложение 'let' в XPath. –