Использование XSL для создания хеша XML-файла - PullRequest
9 голосов
/ 20 июля 2011

Я пытаюсь найти способ "хэшировать" содержимое файла XML. В основе этого лежит необходимость сравнить некоторые текстовые узлы, которые передаются, с текстовыми узлами, которые я ожидаю, чтобы убедиться, что контрольная сумма одинакова. Переданные текстовые узлы вернулись из отправки формы, и я должен убедиться, что они не были изменены (в пределах разумного, исключая коллизии).

Архитектура ужасна, поэтому, пожалуйста, не спрашивайте об этом! Я привязан к конкретной реализации sharepoint с очень плохим пользовательским кодом, который мне нужно обойти.

Существует ли эффективная контрольная сумма / хэш-функция, которая может быть реализована? Мне нужно проверить около 100 текстовых узлов.

1 Ответ

14 голосов
/ 20 июля 2011

Похоже, вам нужна зависящая от позиции контрольная сумма .Вы запрашиваете реализацию 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.

В качестве альтернативы:

Если сумматекста не очень большой, вероятно, было бы быстрее и точнее просто сравнивать сами строки (вместо контрольных сумм) друг с другом.Но, возможно, вы не можете получить доступ к обоим текстовым узлам одновременно из-за ограничений вашей архитектуры ... Я не совсем понимаю это из вашего описания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...