Работа с JSON

В «1С:Шине» представлены широкие возможности по работе с форматом JSON. Во встроенном языке используются специальные типы для работы с данным форматом, основными из которых являются СериализацияJson, ЧтениеJson и ЗаписьJson. Вы можете автоматически преобразовать в/из JSON большинство типов встроенного языка.

Эти и другие встроенные средства позволяют осуществлять потоковую, объектную или смешанную формы работы с форматом JSON:

  • При потоковой работе документ JSON не загружается в память целиком, а считывается по частям. Программа при этом осуществляет навигацию по структуре документа в соответствии с настройками, указанными пользователем. Такой способ удобен при работе с файлами большого размера и/или сложной структурой вложенности объектов.
  • При объектной работе документ JSON загружается в память целиком и считывается в объект, например, соответствие или структура данных. Такой способ удобен, когда требуется передавать данные как простой и относительно небольшой объект, поэтому объекты JSON используются в основном в API.
  • При смешанной работе программа осуществляет навигацию по структуре документа потоковым способом, но когда доходит до требуемого объекта, загружает его объектным способом.
Примечание:

Для тех, кто использует JSON версии JSON5 и выше (в которых поддерживаются однострочные комментарии)

Комментарий начинается с символов // и заканчивается с концом строки. Содержимое комментария при чтении JSON игнорируется, то есть результат чтения JSON не включает содержимого комментариев и не содержит какой-либо информации о наличии комментариев.

Потоковый режим работы с JSON

Во встроенном языке для потокового ввода и вывода данных используются соответственно типы ЧтениеJson и ЗаписьJson.

В типе ЧтениеJson существует метод для чтения значения JSON в указанный тип:

  • ПрочитатьСодержимое, который использует обобщённый тип данных и принимает как аргумент объект типа НастройкиЧтенияОбъектовJson, как и в примере выше для СериализацияJson.

Кроме того, существуют методы для чтения значения JSON в один из конкретных типов:

  • ПрочитатьСодержимоеКакБайты,
  • ПрочитатьСодержимоеКакБулево,
  • ПрочитатьСодержимоеКакВремя,
  • ПрочитатьСодержимоеКакДата,
  • ПрочитатьСодержимоеКакДатаВремя,
  • ПрочитатьСодержимоеКакДлительность,
  • ПрочитатьСодержимоеКакМассив,
  • ПрочитатьСодержимоеКакМомент,
  • ПрочитатьСодержимоеКакСоответствие,
  • ПрочитатьСодержимоеКакСтроку,
  • ПрочитатьСодержимоеКакУуид,
  • ПрочитатьСодержимоеКакЧисло.

Объектный режим работы с JSON

Во встроенном языке для объектной работы с данным используются механизмы сериализации и десериализации. Сериализация используется для перевода структуры данных в формат, позволяющий передавать или хранить эти данные, например, в файле. Десериализация — обратная процедура. В «1С:Шине» для этого используется тип СериализацияJson. Методы этого типа позволяют выполнить сериализацию (метод ЗаписатьОбъект и др.) в поток или строку или десериализацию (метод ПрочитатьОбъект и др.).

Смешанный режим работы с JSON

При смешанной работе с JSON могут использоваться как типы ЧтениеJson и ЗаписьJson, так и тип СериализацияJson. Например:
// Создаём структуру для чтения данных из JSON
структура ФизическоеЛицо
    пер Фамилия: Строка
    пер Имя: Строка
    пер Отчество: Строка   
;

// Используем потоковое чтение с помощью типа ЧтениеJson
метод ПрочитатьФизическихЛиц()
     пер ФизическиеЛицаJson =
        "[
            {
                \"Фамилия\": \"Иванов\",
                \"Имя\": \"Иван\",
                \"Отчество\": \"Иванович\"
            },
            {
                \"Фамилия\": \"Петров\",
                \"Имя\": \"Петр\",
                \"Отчество\": \"Петрович\"
            }
        ]"
    пер ЧтениеМассива = новый ЧтениеJson(ФизическиеЛицаJson) 
    // позиционируемся на начало массива
    если не Чтение.Следующий()
        возврат
    ;  
    // позиционируемся на первый элемент массива
    если не Чтение.Следующий()
        возврат
    ;  

    // Считываем данные из JSON в структуру для дальнейшего использования как объекта
    пока ЧтениеМассива.ВидУзла != ВидУзлаJson.КонецМассива
        пер ФизЛицо = ЧтениеМассива.ПрочитатьСодержимое<ФизическоеЛицо>()
        // Записываем полученные данные в базу
    ;
;
или
// Используем потоковое чтение с помощью типа ЧтениеJson
метод ПрочитатьОбращенияПользователей()
     пер ОбращенияJson =
        "[
            {\"Пользователь\":
                {
                    \"Фамилия\": \"Иванов\",
                    \"Имя\": \"Иван\",
                    \"Логин\": \"Иванов\"
                },
                \"Обращения\": [
                    {\"Категория\": \"Жалоба\", \"Текст\": \"текст1\"},
                    {\"Категория\": \"Вопрос\", \"Текст\": \"текст2\"}
                ]
            },
            {\"Пользователь\":
                {
                    \"Фамилия\": \"Петров\",
                    \"Имя\": \"Петр\",
                    \"Логин\": \"Петров\"
                },
                \"Обращения\": [
                    {\"Категория\": \"Благодарность\", \"Текст\": \"текст3\"}
                ]
            }
        ]"
    пер Чтение = новый ЧтениеJson(ОбращенияJson)
    // позиционируемся на начало массива
    если не Чтение.Следующий()
        возврат
    ;
    // позиционируемся на первый элемент массива
    если не Чтение.Следующий()
        возврат
    ;
 
    пока Чтение.ВидУзла != ВидУзлаJson.КонецМассива
        // позиционируемся на свойство Пользователь
        Чтение.Следующий()
        // позиционируемся на начало объекта Пользователь
        Чтение.Следующий()

        // Считываем данные из JSON в коллекции для дальнейшего использования как объектов
        // читаем данные пользователя в соответствие
        пер ДанныеПользователя = Чтение.ПрочитатьСодержимоеКакСоответствие()
        // после этого вызова ЧтениеJson будет спозиционировано на свойство Обращения
 
        // позиционируемся на начало массива
        Чтение.Следующий()
        // читаем массив обращений
        пер Обращения = Чтение.ПрочитатьСодержимоеКакМассив()
        // после этого вызова ЧтениеJson будет спозиционировано на токен КонецОбъекта
        // Возвращаемся к потоковому чтению JSON
 
        // переходим к следующему элементу массива
        Чтение.Следующий()
    ;
;

Настройки чтения и записи объектов JSON

Для настройки чтения, записи и сериализации объектов JSON используются специальные типы, основными из которых являются НастройкиЧтенияОбъектовJson и НастройкиЗаписиОбъектовJson. Они позволяют указывать, как именно системе обрабатывать свойства объектов JSON, например, нужно ли игнорировать неизвестные поля, инициализировать пустые поля, использовать псевдонимы свойств при совпадении имен и так далее.

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

Соответствующие настройки вы также можете задать с помощью следующих аннотаций:
@JsonИгнорироватьСвойство

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

Данная аннотация является аналогом следующей настройки:
  • НастройкиЗаписиОбъектовJson.ИгнорируемыеСвойства
@JsonСвойство(Имя, БезОбработки, Псевдонимы)
Данной аннотацией помечается поле структуры. Позволяет задать настройки для свойства, аналогичные следующим настройкам:
  • НастройкиЗаписиОбъектовJson.ИспользуемыеИменаСвойств (параметр Имя)
  • НастройкиЗаписиОбъектовJson.ЗаписьСвойствБезОбработки (параметр БезОбработки)
  • НастройкиЧтенияОбъектовJson.ПсевдонимыСвойств (параметр Псевдонимы)
@JsonОбъект(ПропускатьПустыеЗначения, РежимЗаписиТипа, ИгнорироватьНеизвестные)
Данной аннотацией помечается структура. Позволяет задать настройки для объекта, аналогичные следующим настройкам:
  • НастройкиЗаписиОбъектовJson.ПропускатьНеопределено и НастройкиЗаписиОбъектовJson.ПропускатьПустыеКоллекции (параметр ПропускатьПустыеЗначения)
  • НастройкиЧтенияОбъектовJson.ИнициализироватьОтсутствующиеПоляи НастройкиЧтенияОбъектовJson.ИнициализироватьПустыеКоллекции (параметр ПропускатьПустыеЗначения)
  • НастройкиЗаписиОбъектовJson.РежимЗаписиТипа (параметр РежимЗаписиТипа)
  • НастройкиЧтенияОбъектовJson.ИгнорироватьНеизвестныеСвойства (параметр ИгнорироватьНеизвестные)

Пример

@Локально
структура ТестЗаписиВJson
    пер Строка: Строка
    пер Число: Число
    пер Дата: Дата
    пер Время: Время
    пер ДатаВремя: ДатаВремя
    пер Массив: Массив<Строка>   
    пер Множество: Множество<Число>
    пер Объект: Справочник1.Объект
    пер Байты: Байты
    пер ТипЗначения: Строка
;

метод ТестСериализацииJSON(Запрос: HttpСервисЗапрос)
    пер Результат = ""
    пер Ответ = Запрос.Ответ
    пер СтрокаJSON = СериализоватьСтруктуру()
    пер СтрокаИзJSON = ДесериализоватьСтруктуру(СтрокаJSON)
    
    
    Результат = 
    "Результат сериализации: \н\н
    %СтрокаJSON \н\н
    Результат ДЕсериализации: \н\н
    %СтрокаИзJSON \н\н"
    
    Ответ.УстановитьТело(Результат)
;

// Использование псевдонимов свойств

метод СериализоватьСтруктуру(): Строка
    
    знч НастройкиЗаписи = новый НастройкиЗаписиОбъектовJson()
    НастройкиЗаписи.ИспользуемыеИменаСвойств.Вставить(Тип<ТестЗаписиВJson>, {"ТипЗначения":"type"})
    
    знч ОбъектСправочника = новый Справочник1.Объект()
    ОбъектСправочника.Наименование = "Тестовый абонент"
    ОбъектСправочника.Код = "123456"
    
    знч Объект = новый ТестЗаписиВJson(Строка = "ТестоваяСтрока",
                                       Число = 123,
                                       Дата = Дата.Сейчас(),
                                       Время = Время.Сейчас(),
                                       ДатаВремя = ДатаВремя.Сейчас(),
                                       Массив = ["Тестовый", "Массив", "Строка"],
                                       Множество = {9,8,7,6},
                                       Объект = ОбъектСправочника,
                                       Байты = ПолучитьДДФайла(),
                                       ТипЗначения = "ОписаниеТипаЗначения")
    
    пер ТекстJSON = СериализацияJson.ЗаписатьОбъект(Объект, НастройкиЗаписи)
    
    возврат ТекстJSON    
;

метод ДесериализоватьСтруктуру(СтрокаJSON: Строка): Строка
    
    знч Псевдонимы = {
        "ТипЗначения": {"value_type"}
    }
    
    знч НастройкиЧтения = новый НастройкиЧтенияОбъектовJson()
    НастройкиЧтения.ПсевдонимыСвойств[Тип<ТестЗаписиВJson>] = Псевдонимы
    
    знч ПрочитанныйОбъект = СериализацияJson.ПрочитатьОбъект(СтрокаJSON, Тип<ТестЗаписиВJson>, НастройкиЧтения)
    знч ТипОбъекта = ПрочитанныйОбъект.ПолучитьТип().ВСтроку() 
    знч ПредставлениеОбъекта = ПрочитанныйОбъект.ВСтроку()
     
    возврат  "Прочитан объект типа: %ТипОбъекта\н\нСодержимое объекта: \н\н%ПредставлениеОбъекта"  
;

Пример c использованием аннотации свойства структуры

@Локально
структура ТестЗаписиВJson
    пер Строка: Строка
    пер Число: Число
    пер Дата: Дата
    пер Время: Время
    пер ДатаВремя: ДатаВремя
    пер Массив: Массив<Строка>   
    пер Множество: Множество<Число>
    пер Объект: Справочник1.Объект
    пер Байты: Байты
    
    @JsonСвойство(Имя="type", Псевдонимы={"value_type"})
    пер ТипЗначения: Строка
;

метод ТестСериализацииJSON(Запрос: HttpСервисЗапрос)
    пер Результат = ""
    пер Ответ = Запрос.Ответ
    пер СтрокаJSON = СериализоватьСтруктуру()
    пер СтрокаИзJSON = ДесериализоватьСтруктуру(СтрокаJSON)
    
    
    Результат = 
    "Результат сериализации: \н\н
    %СтрокаJSON \н\н
    Результат ДЕсериализации: \н\н
    %СтрокаИзJSON \н\н"
    
    Ответ.УстановитьТело(Результат)
;


// Использование псевдонимов свойств
метод СериализоватьСтруктуру(): Строка
        
    знч ОбъектСправочника = новый Справочник1.Объект()
    ОбъектСправочника.Наименование = "Тестовый абонент"
    ОбъектСправочника.Код = "123456"
    
    знч Объект = новый ТестЗаписиВJson(Строка = "ТестоваяСтрока",
                                       Число = 123,
                                       Дата = Дата.Сейчас(),
                                       Время = Время.Сейчас(),
                                       ДатаВремя = ДатаВремя.Сейчас(),
                                       Массив = ["Тестовый", "Массив", "Строка"],
                                       Множество = {9,8,7,6},
                                       Объект = ОбъектСправочника,
                                       Байты = ПолучитьДДФайла(),
                                       ТипЗначения = "ОписаниеТипаЗначения")
    
    пер ТекстJSON = СериализацияJson.ЗаписатьОбъект(Объект)
    
    возврат ТекстJSON    
;

метод ДесериализоватьСтруктуру(СтрокаJSON: Строка): Строка
        
    знч ПрочитанныйОбъект = СериализацияJson.ПрочитатьОбъект(СтрокаJSON, Тип<ТестЗаписиВJson>)
    знч ТипОбъекта = ПрочитанныйОбъект.ПолучитьТип().ВСтроку() 
    знч ПредставлениеОбъекта = ПрочитанныйОбъект.ВСтроку()
     
    возврат  "Прочитан объект типа: %ТипОбъекта\н\нСодержимое объекта: \н\н%ПредставлениеОбъекта"  
;