При разработке интеграций в среде 1С:Предприятие 8 программисты часто сталкиваются с необходимостью выгрузки данных во внешние системы через формат JSON. Казалось бы, задача тривиальна: собрать данные в массив или структуру и вызвать стандартный метод ЗаписатьJSON. Однако на практике часто возникает ошибка «Передано значение недопустимого типа». Давайте разберем, почему это происходит, и изучим все возможные способы решения этой проблемы — от простых преобразований до системных подходов с использованием XDTO и потоковой записи.
Прежде всего, проанализируем ситуацию. Формат JSON является текстовым и строго ограничен в наборе типов данных, которые он может хранить «из коробки». Согласно синтакс-помощнику платформы 1С, метод ЗаписатьJSON может обрабатывать только следующие типы:
СтрокаЧислоБулевоДата (автоматически преобразуется в строку ISO)Массив и ФиксированныйМассивСтруктура и ФиксированнаяСтруктураСоответствие и ФиксированноеСоответствие (при условии, что ключи — строки)Основная проблема заключается в том, что объекты 1С, такие как СправочникСсылка (например, ссылка на номенклатуру), ДокументСсылка или ПеречислениеСсылка, не входят в этот список. Когда мы пытаемся передать структуру, содержащую ссылку на элемент справочника, платформа выдает исключение, так как она не «знает», как именно нужно представить этот сложный объект в текстовом виде.
Самый быстрый и очевидный способ, который мы можем применить — это преобразовать ссылку в строковое представление перед добавлением в структуру. Рассмотрим пример кода, где мы обходим таблицу значений и подготавливаем данные:
ТЗ = Объект.ИсходныеДанные.Выгрузить();
ЗаписьJSON = Новый ЗаписьJSON;
тПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, " ", Истина);
ЗаписьJSON.УстановитьСтроку(тПараметрыJSON);
МассивДанныхJSON = Новый Массив;
Для Каждого Строка Из ТЗ Цикл
тДанные = Новый Структура;
// Вместо прямой передачи ссылки используем XMLСтрока или Строка()
тДанные.Вставить("Товар", XMLСтрока(Строка.Номенклатура));
тДанные.Вставить("Код", Строка.Номенклатура.Код);
МассивДанныхJSON.Добавить(тДанные);
КонецЦикла;
СтруктураДанныхJSON = Новый Структура("test", МассивДанныхJSON);
ЗаписатьJSON(ЗаписьJSON, СтруктураДанныхJSON);
СтрокаJS = ЗаписьJSON.Закрыть();
Здесь мы использовали функцию XMLСтрока. Она удобна тем, что возвращает уникальный идентификатор объекта в формате, который легко прочитать обратно в 1С. Однако, если данные предназначены для внешней веб-системы, лучше использовать Строка(Строка.Номенклатура.УникальныйИдентификатор()), чтобы передать чистый GUID.
Если в нашей структуре очень много разных полей со ссылками, ручное преобразование каждого поля становится трудоемким. В этом случае мы можем применить более элегантный системный подход — функцию преобразования. Это специальная экспортная функция, которую платформа будет вызывать автоматически каждый раз, когда встретит тип, который она не может записать самостоятельно.
Разберем, как это реализовать. Сначала укажем имя функции при вызове ЗаписатьJSON:
// В модуле обработки или сервера
ЗаписатьJSON(ЗаписьJSON, СтруктураДанныхJSON, "МояФункцияПреобразования");
Затем опишем саму логику в этой функции:
Функция МояФункцияПреобразования(Значение, ДополнительныеПараметры, Отказ) Экспорт
Если ТипЗнч(Значение) = Тип("СправочникСсылка.Номенклатура") Тогда
Возврат Строка(Значение.УникальныйИдентификатор());
ИначеЕсли ТипЗнч(Значение) = Тип("Дата") Тогда
Возврат Формат(Значение, "ДФ=yyyy-MM-dd");
КонецЕсли;
// Если тип нам не знаком, платформа сама решит, что делать (или выдаст ошибку)
Возврат Значение;
КонецФункции
Этот метод позволяет отделить логику формирования структуры данных от логики их представления в JSON, что делает код чище и профессиональнее.
Для случаев, когда нужно выгрузить объект 1С целиком со всеми его реквизитами (например, для обмена между двумя базами 1С), лучше всего использовать СериализаторXDTO. Этот инструмент позволяет автоматически преобразовать объект в формат, поддерживаемый JSON, сохраняя структуру метаданных.
Посмотрим на пример записи через XDTO:
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
// Записываем объект напрямую через сериализатор
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, СсылкаНаНоменклатуру, НазначениеТипаXML.Явное);
Результат = ЗаписьJSON.Закрыть();
Этот способ избавляет нас от необходимости вручную создавать структуры через Новый Структура и использовать ЗаполнитьЗначенияСвойств. Платформа сама сформирует объект JSON со всеми полями справочника.
Если ваша таблица значений (ТЗ) содержит десятки или сотни тысяч строк, попытка собрать их в один массив МассивДанныхJSON может привести к чрезмерному потреблению оперативной памяти и даже к аварийному завершению работы программы. В таких ситуациях мы рекомендуем использовать потоковую запись.
Проанализируем пример, как записывать данные порциями, не создавая огромных промежуточных объектов в памяти:
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписьJSON.ЗаписатьНачалоОбъекта(); // Начинаем корень JSON
ЗаписьJSON.ЗаписатьИмяСвойства("Товары");
ЗаписьJSON.ЗаписатьНачалоМассива(); // Начинаем массив элементов
Для Каждого Строка Из ТЗ Цикл
ЗаписьJSON.ЗаписатьНачалоОбъекта();
ЗаписьJSON.ЗаписатьИмяСвойства("Наименование");
ЗаписьJSON.ЗаписатьЗначение(Строка.Номенклатура.Наименование);
ЗаписьJSON.ЗаписатьИмяСвойства("ID");
ЗаписьJSON.ЗаписатьЗначение(XMLСтрока(Строка.Номенклатура));
ЗаписьJSON.ЗаписатьКонецОбъекта();
КонецЦикла;
ЗаписьJSON.ЗаписатьКонецМассива();
ЗаписьJSON.ЗаписатьКонецОбъекта();
СтрокаРезультат = ЗаписьJSON.Закрыть();
При таком подходе данные сразу пишутся в поток (строку или файл), что значительно повышает стабильность системы при работе с Big Data.
Важно помнить, что объект ПараметрыЗаписиJSON позволяет гибко управлять форматом. Например, мы можем настроить обработку значений NULL или Неопределено. В некоторых внешних API отсутствие поля критично, а в других — поле обязательно должно содержать null. Используйте соответствующие свойства объекта параметров, чтобы ваша интеграция работала корректно.
Подведем итог: если вы столкнулись с ошибкой недопустимого типа, проверьте, не передаете ли вы ссылки. Используйте XMLСтрока для простых случаев, Callback-функции для сложных структур и XDTO для полной сериализации объектов. А для работы с большими массивами данных всегда отдавайте предпочтение потоковой записи.