Как правильно получить данные из истории версий объектов 1С и избежать появления символов

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с подсистемой Версионирование объектов в составе Библиотеки стандартных подсистем (БСП) программисты часто сталкиваются с необходимостью программного анализа прошлых версий документов или справочников. Типичная задача — получить номер документа или значение конкретного реквизита из определенной версии в истории. Однако при попытке прочитать данные напрямую из регистра сведений ВерсииОбъектов вместо привычного XML-кода часто получается нечитаемая строка с символами . Разберем, почему это происходит и как правильно извлекать данные.

Выясняем причину: почему данные отображаются некорректно

Проанализируем ситуацию: в регистре ВерсииОбъектов данные хранятся в ресурсе ВерсияОбъекта, который имеет тип ХранилищеЗначения. Когда мы извлекаем данные методом Получить(), мы получаем объект типа ДвоичныеДанные. Попытка прочитать эти данные напрямую через ЧтениеДанных.ПрочитатьСимволы() с указанием кодировки КодировкаТекста.UTF8 приводит к появлению "мусора".

Рассмотрим причины такого поведения платформы:

  1. Сжатие данных (Deflate/ZIP): Для экономии места в базе данных БСП сжимает XML-представление объекта перед помещением в хранилище. То, что мы видим как "неизвестные символы", на самом деле является заголовком и телом сжатого бинарного потока.
  2. Формат Fast Infoset: Современные версии платформы 1С и БСП могут использовать бинарный формат XML (Fast Infoset). Он гораздо компактнее текстового формата, но не предназначен для прямого чтения как обычный текст.
  3. Сериализация XDTO: Объект в истории версий — это не просто выгрузка в XML, а сериализованный объект XDTO. Для его корректного восстановления требуется использовать механизмы Сериализатор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: Использование штатных функций БСП (рекомендуемый)

Самый надежный метод — не пытаться "изобрести велосипед", а использовать программный интерфейс самой БСП. В общем модуле ВерсионированиеОбъектов (или аналогичном в вашей версии БСП) существуют функции, которые учитывают все нюансы упаковки данных.

Разберем по шагам, как получить объект из версии:


// Выбираем версию из регистра
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВерсииОбъектов.ВерсияОбъекта КАК ДанныеВерсии
    |ИЗ
    |	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
    |ГДЕ
    |	ВерсииОбъектов.Объект = &Объект И ВерсииОбъектов.НомерВерсии = &НомерВерсии";

Запрос.УстановитьПараметр("Объект", СсылкаНаДокумент);
Запрос.УстановитьПараметр("НомерВерсии", 1);
Результат = Запрос.Выполнить().Выбрать();

Если Результат.Следующий() Тогда
    // Используем штатный метод БСП для получения объекта
    // В зависимости от версии БСП имя функции может отличаться
    // Например, ВерсионированиеОбъектов.ОбъектИзХранилища()
    ОбъектВерсии = ВерсионированиеОбъектов.ОбъектИзХранилища(Результат.ДанныеВерсии);
    
    // Теперь у нас есть объект, из которого можно прочитать реквизиты
    Сообщить("Номер из версии: " + ОбъектВерсии.Номер);
КонецЕсли;

Способ 2: Ручная распаковка и чтение через XML

Если по какой-то причине вы не можете использовать функции БСП или вам нужно получить именно строку XML для специфической обработки, необходимо выполнить распаковку данных. Проанализируем, как это сделать программно.

Нам потребуется использовать объект ЧтениеXML и СериализаторXDTO. Важно понимать, что если данные были сжаты методом СжатиеДанных, платформа часто умеет автоматически распознавать это при помещении двоичных данных в поток чтения.

Рассмотрим пример реализации:


// Получаем двоичные данные из хранилища
ДвоичныеДанные = РезультатЗапроса[0].ВерсияОбъекта.Получить();

// Создаем чтение XML
ЧтениеXML = Новый ЧтениеXML;

// Попытка инициализировать чтение двоичными данными
// Платформа 1С v8.3 умеет обрабатывать сжатые потоки в ЧтениеXML
ЧтениеXML.УстановитьДвоичныеДанные(ДвоичныеДанные);

// Используем СериализаторXDTO для восстановления объекта
Попытка
    ОбъектВосстановленный = СериализаторXDTO.ПрочитатьXDTO(ЧтениеXML);
    // Теперь можно обратиться к свойствам объекта XDTO
    ЗначениеНомера = ОбъектВосстановленный.Number; 
Исключение
    Сообщить("Ошибка десериализации: " + ОписаниеОшибки());
КонецПопытки;

Важный момент: Если в ЧтениеXML всё равно попадают "битые" данные, значит, данные были принудительно сжаты алгоритмом Deflate. В этом случае перед чтением XML их нужно прогнать через ЧтениеСжатыхДанных.

Почему поиск подстроки через СтрНайти — это плохая практика

Некоторые разработчики, сталкиваясь с символами , пытаются решить проблему "костылями", используя функцию СтрНайти() для поиска номера или даты прямо в бинарном мусоре. Выясним, почему это опасно:

Резюме

Для корректной работы с историей версий объектов всегда придерживайтесь следующего алгоритма:

  1. Всегда проверяйте, используете ли вы метод Получить() для объекта ХранилищеЗначения.
  2. Никогда не читайте полученные ДвоичныеДанные как обычный текст через ЧтениеДанных.ПрочитатьСимволы().
  3. Используйте ЧтениеXML.УстановитьДвоичныеДанные() для автоматической обработки формата.
  4. Лучшим решением будет вызов функции ВерсионированиеОбъектов.ОбъектИзХранилища() из состава БСП, так как она инкапсулирует в себе все проверки на сжатие и формат сериализации.

Таким образом, соблюдение стандартов разработки 1С и использование встроенных механизмов десериализации позволяет избежать ошибок с кодировкой и гарантирует получение достоверных данных из истории изменений.

← На главную