Работа с форматом JSON в платформе 1С:Предприятие 8.3 — задача стандартная, но имеющая множество подводных камней. Начинающие разработчики часто сталкиваются с ситуациями, когда вместо ожидаемых данных в файле появляются значения null, или система выдает загадочную ошибку "Недопустимое состояние потока записи JSON". В рамках данной статьи мы подробно разберем, как избежать этих проблем, проанализируем разницу между методами коллекций и научимся формировать валидные структуры данных для обмена с внешними системами.
Рассмотрим ситуацию, когда при записи массива строк вы получаете результат вида [null, null, null, "значение"]. Выясним причину такого поведения. В 1С у объекта Массив есть два основных метода добавления данных: Добавить() и Вставить(). Ошибка часто кроется в использовании второго метода.
Метод Вставить(Индекс, Значение) предназначен для помещения элемента в конкретную позицию. Если вы ошибочно передаете туда данные или используете индексы, которые «разрывают» последовательность, 1С заполняет пустые места значениями Неопределено. При сериализации в JSON эти значения превращаются в null.
Проанализируем правильный подход. Для формирования простого списка значений всегда используйте метод Добавить(). Посмотрим на пример кода:
// Неправильный подход, который может привести к null
МассивДанных = Новый Массив;
МассивДанных.Вставить(0, "114973"); // Если перепутать параметры или индексы, будет брак
// Правильный подход
МассивДанных = Новый Массив;
МассивДанных.Добавить("114973");
МассивДанных.Добавить("114974");
МассивДанных.Добавить("114975");
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МассивДанных);
Результат = ЗаписьJSON.Закрыть();
Важный момент: если вы используете высокоуровневый метод ЗаписатьJSON(), система сама заботится об открытии и закрытии всех скобок массива. Попытка вручную «дорисовать» элементы часто приводит к нарушению структуры.
Эта ошибка — одна из самых частых при работе с объектами ЗаписьJSON и ЧтениеJSON. Разберем по шагам, что происходит в памяти системы. Поток записи имеет строгий жизненный цикл. Если вы вызвали метод Закрыть(), объект становится недоступным для дальнейших манипуляций.
Типичная ошибка выглядит так: программист записывает данные, закрывает поток, чтобы получить строку, а затем пытается продолжить запись или передать этот же объект в функцию чтения. Рассмотрим правильную последовательность действий:
ЗаписьJSON.ЗаписатьJSON или низкоуровневые методы).Закрыть().Если вам нужно прочитать только что созданный JSON, необходимо создать новый объект ЧтениеJSON, как показано в примере ниже:
// Код записи
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, МоиДанные);
СтрокаJSON = Запись.Закрыть(); // После этого "Запись" использовать нельзя!
// Код чтения
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(СтрокаJSON);
Результат = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
Выясним важную техническую особенность 1С. В JSON ключи объектов всегда являются строками. Однако в 1С объект Структура имеет жесткое ограничение: ключи должны соответствовать правилам именования переменных (не могут начинаться с цифр, содержать пробелы и т.д.).
Если ваша задача — получить JSON вида {"114973": {...}}, то Структура не подойдет, так как ключ "114973" недопустим. В этом случае мы должны использовать объект Соответствие (Map). Рассмотрим пример создания такой коллекции:
ДанныеДоговоров = Новый Соответствие;
Для Каждого Строка Из ТаблицаДанных Цикл
Детали = Новый Структура;
Детали.Вставить("policy_no", Строка.Номер);
Детали.Вставить("insuranced_at", Формат(Строка.Дата, "ДФ=dd.MM.yyyy"));
// Используем номер договора как ключ в Соответствии
ДанныеДоговоров.Вставить(Строка.НомерДоговора, Детали);
КонецЦикла;
// При записи Соответствие превратится в объект JSON с ключами-строками
ЗаписатьJSON(ЗаписьJSON, ДанныеДоговоров);
Иногда внешние системы требуют странные форматы, например: [ "договор1": { ... } ]. Посмотрим на эту структуру внимательно: это невалидный JSON. В стандарте JSON массив (квадратные скобки) может содержать только перечисление значений, но не пары "ключ: значение". Именованные свойства могут быть только внутри объекта (фигурные скобки).
Если вам нужно передать список именованных объектов, у вас есть два пути:
[ {"номер": "договор1", "данные": {...}}, {"номер": "договор2", "...": ...} ].{ "договор1": {...}, "договор2": {...} }.Попытки «убрать лишнюю запятую» вручную в коде формирования текста обычно сигнализируют о том, что выбран неправильный тип коллекции 1С. Помните: Массив в 1С — это [] в JSON, а Структура или Соответствие — это {}.
Рассмотрим ситуацию, когда вам нужно очень точно контролировать процесс записи, например, при формировании огромных файлов, которые не помещаются в оперативную память целиком. В этом случае мы отказываемся от метода ЗаписатьJSON(Запись, Объект) и используем пошаговую запись.
Проанализируем пример ручного формирования структуры:
ЗаписьJSON.ЗаписатьНачалоМассива(); // Пишет [
Для Каждого Элемент Из СписокДоговоров Цикл
ЗаписьJSON.ЗаписатьНачалоОбъекта(); // Пишет {
ЗаписьJSON.ЗаписатьИмяСвойства("id");
ЗаписьJSON.ЗаписатьЗначение(Элемент.Идентификатор);
ЗаписьJSON.ЗаписатьИмяСвойства("data");
ЗаписьJSON.ЗаписатьНачалоОбъекта();
// ... запись вложенных свойств
ЗаписьJSON.ЗаписатьКонецОбъекта();
ЗаписьJSON.ЗаписатьКонецОбъекта(); // Пишет }
КонецЦикла;
ЗаписьJSON.ЗаписатьКонецМассива(); // Пишет ]
Важное правило: Каждому вызову ЗаписатьНачалоОбъекта должен соответствовать ЗаписатьКонецОбъекта. Если вы нарушите вложенность, 1С выдаст ошибку состояния потока при попытке завершить запись.
Иногда возникает соблазн просто складывать строки: СтрокаJSON = "[" + " { " + .... Мы настоятельно рекомендуем избегать этого метода. Рассмотрим причины:
ЗаписьJSON автоматически превратит её в \".Когда вы читаете данные обратно в 1С, помните о параметрах метода ПрочитатьJSON. По умолчанию 1С пытается прочитать объекты в Структуру. Если в файле были ключи, которые не могут быть именами свойств в 1С (те самые цифры), чтение завершится с ошибкой.
Чтобы этого избежать, всегда указывайте четвертый параметр метода — тип читаемого объекта:
// Указываем, что объекты JSON нужно читать в Соответствие, а не в Структуру
Результат = ПрочитатьJSON(ЧтениеJSON, Ложь, , "Соответствие");
Это обеспечит максимальную совместимость с любыми внешними API, независимо от того, какие имена полей они используют.