Почему при использовании функции восстановления в СериализаторXDTO.ПрочитатьJSON портится Таблица Значений?

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

При работе с механизмом JSON-сериализации в 1С программисты часто сталкиваются с необходимостью восстановить специфические типы данных, которые не поддерживаются форматом JSON напрямую (например, ПеречислениеСсылка или конкретные ссылки на объекты базы данных). Для этого в методе СериализаторXDTO.ПрочитатьJSON предусмотрен параметр "ИмяФункцииВосстановления". Однако при попытке прочитать таким образом ТаблицуЗначений пользователи часто обнаруживают, что результат получается "кривым": структура таблицы разрушается, появляются непонятные вложенные строки, а данные в колонках отсутствуют.

В этой статье мы подробно разберем, почему это происходит, как платформа 1С интерпретирует структуру ТаблицыЗначений через XDTO и как правильно написать функцию восстановления, чтобы не испортить данные.

Разбор механизма работы СериализаторXDTO с Таблицей Значений

Для начала проанализируем, как 1С представляет ТаблицуЗначений в формате JSON. В отличие от простого массива структур, который мы получаем через стандартный метод ПрочитатьJSON, СериализаторXDTO использует строгую схему. Если мы посмотрим на сериализованный JSON, мы увидим, что таблица разбита на два основных блока: описание колонок (метаданные) и сами строки с данными.

Важно понимать: когда вы подключаете функцию восстановления, платформа начинает вызывать её для каждого узла этой сложной структуры. Это касается не только конечных значений в ячейках, но и технических элементов, описывающих саму таблицу. Если ваша функция восстановления написана некорректно или возвращает Неопределено (либо пустую строку) там, где платформа ожидает объект XDTO, вся цепочка восстановления разрывается.

Проблема "пустой" функции восстановления

Рассмотрим типичную ситуацию: разработчик подключает функцию восстановления, но еще не успел написать в ней логику преобразования, оставив тело функции пустым или возвращая пустую строку. В этом случае ТаблицаЗначений на выходе превращается в "кашу".

Выясним причину: при обработке каждой ячейки СериализаторXDTO встречает объект, который в JSON часто помечен ключом "Value". Платформа передает этот объект в вашу функцию восстановления. Если функция ничего не возвращает, сериализатор считает, что значение объекта теперь равно Неопределено. В итоге вместо данных в таблицу записываются пустые значения, а структурные элементы XDTO интерпретируются как обычные строки, что и создает эффект "вложенности".

Правильная реализация функции восстановления

Главное правило при работе с функцией восстановления: вы обязаны всегда возвращать значение. Если текущий элемент не требует преобразования, вы должны вернуть его в неизменном виде. Проанализируем пример правильной функции:


&НаСервере
Функция ПрочитатьТипизациюJSON(Свойство, Тип, Значение, ДополнительныеПараметры) Экспорт
    
    // Если мы просто проходим мимо и ничего не меняем, 
    // обязательно возвращаем входящее 'Значение'
    Возврат Значение;
    
КонецФункции

Рассмотрим параметры, которые приходят в эту функцию:

  1. Свойство: содержит имя текущего обрабатываемого свойства (например, "Value").
  2. Тип: тип XDTO, который ожидает платформа.
  3. Значение: само значение (это может быть как простая строка, так и ЗначениеXDTO).
  4. ДополнительныеПараметры: произвольные данные, переданные в метод чтения.

Пример полного цикла: запись и чтение Таблицы Значений

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


&НаСервере
Процедура ВыполнитьСериализациюТЗ()
    
    // 1. Подготовим исходную таблицу значений
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 5
        |   Номенклатура.Наименование КАК Наим,
        |   Номенклатура.Комментарий КАК Ком
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура";
    
    ТЗ = Запрос.Выполнить.Выгрузить();
    
    // 2. Сериализуем ТЗ в строку JSON
    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку();
    СериализаторXDTO.ЗаписатьJSON(Запись, ТЗ);
    ТЗJSON = Запись.Закрыть();
    
    // 3. Подготовимся к чтению с восстановлением
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(ТЗJSON);
    
    // Определим типы, для которых должна вызываться функция восстановления
    // В данном примере укажем тип 'string' из пространства имен XSD
    ВосстановимТип = ФабрикаXDTO.Тип("http://www.w3.org/2001/XMLSchema", "string");
    МассивВосстановления = Новый Массив;
    МассивВосстановления.Добавить(ВосстановимТип);
    
    // 4. Читаем ТЗ обратно
    // Обратите внимание на передачу 'ЭтаФорма' как контекста для функции восстановления
    ТЗ_Восстановленная = СериализаторXDTO.ПрочитатьJSON(
        Чтение, 
        Тип("ТаблицаЗначений"), 
        "ПрочитатьТипизациюJSON", 
        ЭтаФорма, 
        , 
        МассивВосстановления
    );
    
    Чтение.Закрыть();
    
КонецПроцедуры

Нюансы с версиями платформы

При работе с СериализаторXDTO крайне важно учитывать версию платформы 1С:Предприятие. В версиях ниже 8.3.27 наблюдались ошибки, когда платформа могла аварийно завершать работу (вылетать), если в ПрочитатьJSON не передавался массив восстанавливаемых типов, но была указана функция восстановления. Также в более старых релизах механизм XDTO мог некорректно обрабатывать вложенные коллекции при вмешательстве внешнего обработчика.

Проанализируем ситуацию, описанную в сообщениях форума: переход с платформы 8.3.24 на 8.3.27 решает часть проблем с нестабильностью, однако логика возврата значения остается неизменной. Если вы используете современную платформу, убедитесь, что функция восстановления помечена префиксом &НаСервере и имеет ключевое слово Экспорт, если она находится в модуле формы или другом контекстном модуле.

Как идентифицировать конкретную колонку в функции восстановления?

Один из самых сложных вопросов: как в функции восстановления понять, какое именно поле мы сейчас обрабатываем? Как заметили участники обсуждения, в параметр Свойство часто приходит техническое имя "Value", которое ни о чем не говорит программисту.

Рассмотрим способы решения этой задачи:

Подведем итоги

Использование СериализаторXDTO.ПрочитатьJSON для сложных типов, таких как ТаблицаЗначений, требует внимательного отношения к функции восстановления. Чтобы структура вашей ТЗ не "поплыла", всегда придерживайтесь следующих правил:

  1. Обязательный возврат: Функция всегда должна возвращать результат. Если преобразование не требуется — возвращайте исходное Значение.
  2. Фильтрация типов: Передавайте в метод массив типов, которые действительно требуют восстановления, чтобы не нагружать функцию лишними вызовами для каждой строки и каждой колонки.
  3. Контекст и экспорт: Убедитесь, что функция доступна (Экспорт) и вызывается в правильном контексте.
  4. Обновление платформы: Если вы сталкиваетесь с нелогичным поведением или ошибками доступа к памяти при сериализации, попробуйте обновить платформу до актуального релиза (не ниже 8.3.27).

Если же задача по восстановлению типов в ТЗ кажется слишком громоздкой через XDTO, рассмотрите альтернативный вариант: прочитать JSON в массив структур через обычный ПрочитатьJSON, а затем программно заполнить ТаблицуЗначений, преобразуя типы вручную. Это даст вам полный контроль над процессом, хотя и потребует чуть больше кода.

← На главную