При работе с интеграциями программисты 1С часто сталкиваются с ситуацией, когда один и тот же объект XDTO по-разному представляется в форматах XML и JSON. Если в XML мы видим четкую древовидную структуру с повторяющимися тегами для каждой строки коллекции, то при вызове метода ЗаписатьJSON платформа 1С автоматически «схлопывает» эти теги, создавая простой массив объектов. В этой статье мы подробно разберем, почему так происходит, и какими способами можно заставить систему сохранить имя вложенного тега в итоговом JSON-файле.
Рассмотрим классическую ситуацию. У нас есть XDTO-пакет, в котором определена коллекция (например, табличная часть). В XML-представлении это выглядит логично:
<ТЧ_ИзменениеКоллекции>
<Строка>
<Дата>2001-01-01T00:00:00</Дата>
<Коллекция>НоваяКоллекция</Коллекция>
</Строка>
<Строка>
<Дата>2017-04-01T00:00:00</Дата>
<Коллекция>Сток</Коллекция>
</Строка>
</ТЧ_ИзменениеКоллекции>
Однако при выполнении стандартного кода сериализации в JSON ситуация меняется:
ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(,,,,Истина,Истина,Истина,Истина,Истина);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
МояФабрикаXDTO.ЗаписатьJSON(ЗаписьJSON, МоиДанные, НазначениеТипаXML.Явное);
Результат = ЗаписьJSON.Закрыть();
На выходе мы получаем структуру, где имя тега Строка полностью отсутствует:
"ТЧ_ИзменениеКоллекции": [
{ "Дата": "2001-01-01T00:00:00", "Коллекция": "НоваяКоллекция" },
{ "Дата": "2017-04-01T00:00:00", "Коллекция": "Сток" }
]
Для сторонних систем, ожидающих строгого соответствия (например, "Строка": {...} внутри массива), такой формат может оказаться неприемлемым. Выясним причину такого поведения платформы.
Разберем, почему 1С ведет себя именно так. В формате XML не существует понятия «массив» в том виде, в котором он есть в языках программирования. Чтобы передать список элементов, XML вынужден повторять имя узла (в нашем примере это Строка). В формате JSON, напротив, массивы являются базовой конструкцией. Платформа 1С при чтении схемы XDTO видит свойство с параметром MaxOccurs > 1 и понимает, что перед ней коллекция. При записи в JSON она интерпретирует имя родительского свойства (ТЧ_ИзменениеКоллекции) как ключ массива, а сами элементы вкладывает в массив напрямую, считая промежуточный тег Строка избыточным «техническим» мусором.
Тем не менее, если требования протокола обмена жестко задают наличие вложенного ключа, нам придется прибегнуть к одному из следующих решений.
Самый правильный с точки зрения архитектуры XDTO способ — это модификация самого пакета. Мы можем обмануть механизм сериализации, добавив дополнительный уровень вложенности. Проанализируем шаги:
ТипОбъекта, назовем его, например, ЭлементСпискаСтрок.Строка. Типом этого свойства должен быть ваш исходный тип данных (с датой и коллекцией).ТЧ_ИзменениеКоллекции) укажем, что элементами списка являются объекты типа ЭлементСпискаСтрок.В этом случае при сериализации в JSON платформа увидит массив объектов. Каждый объект массива будет иметь свойство Строка. Итоговый файл примет нужный вид:
"ТЧ_ИзменениеКоллекции": [
{ "Строка": { "Дата": "...", "Коллекция": "..." } },
{ "Строка": { "Дата": "...", "Коллекция": "..." } }
]
Если изменять схему XDTO нельзя (например, она предоставлена внешним контрагентом), мы можем преобразовать данные вручную перед записью в JSON. Для этого нам потребуется переложить данные из объекта XDTO в Массив и Структуры (или Соответствия).
Рассмотрим пример кода для такой трансформации:
// Создаем массив, который станет основой JSON-списка
СписокДляJSON = Новый Массив;
// Обходим данные из XDTO-объекта
Для Каждого ЭлементXDTO Из МоиДанные.ТЧ_ИзменениеКоллекции Цикл
// Для каждого элемента создаем структуру-обертку с нужным ключом
Обертка = Новый Структура;
// Наполняем данными самого элемента
ДанныеЭлемента = Новый Структура;
ДанныеЭлемента.Вставить("Дата", ЭлементXDTO.Дата);
ДанныеЭлемента.Вставить("Коллекция", ЭлементXDTO.Коллекция);
// Вкладываем данные в обертку под ключом "Строка"
Обертка.Вставить("Строка", ДанныеЭлемента);
// Добавляем в общий массив
СписокДляJSON.Добавить(Обертка);
КонецЦикла;
// Теперь упаковываем все это в итоговую структуру
ИтоговаяСтруктура = Новый Структура;
ИтоговаяСтруктура.Вставить("ТЧ_ИзменениеКоллекции", СписокДляJSON);
// Записываем полученную структуру в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ИтоговаяСтруктура);
Результат = ЗаписьJSON.Закрыть();
Этот метод дает полный контроль над именами полей, но требует написания дополнительного кода для обхода всех уровней вложенности объекта.
В самых крайних случаях, когда структура очень сложная, а времени на переписывание логики нет, некоторые разработчики используют текстовую замену. Однако мы не рекомендуем этот способ для промышленной эксплуатации, так как он крайне хрупок. Тем не менее, проанализируем его суть: вы получаете JSON-строку и регулярным выражением или функцией СтрЗаменить пытаетесь вставить нужные ключи. Помните, что это может нарушить валидность JSON, если в данных встречаются те же комбинации символов.
Подводя итог, можно сказать, что «исчезновение» тегов — это не ошибка 1С, а следование стандартам JSON, где массивы не требуют именования каждого элемента. Если же вам жизненно необходимо сохранить структуру "ИмяТега": { ... } внутри массива:
ЗаписатьJSON стали шире, но описанная логика работы с XDTO остается фундаментальной.Посмотрим на ситуацию шире: часто требование сохранить имя тега в JSON возникает из-за того, что принимающая сторона использует автоматические конвертеры XML -> JSON, которые работают по упрощенным алгоритмам. В современной разработке хорошей практикой считается использование плоских массивов объектов в JSON, поэтому, если есть возможность повлиять на спецификацию обмена, лучше отказаться от лишних вложенных ключей в пользу стандартного поведения 1С.