При попытке реализовать механизм контроля изменений объектов в 1С часто возникает задача «снятия снимка» состояния документа. Самый простой путь — сериализовать документ в XML, получить текстовую строку и вычислить для неё хэш-сумму (например, MD5). Однако на практике разработчики сталкиваются с тем, что для одного и того же объекта в разных базах данных ХешированиеДанных выдает разные результаты, несмотря на визуальное сходство данных.
После детального анализа ситуации выяснилось, что проблема кроется не в ошибках алгоритма ХешированиеДанных, а в побайтовом представлении данных, полученных методом ЗаписьXML.Закрыть. Когда мы выполняем сериализацию объекта в 1С, итоговая строка может содержать разные управляющие символы.
Основная причина расхождения хэшей — различие в символах окончания строки (Line Endings). В зависимости от операционной системы (Windows использует комбинацию 0x0D 0x0A, то есть CRLF, а Unix/Linux — только 0x0A, то есть LF) 1С формирует разное байтовое наполнение XML-файла. При сравнении через текстовые редакторы эти символы могут игнорироваться или отображаться как обычный перенос, но для хэш-функции изменение даже одного байта в строке приводит к полному изменению итоговой суммы.
Для того чтобы самостоятельно убедиться в причине расхождений, выполним следующие шаги:
ТекстовыйДокумент в обеих базах.Total Commander или специализированные утилиты).0x0D.Поскольку сериализация в XML зависит от настроек платформы и ОС, данный метод нельзя считать абсолютно надежным для сравнения «снимков» объектов. Рассмотрим более корректные подходы для решения этой задачи:
Если вы все же решили использовать хэширование строки, необходимо привести её к «нормализованному» виду. Разберем пример программной очистки данных перед вычислением хэша:
// Получаем XML как строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписатьXML(ЗаписьXML, Ссылка.ПолучитьОбъект());
ДанныеСтрока = ЗаписьXML.Закрыть();
// Очищаем от невидимых управляющих символов
ДанныеСтрока = СтрЗаменить(ДанныеСтрока, \" \", \"\");
ДанныеСтрока = СтрЗаменить(ДанныеСтрока, Символы.ВК, \"\");
ДанныеСтрока = СтрЗаменить(ДанныеСтрока, Символы.ВТаб, \"\");
ДанныеСтрока = СтрЗаменить(ДанныеСтрока, Символы.НПП, \"\");
ДанныеСтрока = СтрЗаменить(ДанныеСтрока, Символы.ПС, \"\");
ДанныеСтрока = СтрЗаменить(ДанныеСтрока, Символы.ПФ, \"\");
ДанныеСтрока = СтрЗаменить(ДанныеСтрока, Символы.Таб, \"\");
// Вычисляем хеш
Хеш = Новый ХешированиеДанных(ХешФункция.MD5);
Хеш.Добавить(ДанныеСтрока);
Результат = Хеш.ХешСумма;
Вместо стандартной записи XML рассмотрите использование СериализаторXDTO. Работа через XDTO абстрагирует вас от физического представления XML-узлов и позволяет оперировать данными на уровне типов 1С. Это значительно снижает риск влияния платформенных особенностей сериализации на итоговый результат.
Самым надежным способом сравнения объектов, который исключает влияние любых внешних факторов, является перебор реквизитов объекта через Метаданные:
Для Каждого Реквизит Из Метаданные.Документы.ИмяВашегоДокумента.Реквизиты Цикл
Значение1 = Объект1[Реквизит.Имя];
Значение2 = Объект2[Реквизит.Имя];
Если Значение1 <> Значение2 Тогда
Сообщить(\"Найдены различия в реквизите: \" + Реквизит.Имя);
КонецЕсли;
КонецЦикла;
Важное предостережение: Помните, что MD5 — это 128-битный хэш. При большом объеме сравниваемых данных существует теоретическая вероятность коллизий (когда у разных наборов данных хэш-сумма совпадает). Для высококритичных задач контроля целостности данных лучше использовать более современные алгоритмы хэширования или прямое пополевое сравнение значений.
Таким образом, если вы столкнулись с проблемой разных хэшей, в первую очередь ищите различия в невидимых спецсимволах переноса строк, а для надежных решений — переходите от текстовой сериализации к прямому сравнению значений реквизитов.