Как исправить ошибку преобразования данных XDTO при чтении JSON в 1С

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

При работе с механизмами обмена данными в 1С:Предприятие программисты часто сталкиваются с ситуацией, когда стандартный СериализаторXDTO отказывается корректно читать JSON-строку, которую сам же и создал. Типичная ошибка выглядит так: «Ошибка преобразования данных XDTO: НачалоСвойства: Форма: Элемент Тип...». Это происходит в тот момент, когда мы пытаемся восстановить структуру данных, массив или таблицу значений из текстовой строки обратно в объекты 1С.

В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем механизмы работы XDTO и выясним, какие параметры необходимо передать при записи данных, чтобы десериализация прошла успешно. Мы рассмотрим несколько стратегий решения — от «обертывания» в массивы до использования явного указания типов метаданных.

Разбор причины возникновения ошибки

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

Ошибка «НачалоСвойства» обычно сигнализирует о том, что при чтении JSON-поток содержит данные, тип которых СериализаторXDTO не может определить однозначно. Если при записи в JSON не была сохранена информация о типе (метаданные), то при чтении система видит открывающуюся фигурную скобку { и ожидает найти там описание типа, но встречает обычное свойство объекта. Это вызывает конфликт в логике парсера XDTO.

Решение №1: Использование явного назначения типа XML

Как показывает практика и обсуждения опытных разработчиков, самым надежным способом решения проблемы является использование параметра НазначениеТипаXML.Явное. Рассмотрим подробнее, как это изменить в коде.

Проанализируем пример функции сериализации, которая гарантирует корректное последующее чтение:


Функция СериализоватьЗначениеВСтрокуJSON(ТекущиеДанные) Экспорт
    
    ЗаписьJSON = Новый ЗаписьJSON;
    // Настраиваем параметры записи, отключая перенос строк для компактности
    ПараметрыЗаписиJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, , Ложь);
    ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписиJSON);
    
    // Ключевой момент: НазначениеТипаXML.Явное
    // Это заставит 1С добавить в JSON информацию о типах объектов
    СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, ТекущиеДанные, НазначениеТипаXML.Явное);
    
    Возврат ЗаписьJSON.Закрыть();
    
КонецФункции

Когда мы используем НазначениеТипаXML.Явное, в результирующий JSON добавляются специальные служебные поля (атрибуты), которые подсказывают десериализатору, во что именно нужно превратить данный набор полей. Это особенно важно для таких объектов, как ТаблицаЗначений или вложенные структуры с массивами.

Теперь функция десериализации будет работать без ошибок:


Функция ДесериализоватьЗначениеИзJSON(СтрокаJSON) Экспорт
    
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
    
    // Теперь СериализаторXDTO увидит типы в строке и поймет, как их прочитать
    ПолученныеДанные = СериализаторXDTO.ПрочитатьJSON(ЧтениеJSON);
    
    ЧтениеJSON.Закрыть();
    
    Возврат ПолученныеДанные;
    
КонецФункции

Решение №2: Обертывание данных в массив

В некоторых случаях, особенно на старых релизах платформы (например, до 8.3.14), наблюдалась странная особенность: СериализаторXDTO мог выдавать ошибку на корневом объекте, если это была сложная структура, но при этом корректно обрабатывал те же данные, если они являлись элементами массива. Разберем этот обходной путь (workaround).

Суть метода заключается в том, чтобы перед записью поместить наш объект в массив, а после чтения извлечь его обратно из первого элемента массива.

Запись с использованием массива:


ПромежуточныйМассив = Новый Массив;
ПромежуточныйМассив.Добавить(ТекущиеДанные);

ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, ПромежуточныйМассив, НазначениеТипаXML.Явное);
Результат = ЗаписьJSON.Закрыть();

Чтение из массива:


ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
РезультатМассив = СериализаторXDTO.ПрочитатьJSON(ЧтениеJSON);
// Извлекаем наш исходный объект
Если РезультатМассив.Количество() > 0 Тогда
    ИсходныеДанные = РезультатМассив[0];
КонецЕсли;

Хотя этот метод помогает в ряде специфических случаев, мы рекомендуем в первую очередь использовать Явное назначение типа, так как это более "чистый" подход с точки зрения архитектуры 1С.

Решение №3: Использование стандартных функций JSON (без XDTO)

Нужно понимать, что СериализаторXDTO — это не единственный и не всегда лучший способ работы с JSON. Если вашей задачей не является передача сложных специфических объектов (например, ТаблицыЗначений с сохранением типов колонок), а вам нужно просто передать данные в формате Структура или Массив, лучше воспользоваться глобальными функциями платформы.

Разберем ситуацию: если вы обмениваетесь данными со сторонним сервисом (написанным на Python, JS или другом языке), использование СериализаторXDTO категорически не рекомендуется, так как внешние системы не поймут служебные типы 1С.

Рассмотрим пример "простого" и безопасного чтения:


Функция ПреобразоватьJSONВСтруктуру(СтрокаJSON) Экспорт
    
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
    
    // Используем глобальную функцию ПрочитатьJSON вместо СериализаторXDTO
    // Она преобразует JSON в обычные структуры и массивы 1С
    Данные = ПрочитатьJSON(ЧтениеJSON);
    
    ЧтениеJSON.Закрыть();
    
    Возврат Данные;
    
КонецФункции

Этот метод никогда не выдаст ошибку "Ошибка преобразования данных XDTO", так как он вообще не использует механизмы XDTO. Он просто разбирает синтаксис JSON.

Сравнение подходов: что выбрать?

Для того чтобы окончательно определиться с выбором метода, проанализируем таблицу соответствия задач и инструментов:

  1. Обмен между двумя базами 1С: Используем СериализаторXDTO с обязательным параметром НазначениеТипаXML.Явное. Это гарантирует, что если вы передали ТаблицуЗначений, то на приемной стороне вы получите именно ТаблицуЗначений, а не массив структур.
  2. Обмен с внешним сайтом или мобильным приложением: Используем глобальные функции ЗаписатьJSON и ПрочитатьJSON. Это обеспечит максимальную совместимость.
  3. Передача простых структур внутри одной базы (например, в фоновое задание): Также лучше использовать ПрочитатьJSON, так как это работает быстрее и требует меньше кода.

Особенности работы с Таблицей Значений

Важный момент, который часто упускают: ТаблицаЗначений не является базовым типом JSON. Чтобы передать её через СериализаторXDTO, система должна сначала описать структуру колонок. Если вы вручную сформировали JSON, имитирующий таблицу, но не добавили туда описание типов XDTO, СериализаторXDTO.ПрочитатьJSON выдаст ту самую ошибку на «НачалеСвойства».

Выясним, как правильно передавать ТЗ:

  1. Выгружаем данные в массив структур, если типы колонок не критичны.
  2. Если типы колонок важны (например, для дальнейших запросов к этой ТЗ), используем СериализаторXDTO только с флагом Явное.
  3. Если ошибка сохраняется даже с флагом Явное, проверьте версию платформы. В версиях ниже 8.3.13 были зафиксированы ошибки десериализации пустых массивов внутри типизированных объектов.

Таким образом, мы выяснили, что большинство проблем с чтением JSON через XDTO решается правильной настройкой записи данных. Всегда следите за тем, чтобы ЗаписьJSON и ЧтениеJSON работали в паре с одинаковыми ожиданиями относительно метаданных типов.

← На главную