При работе с подсистемой Версионирование объектов в составе Библиотеки стандартных подсистем (БСП) программисты часто сталкиваются с необходимостью программного анализа прошлых версий документов или справочников. Типичная задача — получить номер документа или значение конкретного реквизита из определенной версии в истории. Однако при попытке прочитать данные напрямую из регистра сведений ВерсииОбъектов вместо привычного XML-кода часто получается нечитаемая строка с символами . Разберем, почему это происходит и как правильно извлекать данные.
Проанализируем ситуацию: в регистре ВерсииОбъектов данные хранятся в ресурсе ВерсияОбъекта, который имеет тип ХранилищеЗначения. Когда мы извлекаем данные методом Получить(), мы получаем объект типа ДвоичныеДанные. Попытка прочитать эти данные напрямую через ЧтениеДанных.ПрочитатьСимволы() с указанием кодировки КодировкаТекста.UTF8 приводит к появлению "мусора".
Рассмотрим причины такого поведения платформы:
СериализаторXDTO.Посмотрим на пример того, как выглядят "сырые" данные в бинарном виде, если их не распаковать:
// Пример того, что видит программист при ошибке
E0 00 00 01 00 78 CF 02 78 73 69 28 68 74 74 70 3A 2F 2F 77 77 77 2E...
// После попытки чтения:
x xsi(http://www.w3.org/2001/XMLSchema-instance
Самый надежный метод — не пытаться "изобрести велосипед", а использовать программный интерфейс самой БСП. В общем модуле ВерсионированиеОбъектов (или аналогичном в вашей версии БСП) существуют функции, которые учитывают все нюансы упаковки данных.
Разберем по шагам, как получить объект из версии:
// Выбираем версию из регистра
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВерсииОбъектов.ВерсияОбъекта КАК ДанныеВерсии
|ИЗ
| РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|ГДЕ
| ВерсииОбъектов.Объект = &Объект И ВерсииОбъектов.НомерВерсии = &НомерВерсии";
Запрос.УстановитьПараметр("Объект", СсылкаНаДокумент);
Запрос.УстановитьПараметр("НомерВерсии", 1);
Результат = Запрос.Выполнить().Выбрать();
Если Результат.Следующий() Тогда
// Используем штатный метод БСП для получения объекта
// В зависимости от версии БСП имя функции может отличаться
// Например, ВерсионированиеОбъектов.ОбъектИзХранилища()
ОбъектВерсии = ВерсионированиеОбъектов.ОбъектИзХранилища(Результат.ДанныеВерсии);
// Теперь у нас есть объект, из которого можно прочитать реквизиты
Сообщить("Номер из версии: " + ОбъектВерсии.Номер);
КонецЕсли;
Если по какой-то причине вы не можете использовать функции БСП или вам нужно получить именно строку XML для специфической обработки, необходимо выполнить распаковку данных. Проанализируем, как это сделать программно.
Нам потребуется использовать объект ЧтениеXML и СериализаторXDTO. Важно понимать, что если данные были сжаты методом СжатиеДанных, платформа часто умеет автоматически распознавать это при помещении двоичных данных в поток чтения.
Рассмотрим пример реализации:
// Получаем двоичные данные из хранилища
ДвоичныеДанные = РезультатЗапроса[0].ВерсияОбъекта.Получить();
// Создаем чтение XML
ЧтениеXML = Новый ЧтениеXML;
// Попытка инициализировать чтение двоичными данными
// Платформа 1С v8.3 умеет обрабатывать сжатые потоки в ЧтениеXML
ЧтениеXML.УстановитьДвоичныеДанные(ДвоичныеДанные);
// Используем СериализаторXDTO для восстановления объекта
Попытка
ОбъектВосстановленный = СериализаторXDTO.ПрочитатьXDTO(ЧтениеXML);
// Теперь можно обратиться к свойствам объекта XDTO
ЗначениеНомера = ОбъектВосстановленный.Number;
Исключение
Сообщить("Ошибка десериализации: " + ОписаниеОшибки());
КонецПопытки;
Важный момент: Если в ЧтениеXML всё равно попадают "битые" данные, значит, данные были принудительно сжаты алгоритмом Deflate. В этом случае перед чтением XML их нужно прогнать через ЧтениеСжатыхДанных.
Некоторые разработчики, сталкиваясь с символами , пытаются решить проблему "костылями", используя функцию СтрНайти() для поиска номера или даты прямо в бинарном мусоре. Выясним, почему это опасно:
Для корректной работы с историей версий объектов всегда придерживайтесь следующего алгоритма:
Получить() для объекта ХранилищеЗначения.ДвоичныеДанные как обычный текст через ЧтениеДанных.ПрочитатьСимволы().ЧтениеXML.УстановитьДвоичныеДанные() для автоматической обработки формата.ВерсионированиеОбъектов.ОбъектИзХранилища() из состава БСП, так как она инкапсулирует в себе все проверки на сжатие и формат сериализации.Таким образом, соблюдение стандартов разработки 1С и использование встроенных механизмов десериализации позволяет избежать ошибок с кодировкой и гарантирует получение достоверных данных из истории изменений.