Похоже, вам нужна зависящая от позиции контрольная сумма .Вы запрашиваете реализацию XSLT или просто алгоритм?
Вот реализация контрольной суммы Флетчера в C, которую не должно быть очень сложно портировать на XSLT.
Обновление: Ниже приведена адаптация контрольной суммы Флетчера для XSLT 2.0.Будет ли это достаточно быстро, зависит от размера ваших данных и количества времени, которое у вас есть.Мне было бы интересно услышать, как проходят ваши тесты.Для оптимизации я бы попытался изменить xs:integer
на xs:int
.
Обратите внимание, что я заменил обычное добавление на побитовое ИЛИ (|
) реализации, с которой я связан выше.Я не очень квалифицирован для анализа последствий этого изменения в отношении однородности или необратимости , но, похоже, все в порядке, если у вас нет умного хакера, пытающегосязлонамеренно обойти проверки контрольной суммы.
Обратите внимание, что из-за вышеуказанного изменения эта реализация не будет давать те же результаты, что и истинные реализации контрольной суммы Флетчера (@MDBiker).Таким образом, вы не можете сравнить вывод этой функции, например, с выводом Java Fletcher16.Однако будет всегда возвращать один и тот же результат для одного и того же ввода (он детерминирован), поэтому вы можете сравнить выходные данные этой функции в двух текстовых строках.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:foo="my.foo.org">
<xsl:variable name="str1">The quick brown fox jumps over the lazy dog.</xsl:variable>
<xsl:variable name="str2">The quick frown box jumps over the hazy frog.</xsl:variable>
<xsl:template match="/">
Checksum 1: <xsl:value-of select="foo:checksum($str1)"/>
Checksum 2: <xsl:value-of select="foo:checksum($str2)"/>
</xsl:template>
<xsl:function name="foo:checksum" as="xs:int">
<xsl:param name="str" as="xs:string"/>
<xsl:variable name="codepoints" select="string-to-codepoints($str)"/>
<xsl:value-of select="foo:fletcher16($codepoints, count($codepoints), 1, 0, 0)"/>
</xsl:function>
<!-- can I change some xs:integers to xs:int and help performance? -->
<xsl:function name="foo:fletcher16">
<xsl:param name="str" as="xs:integer*"/>
<xsl:param name="len" as="xs:integer" />
<xsl:param name="index" as="xs:integer" />
<xsl:param name="sum1" as="xs:integer" />
<xsl:param name="sum2" as="xs:integer"/>
<xsl:choose>
<xsl:when test="$index gt $len">
<xsl:sequence select="$sum2 * 256 + $sum1"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="newSum1" as="xs:integer"
select="($sum1 + $str[$index]) mod 255"/>
<xsl:sequence select="foo:fletcher16($str, $len, $index + 1, $newSum1,
($sum2 + $newSum1) mod 255)" />
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:stylesheet>
Вывод:
Checksum 1: 65256
Checksum 2: 25689
Замечание по использованию: Вы сказали, что вам нужно запустить контрольную сумму для «содержимого файла XML. В корне этого необходимо сравнить некоторые текстовые узлы».Если вы передадите текстовый узел в foo: checkum (), он будет работать нормально: его строковое значение будет извлечено.
К вашему сведению, я запустил тест производительности, чтобы вычислить контрольную сумму текстовых узлов в 535KB XMLвходной файл.Вот исходный шаблон, который я использовал:
<xsl:template match="/">
Checksum of input: <xsl:value-of
select="sum(for $t in //text() return foo:checksum($t)) mod 65536"/>
</xsl:template>
Он закончился через 0,8 с использованием Saxon PE.
В качестве альтернативы:
Если сумматекста не очень большой, вероятно, было бы быстрее и точнее просто сравнивать сами строки (вместо контрольных сумм) друг с другом.Но, возможно, вы не можете получить доступ к обоим текстовым узлам одновременно из-за ограничений вашей архитектуры ... Я не совсем понимаю это из вашего описания.