Ошибка при вызове метода контекста прочитатьjson ошибка преобразования данных xdto

1С: Предприятие 8.3.14.Документация

1 Общая информация

Формат JSON является универсальным способом представления при обмене данными (RFC 7159, https://tools.ietf.org/html/rfc7159). Данные в формате JSON представляют собой (в закодированном виде):
Объект – неупорядоченное множество пар ключ:значение, заключенный в фигурные скобки ({}). Пары ключ:значение разделяются запятыми (,).
Массив – множество значений. Массив заключается в квадратные скобки ([]). Значения разделяются запятыми (,).
● Значение – может быть строкой, числом, объектом, массивов или литералом true, false, null.
● Строка – набор символов, заключенный в двойные кавычки (“”).
● Число – сериализуется с разделителем точка (.). Точность числа не ограничена.
Таким образом, с помощью вышеперечисленных элементов допускается описание объектов любой сложности для представления в формате JSON. Например, некоторый код на встроенном языке, формирует некоторый набор данных (в структуре):

Данные = Новый Структура;
 Данные.Вставить("Фамилия", "Иванов");
 Данные.Вставить("Имя", "Иван");
 Данные.Вставить("Отчество", "Иванович");
 Данные.Вставить("ДеньРождения", ДатаРождения);
 Телефоны = Новый Массив;
 Телефоны.Добавить("+7-987-123-45-67");
 Телефоны.Добавить("+7-986-987-65-43");
 Данные.Вставить("Телефоны", Телефоны);

Сериализуя этот объект в JSON, может быть получен следующий документ:

 {
 "Фамилия": "Иванов",
 "Имя": "Иван",
 "Отчество": "Иванович",
 "ДатаРождения": "2009-02-15T00:00:00Z",
 "Телефоны": [
 "+7-987-123-45-67",
 "+7-986-987-65-43"
 ]
 }

JSON не стандартизует формат представления даты. В силу этого представление даты в JSON-документе определяется предпочтениями прикладного разработчика, который формирует документ, и требованиями системы, которая будет обрабатывать JSON-документ. Система «1С:Предприятие» поддерживает несколько форматов представления даты (задается с помощью системного перечисления ФорматДатыJSON):
1. Формат ISO (значение ФорматДатыJSON.ISO). В этом случае дата сериализуется следующим образом: “2009-02-15T00:00:00+0400”.
2. Формат JavaScript (значение ФорматДатыJSON.JavaScript). В этом случае дата сериализуется следующим образом: “new Date
(1234656000000)”.
3. Формат Microsoft (значение ФорматДатыJSON.Microsoft). В этом случае дата сериализуется следующим образом: “/Date(1234656000000)/”
или “/Date(1234656000000)/” (в зависимости от режима экранирования символов).
Дата может записываться несколькими вариантами (для примера используется дата 10 мая 2014 13:14:15 в зоне UTC+4):
● как локальная дата: 2014-05-10T13:14:15.
● как локальная дата с указанием смещения: 2014-05-10T13:14:15+04:00.
● как дата в UTC: 2014-05-10T09:14:15Z.
Управлять этим можно с помощью системного перечисления ВариантЗаписиДатыJSON. Дату в варианте UTC можно записать в любом формате (ISO, JavaScript и Microsoft), остальные варианты представления даты возможны только в том случае, если сериализация выполняется в формате ISO.
При записи JSON-документа предоставляются возможности по управлению формируемыми данными: настраивать перенос строк, формат сериализации даты, обработка символа “/” и т. д. Эти настройки можно выполнять с помощью объектов НастройкиСериализацииJSON и ПараметрыЗаписиJSON.
Работа с данными в формате JSON может выполняться в нескольких техниках:
● Объектная техника – позволяет формировать простые и небольшие JSON-документы для обмена с внешними приложениями или веб-сервисами. Структура JSON-документа автоматически формируется системой «1С:Предприятие» во время записи документа. Более подробно описание данной техники см. раздел 16.2.2. Специальным вариантом такой техники является возможность сериализации в формате JSON для XDTO-
объектов системы «1С:Предприятие». Более подробное описание работы с XDTO-объектами см. раздел 16.2.3.
● Потоковая техника – позволяет работать с данными большого объема без загрузки их в память приложения. Навигация по JSON-документу  полностью ложится на прикладного разработчика (как при записи, так и при чтении документа). Более подробно описание данной техники см. раздел 16.2.4.
● Совмещенная техника – позволяет сочетать гибкость потоковой техники и простоту объектной техники. Более подробно описание данной техники см. раздел 16.2.5.

2. Объектная техника работы

2.1. Общая информация

Система «1С:Предприятие» поддерживает сериализацию следующих данных в формат JSON:
● Строка – сериализуется в строку;
● Число – сериализуется в число;
● Булево – сериализуется в литералы true и false;
● Неопределено – сериализуется в null
● Массив, ФиксированныйМассив – сериализуется в массив JSON в том случае, если любой элемент массива может быть сериализован в JSON.
● Структура, ФиксированнаяСтруктура – сериализуется в объект JSON:
● Ключ – ключ элемента структуры.
● Значение – значение элемента структуры в том случае, если значение может быть                 сериализовано в JSON.
● Соответствие, ФиксированноеСоответствие – сериализуется в объект JSON:
● Ключ – ключ элемента соответствия. Ключ может быть только значением типа Строка, в противном случае будет генерироваться исключение.
● Значение – значение элемента соответствия в том случае, если значение может быть сериализовано в JSON.
● Дата – формат сериализации определяется настройками.
● Если выполняется попытка сериализации типа, отсутствующего в данном списке – будет вызвано исключение.
При работе с объектной техникой, имеется возможность читать (и писать) данные в соответствие или структуру. Основное отличие между этими объектами состоит в том, что ключ элемента структуры подчиняется правилам формирования переменной на встроенном языке, а ключ элемента соответствия может быть любым. С учетом того, чтоб JSON не накладывает ограничений на значение ключа, не все JSON-документы можно
прочитать в структуру. Еще одним различием между структурой и соответствием является то, что к элементам структуры можно обращаться «через точку», а к элементам соответствия такой доступ не предоставляется. В связи с этим, может оказаться удобным получать данные в виде структуры, если ключи из JSON-документа соответствуют требованиям к ключам структур системы «1С:Предприятие».
Объектная техника предполагает достаточно простую работу с данными, однако платой за это является большой расход памяти, т. к. весь JSON-документ обрабатывается целиком в оперативной памяти.

2.2. Запись

Для того чтобы выполнить запись объекта в формате JSON, необходимо использовать (в простейшем случае) следующие объекты:
1. Собственно записываемый объект, например типа Структура.
2. Объект, обеспечивающий низкоуровневую запись данных в формате JSON – ЗаписьJSON.
3. Объект настроек сериализации НастройкиСериализацииJSON.
Метод глобального контекста ЗаписатьJSON() оперирует вышеперечисленными объектами. Рассмотрим пример, в котором потребуется записать структуру, которая состоит из трех элементов разного типа (но типы являются примитивными):

Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempsimpleWrite.json");
 Данные = Новый Структура;
 Данные.Вставить("ДлинаЗаписи", 20);
 Данные.Вставить("КлючЗаписи", "abcdefgh");
 Данные.Вставить("ДатаИзменения", ТекущаяДата());
 ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON);
 Запись.Закрыть();

В результате работы данный пример сформирует следующий JSON-документ:

{
“ДлинаЗаписи”: 20,
“КлючЗаписи”: “abcdefgh”,
“ДатаИзменения”: “2014-09-24T17:32:11”
}
Если в сериализуемых данных участвуют значения типа Дата, то может потребоваться управлять форматом сериализации. Для этого необходимо установить параметры объекта НастройкиСериализацииJSON. В следующем примере дата будет сериализоваться в формате JavaScript:

НастройкиСериализации = Новый НастройкиСериализацииJSON;
 НастройкиСериализации.ФорматСериализацииДат = ФорматДатыJSON.JavaScript;
 НастройкиСериализации.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.УниверсальнаяДата;
 Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempsimpleWrite.json");
 Данные = Новый Структура;
 Данные.Вставить("ДлинаЗаписи", 20);
 Данные.Вставить("КлючЗаписи", "abcdefgh");
 Данные.Вставить("ДатаИзменения", ТекущаяДата());
 ЗаписатьJSON(Запись, Данные, НастройкиСериализации);
 Запись.Закрыть();

В результате работы данный пример сформирует следующий JSON-документ:

{
 "ДлинаЗаписи": 20,
 "КлючЗаписи": "abcdefgh",
 "ДатаИзменения": "new Date(1411565832000)"
 }

Если несколько расширить набор записываемых данных, например, добавить к ним значение типа УникальныйИдентификатор, то запись не будет выполнена. В результате исполнения кода:

Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempsimpleWrite.json");
 Данные = Новый Структура;
 Данные.Вставить("ДлинаЗаписи", 20);
 Данные.Вставить("КлючЗаписи", "abcdefgh");
 Данные.Вставить("ДатаИзменения", ТекущаяДата());
 Данные.Вставить("UID", Новый УникальныйИдентификатор);
 ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON);
 Запись.Закрыть();

Будет вызвано исключение:

Ошибка при вызове метода контекста (ЗаписатьJSON)
 ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON);
 по причине:
 Передано значение недопустимого типа

Причиной такого поведения является то, что тип УникальныйИдентификатор не входит в состав JSON-сериализуемых типов данных системы «1С:Предприятие». Однако система предоставляет возможность «обойти» это ограничение: необходимо передать в функцию ЗаписатьJSON() имя функции обратного вызова, которая будет заниматься JSON-сериализацией неподдерживаемых объектов. Эта функция будет называться
функцией преобразования. При этом формат такой сериализации будет разрабатывать непосредственно сам прикладной разработчик. Надо понимать, что такая сериализация не будет универсальной, т. к. принимающая сторона, не обладающая знаниями о формате сериализации, не сможет прочитать переданные данные. Другими словами, формат сериализации необходимо разрабатывать совместно всеми сторонами обмена
такого рода данными.
С учетом вышесказанного, более сложный вариант обмена теперь происходит следующим образом:
● Вызывается функция сериализации объекта в формат JSON (ЗаписатьJSON()).
● Система «1С:Предприятие» для каждого элемента структуры, тип значения которого не сериализуется в формат JSON, будет вызываться функция преобразования.
● Функция преобразования анализирует переданный объект и принимает решение – отказаться от его записи или вернуть платформе значение, которое может быть сериализовано в JSON.
Доработанный код записи будет выглядеть следующим образом:

&НаСервере
 Процедура ЗаписьНаСервере()
 Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempcompositeWrite.json");
 Данные = Новый Структура;
 Данные.Вставить("ДлинаЗаписи", 20);
 Данные.Вставить("КлючЗаписи", "abcdefgh");
 Данные.Вставить("ДатаИзменения", ТекущаяДата());
 Данные.Вставить("UID", Новый УникальныйИдентификатор);
 ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON, "ФункцияПреобразованияЗаписи", ЭтотОбъект);
 Запись.Закрыть();
 КонецПроцедуры
 &НаСервере
 Функция ФункцияПреобразованияЗаписи(Свойство, Значение, ДополнительныеПараметры, Отказ) Экспорт
 Если ТипЗнч(Значение) = Тип("УникальныйИдентификатор") Тогда
 Возврат Строка(Значение);
 КонецЕсли;
 Отказ = Истина;
 КонецФункции

Следует обратить внимание, что функция преобразования должна быть объявлена с указанием ключевого слова Экспорт. Также следует помнить, что функция преобразования (в модуле управляемой формы) может быть описана только в «контекстной» части модуля, т. е. с использованием директивы компиляции &НаКлиенте или &НаСервере.
В результате работы приведенного примера будет сформирован следующий JSON-документ:

{
 "ДлинаЗаписи": 20,
 "КлючЗаписи": "abcdefgh",
 "ДатаИзменения": "2014-09-24T18:09:13",
 "UID": "5a80e5dc-252b-416f-b487-d9ddcebc523e"
 }

При создании функции преобразования следует помнить о следующих особенностях:
● Функция преобразования вызывается для значений всех типов, которые не поддерживают сериализацию в JSON (см. раздел 16.2.1).
● Если функция преобразования вернет значение, которое не может быть сериализовано в JSON – будет вызвано исключение.
● Если переданное значение является структурой, то вызов функции преобразования для элементов этой структуры будет вызваться до того, как в поток будет записано имя свойства этого элемента. В результате функция преобразования может отказаться от записи значения и структура формируемого JSON-документа не будет нарушена.
● Имя свойства будет передано в функцию преобразования только для элементов структур и соответствий.

2.3. Чтение

2.3.1. Общая схема

Чтение данных в объектной технике выглядит аналогично записи. Рассмотрим пример чтения файлов, которые формировались во время рассмотрения объектной записи (предыдущий раздел).

Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempsimpleWrite.json");
 Данные = ПрочитатьJSON(Чтение, Ложь, "ДатаИзменения", ФорматДатыJSON.JavaScript);
 Чтение.Закрыть();

Документ имеет следующее содержание (с точностью до значения даты):

{
 "ДлинаЗаписи": 20,
 "КлючЗаписи": "abcdefgh",
 "ДатаИзменения": "new Date(1411565832000)"
 }

При чтении JSON-документа в переменную Данные будет сформирована структура вида:

Ключ = ДлинаЗаписи, значение = 20
Ключ = КлючЗаписи, значение = abcdefgh
Ключ = ДатаИзменения, значение = <значение даты и времени>

Такой вариант чтения хорошо подходит в том случае, если читаемые данные могут быть преобразованы в структуру или соответствие и все читаемые данные могут быть однозначно десериализованы без потери информации о типе. Если читаемые данные обладают сложной структурой или требуют выполнения дополнительных преобразований при чтении, то можно пойти двумя путями:
1. Получить соответствие (или структуру), в которое будет полностью загружен JSON-документ, и потом завершить преобразование с помощью обхода получившегося объекта.
2. Заниматься необходимым преобразованием непосредственно во время загрузки данных.

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

{
 "id":524901,"name":"Moscow","dt":1411464940000,
 "coord": { "lon":37.62,"lat":55.75 },
 "sys": { "country":"RU","sunrise":1411442400000,"sunset":1411485660000 },
 "weather": [
 { "main":"Clouds","description":"пасмурно" }
 ],
 "main": { "temp":282.93,"pressure":1014,"humidity":93 },
 "wind": { "speed":4,"deg":350 },
 "clouds": { "all":90 }
 }

Кратко рассмотрим описание формата:
● id – идентификатор города;
● name – имя города;
● dt – дата и время получения погоды, в формате Unix, GMT;
● coord – местоположение города:
● lon – долгота;
● lan – широта.
● sys – дополнительная информация:
● country – страна расположения города;
● sunrise – время восхода Солнца в формате Unix, GMT;
● sunset – время заката Солнца, в формате Unix, GMT.
● weather – дополнительная информация о погоде:
● main – общая характеристика погоды;
● description – описание погоды.
● main – собственно описание погоды:
● temp – температура, в градусах Кельвина. Для получения градусов Цельсия необходимо вычесть 273.15;
● pressure – давление в гектопаскалях. Для перевода в миллиметры ртутного столба, надо значение давления умножить на 0,75.
● humidity – влажность в %.
● wind – параметры ветра:
● speed – скорость в милях в час. Для перевода в километры в час необходимо умножить на 1,61.
● deg – направление ветра, в градусах.
● clouds – информация об осадках:
● all – вероятность возникновения осадков, в %.
В результате загрузки этих данных должна получиться структура, где все времена представлены стандартным типом Дата, температура – в градусах Цельсия, скорость – в километрах в час, а давление – в миллиметрах ртутного столба.
Рассмотрим загрузку данной информации обоими способами. Данные записаны в файле c:tempweather.json.

2.3.2. Чтение с постобработкой

Собственно процесс чтения выглядит просто:

Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempweather.json");
 Данные = ПрочитатьJSON(Чтение, Ложь);
 Чтение.Закрыть();

В результате в переменной Данные будет следующая информация:

Рис. 3 Результат загрузки

Без учета необходимости конвертации все выглядит предсказуемо. Однако дата и время автоматически не преобразовались. Можно попробовать указать системе на то, что поле dt (например) является полем, где находится дата и время:

Чтение = Новый ЧтениеJSON; Чтение.ОткрытьФайл("c:tempweather.json");
Данные = ПрочитатьJSON(Чтение, Ложь, "dt", ФорматДатыJSON.JavaScript);
 Чтение.Закрыть();

В результате получим сообщение об ошибке следующего вида:

Ошибка при вызове метода контекста (ПрочитатьJSON)

Данные = ПрочитатьJSON(Чтение, Ложь, "dt", ФорматДатыJSON.JavaScript);

по причине:

Представление даты имеет неверный формат

Ошибка произошла потому, что система не понимает формат даты и времени, выраженной простым числом. Программный интерфейс работы с JSON предлагает функцию, помогающую выполнить конвертацию полей типа Дата – ПрочитатьДатуJSON(). Для использования этой функции необходимо привести десериализованную строку к формату, принятому, например, в JavaScript. В рассматриваемом примере получится
следующий программный текст:

Данные.dt = ПрочитатьДатуJSON(“new Date(“+Формат(Данные.dt, “ЧГ=”)+”)”, ФорматДатыJSON.JavaScript);

В результате значение свойства Данные.dt станет равно значению 23.09.2014 13:35:40 (типа Дата). Остальная конвертация выполняется аналогичным образом.

2.3.3. Чтение с функцией восстановления

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

&НаСервере
 Функция ФункцияВосстановленияЧтения(Свойство, Значение, ДополнительныеПараметры) Экспорт
 Если Свойство = "dt" ИЛИ Свойство = "sunrise" ИЛИ Свойство = "sunset" Тогда
 Возврат ПрочитатьДатуJSON("new Date("+Формат(Значение, "ЧГ=")+")", ФорматДатыJSON.JavaScript);
 КонецЕсли;
 Если Свойство = "pressure" Тогда
 Возврат Значение*0.75;
 КонецЕсли;
 Если Свойство = "temp" Тогда
 Возврат Значение-273.15;
 КонецЕсли;
 Если Свойство = "speed" Тогда
 Возврат Значение*1.61;
 КонецЕсли;
 КонецФункции
 &НаСервере
 Процедура ЧтениеНаСервере()
 Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempweather.json");
 Данные = ПрочитатьJSON(Чтение, Ложь, , , "ФункцияВосстановленияЧтения", ЭтотОбъект);
 Чтение.Закрыть();
 КонецПроцедуры

В вышеуказанном примере присутствует особенность – функция восстановления будет вызвана для всех свойств, которые будут обнаружены в JSON-документе. Это не всегда удобно и, кроме того, существенно снижает производительность чтения JSON-документа (за счет вызова функции восстановления). Например, при чтении метеорологических данных нам необходимо выполнять особое преобразование только для свойств, в
которых содержится дата и время, а остальные свойства мы конвертировать не собираемся. Чтобы не анализировать в функции восстановления имя реквизита (как в вышеприведенном примере), можно поступить другим способом: явным образом передать в функцию чтения JSON-документа список реквизитов, которые содержат дату и время, а функцию восстановления написать исходя из того, что эта функция будет вызвана только для необходимых свойств. В результате получится следующий код:

&НаСервере
Процедура ЧтениеНаСервере()
Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempweather.json");
Реквизиты = Новый Массив;
Реквизиты.Добавить("dt");
Реквизиты.Добавить("sunrise");
Реквизиты.Добавить("sunset");
Данные = ПрочитатьJSON(Чтение, Ложь, , , "ФункцияВосстановленияЧтения", ЭтотОбъект, , Реквизиты);
Чтение.Закрыть();
КонецПроцедуры
&НаСервере
Функция ФункцияВосстановленияЧтения(Свойство, Значение, ДополнительныеПараметры) Экспорт
Возврат ПрочитатьДатуJSON("new Date("+Формат(Значение, "ЧГ=")+")", ФорматДатыJSON.JavaScript);
КонецФункции

Следует обратить внимание, что функция восстановления должна быть объявлена с указанием ключевого слова Экспорт. Также следует помнить, что функция восстановления (в модуле управляемой формы) может быть описана только в «контекстной» части модуля, т. е. с использованием директивы компиляции &НаКлиенте или &НаСервере. При разработке функции восстановления необходимо принимать во внимание тот факт, что свойства документа считываются не в том порядке, как они представлены в файле.
Рассмотрим последовательность, в которой свойства JSON-документа попадают в функцию восстановления. Для этого разместим в таблице каждое свойство файла и то, в каком порядке будет прочитано свойство:

В общем случае, можно сформулировать следующее правило обхода: первым будет прочитано свойство, которому не подчинено ни одно другое свойство. Например, свойству id не подчинено никакое свойство, и оно считывается первым. Однако свойству coord подчинено свойства lon и lat, поэтому вначале будут считаны эти свойства, а лишь затем – свойство coord, которое в качестве значения получит структуру (или соответствие) из подчиненных свойств документа.

3. Работа с XDTO-объектами

3.1. Общая информация

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

3.2. Запись

Для того чтобы выполнить запись XDTO-объекта в формате JSON, необходимо использовать (в простейшем случае) следующие объекты:
1. Собственно записываемый объект, поддерживающий преобразование в/из XDTO, например, элемент справочника.
2. Сериализатор XDTO-объектов – СериализаторXDTO;
3. Объект, обеспечивающий низкоуровневую запись данных в формате JSON – ЗаписьJSON.
4. Объект настроек сериализации НастройкиСериализацииJSON.
Собственно сериализация выполняется с помощью метода ЗаписатьJSON() объекта СериализаторXDTO. Рассмотрим пример сериализации данных типа СправочникОбъект. В качестве примера используется справочник Валюты, который содержит поля Курс (типа Число) и ДатаКурса (типа Дата):

 Данные = Справочники.Валюты.НайтиПоКоду("978").ПолучитьОбъект();
 Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempsimpleXDTOWrite.json");
 СериализаторXDTO.ЗаписатьJSON(Запись, Данные);
 Запись.Закрыть();
 
 В результате работы данный пример сформирует следующий JSON-документ:

{ “#value”: { “Ref”: “5b65bd8e-ea70-11e4-af93-e03f49b16069”, “DeletionMark”: false, “Code”: “978”, “Description”: “Евро”, “Курс”: 54.659, “ДатаКурса”: “2015-04-25T00:00:00” } }

Сериализация значений типа Дата выполняется в формате ISO (определяется механизмом XDTO) и не управляется при записи данных. Также не поддерживается использование функции преобразования при операции сериализации, в отличие от потоковой (см. раздел 16.2.4) и объектной (см. раздел 16.2.2) техник.
Также следует помнить о следующей особенности: при записи объекта не формируется его тип, поэтому после JSON-сериализации XDTO-объекта отсутствует возможность выполнить десериализацию без указания типа считываемого объекта. Предыдущий пример сериализации элемента справочника Валюты будет невозможно десериализовать без явного указания типа значения. Чтобы упростить ситуацию, можно воспользоваться
параметром НазначениеТипаXML метода ЗаписатьJSON() объекта СериализаторXDTO. Если в качестве значения этого параметра указать НазначениеТипаXML.Явное, то появится возможность выполнить десериализацию без явного указания типа, а сформированный файл будет выглядеть следующим образом:

{ “#type”: “jcfg:CatalogObject.Валюты”, “#value”: { “Ref”: “5b65bd8e-ea70-11e4-af93-e03f49b16069”, “DeletionMark”: false, “Code”: “978”, “Description”: “Евро”, “Курс”: 54.659, “ДатаКурса”: “2015-04-25T00:00:00” } }

В данном примере особого внимания заслуживает элемент #type, который и описывает тип текущего элемента. Описание префиксов пространств имен см. приложение
Общие принципы JSON-сериализации объектов XDTO идентичны XML-сериализации:
● Структура данных соответствует структуре XML-документа.
● Имеются незначительные отличия, связанные с особенностями хранения типов и представлением массивов в JSON:
● Порядок и состав свойств определен в модели XDTO и не может быть изменен.
● Если тип записываемого значения однозначно определяется из типа, определенного в         соответствующем свойстве XDTO-модели, то записывается только значение без                    идентификации типа.
● Если тип записываемого значения неоднозначно определяется из типа, определенного       в соответствующем свойстве XDTO-модели (например, значение составного типа), то           значение будет записано в виде сложного объекта JSON с отдельными свойствами для         типа (свойство #type) и значения (свойство #value). В следующем примере записаны           эквивалентные варианты представления значения типа Строка. Первая запись                         используется при неоднозначном определении типа, вторая – при однозначном:

Первая запись
{
“#type”: “jxs:string”,
“#value”: “Строка с примером”
}
Вторая запись
“Строка с примером”
JSON-сериализация объектов XDTO имеет ряд особенностей (по сравнению с XML-сериализацией):

● Коллекции значений (например, значения типа Массив, Структура и т. д.) всегда записываются виде массива JSON.
● Тип значения реквизита записывается в специальное свойство JSON с именем #type.
● Пространство имен типов записывается в специальное свойство JSON с именем #ns:
● Для встроенных в платформу пространств имен типы записываются без использования свойства #ns, но с указанием префикса:
jxс:ChartOfCharacteristicTypesObject.ДемоПланВидовХарактеристик
jxs:string
jxs:decimal

Соответствие префиксов и пространств имен см.в приложении.
● Если встретится схема, которая не имеет префикса, то имя схемы явно записывается с        помощью свойства #ns:

{
"#ns": "http://mycompany.com/data/enterprise/myscheme",
"#type": "СпециальныйОбъект",
"#value": …
}
Значения Неопределено и NULL сериализуются особым образом:
1. Неопределено:
{
"#type": "jv8:Null",
"#value": ""
}
2. NULL:
{
"ИмяРеквизита": null
}

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

{
"#type": "jxs:anyType",
"#value": {
"Filters": {
"Filter": {
"Name": "Recorder",
"Value": {
"#type": "jxs:anySimpleType",
"#value": "acc2d259-c8f3-11e2-b5da-5404a6a68c42"
}
}
},
"Record": {
"Recorder": {
"#type": "jxs:anySimpleType",
"#value": "acc2d259-c8f3-11e2-b5da-5404a6a68c42"
},
"Period": {
"#type": "jxs:anySimpleType",
"#value": "2012-09-08T00:00:00"
},
"Active": {
"#type": "jxs:anySimpleType",
"#value": "true"
},
},
"Record": {
"Recorder": {
"#type": "jxs:anySimpleType",
"#value": "acc2d259-c8f3-11e2-b5da-5404a6a68c42"
},
"Period": {
"#type": "jxs:anySimpleType",
"#value": "2012-09-08T00:00:00"
},
"Active": {
"#type": "jxs:anySimpleType",
"#value": "true"
},
},
}
}
3.3. Чтение

В общем случае, чтение XDTO-объекта из JSON-документа аналогично записи. Чтение выполняется с помощью механизма чтения XDTO-объектов из XML-файла, поэтому чтение выполняется со следующими ограничениями:
● Возможно чтение только тех объектов, для которых существует XDTO-сериализация.
● Свойства в JSON-документе должны следовать в том же порядке, как и в XDTO-объекте.
● В случае если читаемый объект не соответствует схеме – будет вызвано исключение.
● Имеется возможность выполнять чтение произвольного JSON-документа в объект XDTO (ОбъектXDTO) с помощью фабрики XDTO (ФабрикаXDTO). Такое чтение возможно в том случае, если:
● фабрика XDTO, с помощью которой выполняется чтение, «знает» о типах, которые присутствуют в JSON-документе, из которого производится чтение.
● все элементы JSON указаны без явного указания типов и элементов, специфичных для JSON-документов, формируемых при сериализации объектов XDTO.
Выполнить чтение JSON-документа в том случае, если в нем используются типы, которые неизвестны фабрике XDTO, с помощью которой выполняется чтение документа – невозможно.
Рассмотрим пример чтения некоторого JSON-документа, например, полученного при работе примера работы со справочником Валюты из предыдущего раздела .

Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempsimpleXDTOWrite.json");
 Данные = СериализаторXDTO.ПрочитатьJSON(Чтение);
 Чтение.Закрыть();

В результате работы примера в переменно Данные будет помещен объект типа СправочникОбъект.Валюты для валюты с кодом 978. Однако данное поведение будет наблюдаться только в том случае, если при выполнении JSON-сериализация значение параметра НазначениеТипаXML было установлено в значение Явное. В противном случае при попытке чтения (как указано выше) будет вызвано исключение. При чтении объекта с
неявным указанием типа объекта, читаемый тип можно передать в виде параметра метода ПрочитатьJSON(). В этом случае пример будет выглядеть следующим образом:

Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempsimpleXDTOWrite.json");
 Данные = СериализаторXDTO.ПрочитатьJSON(Чтение, Тип("СправочникОбъект.Валюты"));
 Чтение.Закрыть();

При обмене данными между прикладными решениями с помощью объектов XDTO может возникать задача, когда требуется выполнить некоторую предобработку данных, которые поступают в пакете обмена. Например, заменить любое значение некоторого типа на фиксированное значение того же типа. Для упрощения такой предобработки предназначена функция восстановления. Имя функции восстановления передается в
функцию чтения из JSON-документа для сериализатора или фабрики XDTO. При чтении объекта функция восстановления будет вызываться при десериализации значений следующих типов:
● Булево;
● Число;
● Строка;
● Дата;
● УникальныйИдентификатор;
● ДвоичныеДанные;
● ХранилищеЗначения;
● Значения перечислений;
● Значения системных перечислений;
● Ссылки на объекты базы данных.
Для значений Неопределено функция восстановления не вызывается.
При разработке функции восстановления необходимо помнить, что в этой функции можно заменить значение, которое считано из JSON-документа, но нельзя изменить тип считываемого объекта. Функция восстановления также не будет вызываться для служебных свойств, которые создаются и используются системой «1С:Предприятие», например, #type, #ns и т. д.

4. Потоковая техника работы

4.1. Общая информация

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

4.2. Запись

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

Рассмотрим простой пример записи документа:

ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, " ", Истина);
Запись = Новый ЗаписьJSON;
Запись.ПроверятьСтруктуру = Истина;
Запись.ОткрытьФайл("c:tempstreamWrite.json", , , ПараметрыJSON);
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("ДлинаЗаписи");
Запись.ЗаписатьЗначение(20);
Запись.ЗаписатьИмяСвойства("Товар");
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("Код");
Запись.ЗаписатьЗначение("0020");
Запись.ЗаписатьИмяСвойства("Наименование");
Запись.ЗаписатьЗначение("Товар");
Запись.ЗаписатьКонецОбъекта();
Запись.ЗаписатьИмяСвойства("МассивЧисел");
Запись.ЗаписатьНачалоМассива();
Запись.ЗаписатьЗначение(3.141592654, Истина);
Запись.ЗаписатьЗначение(2.718281828, Ложь);
Запись.ЗаписатьКонецМассива();
Запись.ЗаписатьКонецОбъекта();
Запись.Закрыть();

В результате исполнения этого программного кода будет сформирован следующий документ:

{
"ДлинаЗаписи": 20,
"Товар": {
"Код": "0020",
"Наименование": "Товар"
},
"МассивЧисел": [
3.141592654E0,
2.718281828
]
}

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

{“ДлинаЗаписи”:20,”Товар”:{“Код”:”0020″,”Наименование”:”Товар”},”МассивЧисел”:[3.141592654E0,2.718281828]}
Если необходимо получить JSON-документ без формирования файла, то можно использовать метод УстановитьСтроку() объекта ЗаписьJSON.
После вызова этого метода, для получения строки со сформированным JSON-документом, достаточно просто завершить запись документа методом Закрыть() объекта ЗаписьJSON:

ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, ” “, Истина);
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку(ПараметрыJSON);

Документ = Запись.Закрыть();
Теперь данный документ (из переменной Документ) можно передавать, например, в тело HTTP-запроса.

4.3. Чтение

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

Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempstreamWrite.json");
Пока Чтение.Прочитать() Цикл
Сообщить("Тип текущего элемента " + Чтение.ТипТекущегоЗначения);
Если Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.ИмяСвойства Тогда
Сообщить("Имя = " + Чтение.ТекущееЗначение);
КонецЕсли;
Если Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Булево Или
Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Строка Или
Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Число Или
Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Комментарий Тогда
Сообщить("Значение = " + Чтение.ТекущееЗначение);
КонецЕсли;
 КонецЦикла;
Чтение.Закрыть();

Тогда при чтении документа, сформированного при рассмотрении потоковой записи JSON-документа , будет сформирован следующий результат:

Тип текущего элемента Начало объекта
Тип текущего элемента Имя свойства
Имя = ДлинаЗаписи
Тип текущего элемента Число
Значение = 20
Тип текущего элемента Имя свойства
Имя = Товар
Тип текущего элемента Начало объекта
Тип текущего элемента Имя свойства
Имя = Код
Тип текущего элемента Строка
Значение = 0020
Тип текущего элемента Имя свойства
Имя = Наименование
Тип текущего элемента Строка
Значение = Товар
Тип текущего элемента Конец объекта
Тип текущего элемента Имя свойства
Имя = МассивЧисел
Тип текущего элемента Начало массива
Тип текущего элемента Число
Значение = 3,141592654
Тип текущего элемента Число
Значение = 2,718281828
Тип текущего элемента Конец массива
Тип текущего элемента Конец объекта5. Совмещение техник

Для упрощения работы с JSON, можно совмещать различные техники при формировании одного документа. Например, необходимо сформировать документ, который содержит в себе некоторый набор структур и массив. В этом случае можно все оформление документа
выполнять с помощью потоковой техники, а уже готовые структуры и массив записывать с помощью объектной техники. Важно только обеспечить корректную структуру документа перед началом объектной записи.
Приведем пример совмещения техник на следующем примере:
● В ответ на запрос внешней системы, этой системе необходимо возвращать список заказов.
● Список должен содержать дату формирования и набор заказов (соответствующий некоторому критерию).
● Каждый заказ описывается следующими параметрами:
1. Номер заказа;
2. Дата формирования заказа;
3. Контрагент по заказу;
4. Уникальный идентификатор заказа, по которому впоследствии можно получить всю информацию по заказу.
Фрагмент кода на встроенном языке, который формирует JSON-документ, будет иметь следующий вид:

НастройкиСериализации = Новый НастройкиСериализацииJSON;
НастройкиСериализации.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.УниверсальнаяДата;
НастройкиСериализации.ФорматСериализацииДат = ФорматДатыJSON.ISO;
НастройкиСериализации.СериализовыватьМассивыКакОбъекты = Истина;
ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, " ", Истина);
Запись = Новый ЗаписьJSON;
Запись.ПроверятьСтруктуру = Истина;
Запись.ОткрытьФайл("c:tempcombinedWrite.json", , , ПараметрыJSON);
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("ДатаФормирования");
Запись.ЗаписатьЗначение(ЗаписатьДатуJSON(КогдаСформировано, ФорматДатыJSON.ISO, ВариантЗаписиДатыJSON.УниверсальнаяДата));
Запись.ЗаписатьИмяСвойства("Заказы");
Заказы = Новый Массив;
Для каждого Заказ Из СписокЗаказов Цикл
ОписаниеЗаказа = Новый Структура("Ссылка, Номер, Дата, Контрагент");
ОписаниеЗаказа.Ссылка = Строка(Заказ.Ссылка);
ОписаниеЗаказа.Номер = Заказ.Номер;
ОписаниеЗаказа.Дата = Заказ.Дата;
ОписаниеЗаказа.Контрагент = Строка(Заказ.Контрагент);
Заказы.Добавить(ОписаниеЗаказа);
КонецЦикла;
ЗаписатьJSON(Запись, Заказы, НастройкиСериализации);
Запись.ЗаписатьКонецОбъекта();
Запись.Закрыть();

При исполнении данного кода предполагается, что:
● Переменная КогдаСформировано содержит значение типа Дата. Содержит дату и время формирования JSON-документа.
● Переменная СписокЗаказов является массивом ссылок на документы заказов.
Исполнение данного код приведет к формированию следующего JSON-документа:

{
"ДатаФормирования": "2014-10-06T12:57:35Z",
"Заказы": {
"0": {
"Ссылка": "f4d1495a-02b5-4d56-92c6-840c11dfb592",
"Номер": 234,
"Дата": "2014-09-30T20:00:00Z",
"Контрагент": "Иванов И.И."
},
"1": {
"Ссылка": "ee821799-2d57-475e-a330-f414e53b8bda",
"Номер": 436,
"Дата": "2014-09-24T20:00:00Z",
"Контрагент": "Петров А.П."
},
"2": {
"Ссылка": "e058a5a8-3c0d-453b-8b1c-963a35fe2b7a",
"Номер": 118,
"Дата": "2014-08-31T20:00:00Z",
"Контрагент": "Иванов И.И."
}
}
}

Изменяя значения параметров объектов НастройкиСериализации и ПараметрыJSON, а также манипулируя параметрами метода ЗаписатьДатуJSON(), можно изменять результирующий JSON-документ для максимального соответствия «ожиданиям» принимающей системы.

Приложение . Префиксы пространств имен при JSON-сериализации

Префиксы пространств имен


Моя первая статья про XDTO получила широкую поддержку. Большое спасибо всем, кто оставил отзывы. Видно, что тема является актуальной, посему — продолжение.

Обновление 28.01.2013:

Опубликована очередная статья: //infostart.ru/public/171019/

В предыдущей статье было дано небольшое введение в механизм XDTO, предлагаемый платформой 1С. Это вторая часть серии про XDTO, где предлагается рассмотреть основные моменты создания модели типов XDTO с помощью схем XML, т.к. понятие модели типов фундаментально для XDTO, и без понимания того, какие типы бывают сложно двигаться дальше.

Стоит также отметить, что данная статья, по сути, является прямым продолжением первой статьи, т.е. все, что будет написано ниже должно было быть включено в первую статью, но она, неожиданно для меня, получилась довольно большой и ее пришлось разбить на две. Таким образом, обе статьи следует считать одной, тема здесь и там рассматривается одна и та же — самые основы-основ XDTO с минимумом «внутренностей». Более детальные обзоры требуют понимания фундамента, поэтому, данная вводная часть, хоть и не так интересна, но, тем не менее, просто обязана быть. Еще раз, хочу обратить внимание — если материал статьи Вам и так известен, пролистайте ее, а в комментариях напишите те вопросы, которые нужно осветить подробно в будущих статьях.

Liquid XML Studio

Как я уже говорил, для разработки схем я пользуюсь Liquid XML Studio, а стало быть примеры схем будут приведены для этой программы. Разумеется, никто не запрещает создавать схемы любыми другими редакторами, например XML Spy или Oxygen. Старый добрый Блокнот тоже никто не отменял ;). Да, забыл! В 1С есть встроенный редактор типов XDTO. Он чуть лучше, чем блокнот, поэтому, запросто можно использовать его для небольших схем.

Какие бывают типы?

Как я уже говорил, фундаментальным понятием для XDTO является модель типов, т.е. совокупность всех прикладных (полезных бизнес-логике) типов данных. Прикладных типов может быть много, но по принципу построения все они похожи.

Во-первых, типы делятся на простые (simple) и составные (complex). Составные типы могут иметь несколько моделей содержимого, но XDTO поддерживает только простые последовательности свойств — так называемые sequence. Вдаваться в особенности моделей содержимого не будем. Sequence — это просто перечень свойств, как реквизиты справочника, например. Остальные в рамках данной темы нам не интересны.

Простые типы представляют данные, которые можно выразить одним строковым значением, например даты, строки и числа. Составные, как следует из названия, это типы содержащие несколько значений.

Стандарты XML представляют большое количество базовых типов данных. Все их перечислять нет смысла, некоторые будут в примерах, при необходимости, их можно найти в стандартах w3c, а также в гугле.

Типы могут наследовать друг-друга, так же, как в любимом всеми ООП. Например, “ФизЛицо” с атрибутами имени, номера паспорта и адресом может наследоваться типами “Сотрудник” и “Клиент”. На наследовании останавливаться не будем, думаю, все знают, что это такое. Кроме того, свойства в составных типах данных могут иметь так называемую “повторяемость”, т.е. встречаться в документе более 1 раза. По-простому, это называется список.

Как тип данных может выглядеть в XML?

Рассмотрим небольшой тип данных, который описывает одно сообщение в сетевом чате типа аськи:
У сообщения есть уникальный номер, дата-время его поступления на сервер и, собственно, тело сообщения. Здесь интересный момент. Составной тип данных может выглядеть в XML разными способами, но логически означать одно и тоже. В XDTO, как в средстве “логической” обработки данных, все типы будут обрабатываться из языка 1С одинаково, но физически в потоке XML они могут быть представлены разными способами.
Способов представления всего три: Элемент, Атрибут и Текст. Все очень просто — элементы пишутся в XML, как элементы, атрибуты — как атрибуты, а текст — как текст (логично, правда?). Напомним, как выглядят эти вещи в синтаксисе XML:

Обратите внимание, свойства number и date представлены в виде атрибутов, а тело сообщения представлено в виде текста. Если вы разрабатываете свой тип данных, то способы размещения выбирать вам. Атрибут или Элемент — можно холиварить, но в конечном итоге — это дело вкуса.

Никто не запрещает оформить наш тип данных вот так:

Ровно те же самые данные, но выглядят иначе. Для XDTO это важно, т.к. при чтении потока XML, платформа должна понимать, как отобразить XML на бизнес-объект XDTO. Об особенностях настройки этого момента в XDTO расскажу ниже.

Конструирование типа в Liquid

Рассмотрим создание указанной модели типов в Liquid. Перво-наперво, создадим чистую схему и зададим ей уникальное пространство имен (вспоминаем первую статью).
В корневом элементе схемы щелкнем правой кнопкой и выберем Add child->Complex type.

Будет добавлен новый тип. Назовем его Message, а в качестве базового укажем string. Базовый тип означает, что наш новый тип в конечном итоге является строкой. Это позволит помещать тело сообщения в текстовый узел XML (см. первую картинку, выше).

Теперь, добавим 2 атрибута — номер и дату сообщения. Правой кнопкой щелкаем на типе Message, выбираем Add child->Attribute. Задаем имя атрибута и тип его значения. Для number — это будет тип decimal (число), для date — dateTime.

Тип Message готов, теперь нужно создать объект пакета сообщений MessagePackage, как в приведенном примере.

Добавляем новый составной тип (корневой элемент, Add child->Complex type), задаем ему имя типа MessagePackage. Базовый тип не указываем.

Теперь еще один момент. Чтобы составной тип мог содержать другие элементы, нужно указать ему модель содержимого. Как я уже говорил, XDTO поддерживает только Sequence. Добавляем в MessagePackage дочерний элемент (правой кнопкой, Add child) и выбираем Sequence. Появится такая серая кракозябла, в которую впоследствии и надо добавлять дочерние элементы.

Щелкнем на этой кракозябле, укажем Add Child — > Element. Для элемента зададим имя (любое), а главное — тип значения — наш тип Message.

В результате получится такая картинка:

Теперь, нам надо указать, что Message может повторяться несколько раз внутри MessagePackage. Для этого, в контекстном меню элемента Message (того, который красненький, ведь это именно он должен повторяться) выберем пункт Cardinality.

Данное свойство позволяет указать особенности повторяемости. Как правило, элементы повторяются либо неограниченное число раз (1..unbounded), либо являются необязательными (т.е. повторяются  от 0 до 1 раз). Если cardinality не указан, что считается, что элемент обязательный и присутствует только один раз.

Для особо тяжелых случаев в свойствах элемента можно настроить точную повторяемость с помощью Min Occurs и Max Occurs. Например, можно указать, что элемент должен встречаться не менее 2-х и не более 10-раз.

Сообщений в нашем пакете может быть одно и более. Указываем Cardinality “1..unbounded”. Теперь элемент Message может повторяться более в пакете более 1 раза. В XDTO такой элемнет будет не просто свойством, а СпискомXDTO.

Обратите внимание, тип Message унаследован от string, а это значит он ЯВЛЯЕТСЯ строкой, просто у этой строки есть 2 дополнительных свойства. Кроме того, само тело сообщения не имеет какого-то имени, к которому можно обратится через точку.

Здесь вступает в игру противоречие между концепцией хранения данных в XML и объектной моделью языка 1С. Например, в общем случае, мы можем объявить тип Message, и из языка 1С задать значение number одной строкой кода:

message.number = 12;

Но что делать, если в схеме нет имени свойства (как в нашем примере с текстом), или свойство называется message-idXML не запрещает дефисы в именах, а вот компилятору 1С вряд ли понравится переменная с дефисом в имени. Мне кажется, это одна из причин, по которой в 1С разделили понятие “Схемы” и понятие “Модели данных”. XML не может однозначно отображаться на объектную модель языка. Требуются дополнительные настройки, а значит, термины, понятия и объекты…

Вернемся в Конфигуратор

Итак, представим, что в корпоративной сети нашей фирмы есть внутренний чат, который называется Corporative Messaging System, сокращенно CMS. Протокол обмена сообщениями — приведенная выше схема. По сети гуляют пакеты сообщений в виде приведенных фрагментов XML. Давайте напишем для этой системы генератор спама на языке 1С.

Сама CMS написана не на 1С, а на Турбо Бейсике 1.0 (чтобы было ясно, что XDTO применимо не только к обмену 1С->1С). При помещении файла XML в специальный каталог он подхватывается сервером CMS и транслируется дальше по сети. Архитектура не ахти какая, но это же Бейсик 1.0, так что не придираемся 🙂

Импорт схемы в конфигуратор

Первое, что мы должны сделать, это выяснить к какому пространству имен относятся типы почтовой системы. В Liquid надо выбрать корневой элемент схемы и открыть окно свойств из контекстного меню. В списке свойств ищем “targetNamespace”. Допустим в нашем примере пространство имен называется “urn:my-company/cms

Теперь, нам надо загрузить схему в конфигуратор. Это мы делали в прошлой статье: щелкаем правой кнопкой на ветке ПакетыXDTO и выбираем “Импорт схемы XML”.
Теперь, откроем на редактирование новый Пакет XDTO и посмотрим, что у него внутри.

Ага, все знакомо, только что это за __content в типе Message? Это как раз то, что платформа предлагает в качестве свойства для текстового содержимого объекта. Модель XDTO предлагает “заменители” для тех имен XML-схемы, которые не могут использоваться в качестве имен переменных в языке 1С. Давайте откроем окно свойств для элемента __content в типе Message.

Обратите внимание, на пункт “Локальное имя”. Он означает то, как свойство представлено в самом файле XML. Пункт “Имя” вверху — то, как объект выглядит в языке 1С. В идеале, они должны совпадать, но если вдруг они различаются, то здесь можно настроить трактовку подобных различий.

Также стоит обратить внимание на пункт “Форма”. Сейчас там стоит “Текст”, это значит, что значение расположено в текстовом узле. Например, если система CMS станет писать message.number не в атрибут, а в обычный элемент, то нам нужно будет поменять поле “Форма” и указать “Элемент”, чтобы новые файлы корректно обрабатывались. А если поле number еще и переименуется в message-id, то надо будет откорректировать “Локальное имя”. Таким образом, независимо (почти) от того, как данные оформлены внутри XML, мы можем настроить то, как они будут выглядеть в языке, а значит при изменении схемы XML нам не придется переписывать код.

Если нам не нравится писать Message.__content = “Hello”, то можно задать другое значение в поле “Имя”. При этом файл будет читаться без ошибок, опираясь на настройку «Форма» и «Локальное имя».

Что там насчет генератора спама?

Да, да. Я не забыл 🙂 Создаем обработку, вешаем на нее большую кнопку и всю необходимую инфраструктуру настроек (текст спама, список адресатов и т.п.).

В самом интересном месте, там где должен формироваться XML документ, код будет выглядеть следующим образом:

ПакетСообщений = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(«urn:my-company/cms»),«MessagePackage»);

Для Каждого Адресат Из СписокАдресатов Цикл

    Сообщение = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(«urn:my-company/cms»),«Message»);

    Сообщение.number = Адресат.Номер;
   
Сообщение.date = ТекущаяДата();
   
Сообщение.__content = «Купите дубленку»;

    ПакетСообщений.Добавить(Сообщение);

    Сообщение = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(«urn:my-company/cms»),«Message»);

    Сообщение.number = Адресат.Номер;
   
Сообщение.date = ТекущаяДата();
   
Сообщение.__content = «Уран недорого»;

    ПакетСообщений.Message.Добавить(Сообщение);

КонецЦикла;

Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ФайлПочтовойСистемы);
ФабрикаXDTO.ЗаписатьXML(Запись, ПакетСообщений);
Запись.Закрыть();

На этом все. Файл со списком сообщений будет корректно сформирован в том месте, где мы указали.

А теперь, следите за руками!

В приведенном примере кода объект Сообщение создается 2 раза. Угадайте, что будет, если убрать вторую строчку “Сообщение = ФабрикаXDTO.Создать”? А будет вот что:

После добавления первого сообщения пакет сообщений содержит 1 элемент. После второго добавления в дерево будет добавлен еще раз тот же самый объект. Загадка: сколько объектов «Сообщение» будет записано в файл XML?

Будет записан только один объект. И этот эффект абсолютно нигде не документирован. Происходит следующее: объект XDTO представляет собой единый граф XML документа. Т.е. все вложенные элементы уникальны, и по объекту XDTO можно гулять вверх-вниз, определяя, какой XML записан выше или ниже объекта. Если мы возьмем объект Message, который уже помещен внутрь списка и присвоим его куда-то еще (например в другой список) то он удалится из первого списка. Объект уникален. Он не будет скопирован в другое место, он будет перемещен, а его связи перестроены.

Еще один пример. Есть тип “Должность” со свойствами “Название” и “Оклад”.

Записываем список сотрудников, где все они имеют должность “Рабочий”

ДолжностьРабочий = СоздатьДолжностьXDTO(); // Фабрика.Создать(.. ля-ля-ля);
СписокСотрудников = СоздатьСписокСотрудников(); // Фабрика.Создать(.. «НекийСписок»)
Для Каждого Сотрудник Из Сотрудники Цикл

    xdtoСотрудник = ФабрикаXDTO.Создать(«namespace»,«Сотрудник»);
   
xdtoСотрудник.Должность = ДолжностьРабочий; // Это всегда один и тот же объект
   
СписокСотрудников.Добавить(xdtoСотрудник);

КонецЦикла;
ФабрикаXDTO.Записать(ЗаписьXML, СписокСотрудников);

Объект “ДолжностьРабочий” будет гулять от сотрудника к сотруднику, и должность окажется назначенной только у последнего в списке. У всех остальных Должность будет пустой, т.к. она по очереди “перепрыгнула” от одного к другому.

В заключение

В моем редакторе получается 8 страниц. По-моему, для одной статьи даже много и нужно прерваться.

В этой статье мы рассмотрели то, как создаются XML схемы с помощью Liquid и как они отображаются в объекты XDTO. В других редакторах схем они создаются практически так же. Были рассмотрены разные способы задания объектов в XML, определились с терминами “Атрибут”, “Элемент”, “Текстовый узел”. Кроме того, в приведенном примере рассмотрен один нюанс, который с непривычки сложно понять. При присваивании объекта XDTO куда-либо в другом объекте, первый объект удаляется из своего старого места (если он имел таковое), и помещается в новое место. Нельзя один раз создать маленький повторяющийся объект (вроде «Должности»), а потом помещать его в несколько разных других объектов.

На этом предлагаю остановиться. Более подробно копать XDTO будем в одной из следующих статей.

В следующей серии:

Создание собственных Фабрик

Тонкости сериализации

Стандартная XDTO сериализация, с чем едят «СериализаторXDTO» и чем он отличается от «Фабрики».

Запись/чтение XDTO в поток XML, особенности anyType.

I_learn_1c

13.05.20 — 23:01

Доброй ночи,

Помогите пожалуйста…..

HTTP ответ нужно прочитать в структуру. Код состояния 200, все норм.

На ПрочитатьJSON(ЧтениеJSON)  Ошибка при вызове метода контекста (ПрочитатьJSON). Что не так не пойму… перечитала синтакс помощник раз 10 уже, даже если пустую строку «{}» дать, то ошибка контекста. Вызывается в общем модуле с галками клиент, сервер, внешнее соединение.

Пишу:

        HTTPОтвет = Соединение.ОтправитьДляОбработки(ЗапросHTTP);

        
        СтрокаJSON = HTTPОтвет.ПолучитьТелоКакСтроку();

            

        //Разбираем ответ        

        ЧтениеJSON = Новый ЧтениеJSON;        

        ЧтениеJSON.УстановитьСтроку(СтрокаJSON);

        

        Попытка

            РезультатСоответствие = ПрочитатьJSON(ЧтениеJSON);

        Исключение

            Сообщить(«1»);

        КонецПопытки;

I_learn_1c

1 — 13.05.20 — 23:03

(0) если пробую в том же месте простенький пример (ниже), то работает. а как прочитать то что возвращает сервер в СтрокаJSON … не пойму. там много, не стала вставлять сюда

"server": 10234,
"user": 3745,
"hash": "8263ad83ce"
}
Пример кода

ДанныеСтр = Новый Структура("server,user,hash",
            10234, 3745, "8263ad83ce");
            
        мЗапись = Новый ЗаписьJSON;
        мЗапись.УстановитьСтроку();
        ЗаписатьJSON(мЗапись, ДанныеСтр);
        СтрJSON = мЗапись.Закрыть();        
        
        тЧтение = Новый ЧтениеJSON;
        тЧтение.УстановитьСтроку(СтрJSON);
        Структура = ПрочитатьJSON(тЧтение);

palsergeich

2 — 13.05.20 — 23:10

(1) проверь то что возвращает сервер валидатором/эдитором, может там не каннонический json.

Например для bulk операций в некоторых системах приходит не json а куча json разделенных символами ПС

https://jsoneditoronline.org/ я этим пользуюсь

рикардо милос

3 — 13.05.20 — 23:15

Параметры:

<ЧтениеJSON> (обязательный)

Тип: ЧтениеJSON.

Объект чтения JSON.
<ПрочитатьВСоответствие> (необязательный)

Тип: Булево.

Если установлено Истина, чтение объекта JSON будет выполнено в Соответствие.

Если установлено Ложь, объекты будут считываться в объект типа Структура.

вот этот параметр ПрочитатьВСоответствие=Истина

palsergeich

4 — 13.05.20 — 23:22

(3) чтение в соответствие выручки только тогда когда ключи не могут быть ключами структуры (точка в имени) свойства наприиер и ещё какой то экзотический случай, но там другая ошибка вроде, не про контекст.

palsergeich

5 — 13.05.20 — 23:23

Я бы таки начал с проверки json на валидность и отсутствие недопустимых символов

Asmody

6 — 13.05.20 — 23:45

И что показывает отладчик после 
СтрокаJSON = HTTPОтвет.ПолучитьТелоКакСтроку(); 

?

Asmody

7 — 13.05.20 — 23:46

(5) я бы таки начал с проверки ответа сервера

I_learn_1c

9 — 14.05.20 — 00:03

(2) https://jsoneditoronline.org/  дерево строит, вроде нормально все

Turku

10 — 14.05.20 — 00:08

Параметры:

<ЧтениеJSON> (обязательный)

Тип: ЧтениеJSON.

Объект чтения JSON.
<ПрочитатьВСоответствие> (необязательный)

Тип: Булево.

Если установлено Истина, чтение объекта JSON будет выполнено в Соответствие.

Если установлено Ложь, объекты будут считываться в объект типа Структура.

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

Значение по умолчанию: Ложь.

Надо поправить на РезультатСоответствие = ПрочитатьJSON(ЧтениеJSON,Истина);

I_learn_1c

11 — 14.05.20 — 00:11

(10) не помогает, все равно ошибка про контекст

NecroDog

12 — 14.05.20 — 00:15

Полное описание ошибки есть? Ошибка метода контекста обычно сопровождается каким-нибудь комментарием.

I_learn_1c

13 — 14.05.20 — 00:23

(12) неа… все что есть↓

Уходит в исключение вот тут, в исключении ИнформацияОбОшибке() или ОписаниеОшибки() возвращают "", если отладкой открыть  ПрочитатьJSON(ЧтениеJSON, Истина), то видна ошибка, и в РезультатСоответствие будет неопределено в итоге

Попытка
            РезультатСоответствие = ПрочитатьJSON(ЧтениеJSON, Истина);
        Исключение
            Сообщить("1");
        КонецПопытки;


https://yadi.sk/i/jMGpj7l-Mm8SCg

NecroDog

14 — 14.05.20 — 00:27

Вызовите метод ПрочитатьJSON вне попытки или в Сообщить() передайте ОписаниеОшибки(). В отладке полное описание ошибки не увидеть.

I_learn_1c

15 — 14.05.20 — 00:33

(14) ОписаниеОшибки при попадании в исключение в предприятии вывело

{ОбщийМодуль.D3_ИнтеграцияБитрикс.Модуль(44)}: Ошибка при вызове метода контекста (ПрочитатьJSON): Недопустимое состояние потока записи JSON

I_learn_1c

16 — 14.05.20 — 00:36

(15)уффф… это парсить вручную выходит нужно такое?

Garykom

17 — 14.05.20 — 00:37

Пиши HTTPОтвет в файл и читай из файла.

Garykom

18 — 14.05.20 — 00:39

(17)+ Два варианта или в строку все не влезло или не валидный json с точки зрения 1С.

Попробуй как в файлу сохранишь поизвращаться с ним, убрать разные левости (типа «/» и прочего) и выяснить на чем падает.

Garykom

19 — 14.05.20 — 00:45

(17)+ Кодировку проверить, может есть некорректные символы на которые валидаторы плюют а 1С падает

I_learn_1c

20 — 14.05.20 — 00:46

(17) что-то туплю.. а как записать HTTPОтвет в файл?

СтрокаJSON = HTTPОтвет.ПолучитьТелоКакСтроку();
        
        ИмяВремФайла = ПолучитьИмяВременногоФайла("json");
        
        мЗапись = Новый ЗаписьJSON;
        мЗапись.ОткрытьФайл(ИмяВремФайла);
        //?????? что тут 

        мЗапись.Закрыть();

Garykom

21 — 14.05.20 — 00:56

(20)

ФайлРезультат = ПолучитьИмяВременногоФайла();
затем в СП HTTPСоединение.ОтправитьДляОбработки смотри параметры

Garykom

22 — 14.05.20 — 00:59

ФайлРезультат = ПолучитьИмяВременногоФайла();
HTTPОтвет = Соединение.ОтправитьДляОбработки(ЗапросHTTP, ФайлРезультат);

I_learn_1c

23 — 14.05.20 — 01:04

(21) все равно валится с Недопустимое состояние потока записи JSON… видимо в строке серьезные косяки для 1с

ИмяВремФайла = ПолучитьИмяВременногоФайла();
        HTTPОтвет = Соединение.ОтправитьДляОбработки(ЗапросHTTP,ИмяВремФайла); 
        
        //Разбираем ответ        

        тЧтение = Новый ЧтениеJSON;    
        тЧтение.ОткрытьФайл(ИмяВремФайла);
        
        Попытка
            РезультатСоответствие = ПрочитатьJSON(тЧтение, Истина);
        Исключение
            Сообщить(ОписаниеОшибки());
        КонецПопытки;

Garykom

24 — 14.05.20 — 01:08

(23) Выложи этот ИмяВремФайла куда то и сам его проверь глазками.

Garykom

25 — 14.05.20 — 01:08

(24) *сама

Garykom

26 — 14.05.20 — 01:11

lodger

27 — 14.05.20 — 01:14

(23) это не косяки серьезные, а вариативность JSON не позволяет парсить всё что угодно в полностью автоматическом режиме

читайте https://wonderland.v8.1c.ru/blog/sredstva-raboty-s-json/

хотя бы заголовок «Сериализация типа Дата».

а еще есть педали «Функции преобразования и восстановления».

Garykom

28 — 14.05.20 — 01:14

«link»:»/company/personal/user/50/»,

Вот тут лишнее экранирование, только обратный слеш обязательно
"" - надо
"/" - можно без экранирование через ""

I_learn_1c

29 — 14.05.20 — 01:26

(28) а насчет дат заморачиваться или их должно бы прочитать?

Asmody

30 — 14.05.20 — 01:27

(8) там написано было почему закрыли

Garykom

31 — 14.05.20 — 01:28

(29) Возьми эти строковые даты, вставь в пустой json и попробуй парсятся ли в 1С.

И аналогично со всеми подозрительными

vde69

32 — 14.05.20 — 07:58

сейчас много работаю с json но не в 1с, основных причин сабжа всего 3

1. не сериализуемый объект
2. не поддерживаемый уровень вложености
3. запрещенные или не поддерживаемые символы 

искать ошибку надо так

1. общая проверка (помогает найти нестандартные символы и объекты)
 делаем двойное преобразование в каком онлайн сервисе декоде+обратное кодирование, потом сравниваем строки

2. дробим на куски по уровням вложености и пробуем загрузить в 1с кусочки

Василий Алибабаевич

33 — 14.05.20 — 08:15

(32) Другое дело. Все сразу стало понятно…)))

Обычно в дешевых американских фильмах вместо вот этого :

«1. не сериализуемый объект

2. не поддерживаемый уровень вложености
3. запрещенные или не поддерживаемые символы"
говорят - "что-то пошло не так".

Результат и одного и другого одинаков.

I_learn_1c

34 — 14.05.20 — 09:44

(28) какая-то странная фигня происходит..

в общем если поставить одну точку останова на Сообщить(«5 все ок») или Сообщить(«5») то до нее доходит без ошибок, читает в соответствие, и ссылки со слешами верно читает, только дата в виде строки в итоге «2020-05-14T09:34:23+03:00»

в структуру не читает, т.к. есть такое вот в строке «…»edit.originator»:true,…» ну а в структуре нельзя точку в заголовок, ок, допустим, пусть соответствие.

но если поставить точку останова где-то до попытки и идти пошагово, то вываливается на ПрочитатьJSON в исключение…

                Попытка
            РезультатСоответствие = ПрочитатьJSON(тЧтение,Истина);
            Сообщить("5 все ок");
            Сообщить("5");
        Исключение
            Сообщить("1 "+ОписаниеОшибки());
        КонецПопытки;

I_learn_1c

35 — 14.05.20 — 09:46

(34) с ошибкой «недопустимое состояние потока записи json»

dezss

36 — 14.05.20 — 09:55

Сделай уже Сообщить(СтрокаJSON)

И кидай что получилось сюда.

Увидим что не так.

МимохожийОднако

37 — 14.05.20 — 09:56

Убери из файла ответа /

RomanYS

38 — 14.05.20 — 09:57

(34) Убери ПрочитатьJSON из табло отладчика. Ошибка вероятно при повторном вызове.

trad

39 — 14.05.20 — 09:57

(36) нет, это слишком просто

FormatC

40 — 14.05.20 — 09:58

Процедура ЗаполнитьДанныеИзОтветаJSON(Результат, ТекстJSON, ТипДанных)          ТекстJSON = СокрЛП(Сред(ТекстJSON, 2));    // удалим открывающий символ структуры(массива)           НомерЗначения = 0;          Пока ТекстJSON <> "" Цикл                  ПервыйСимвол = Лев(ТекстJSON, 1);         Если ПервыйСимвол = "{" Тогда             // вложенная структура              Значение = Новый Структура;             ЗаполнитьДанныеИзОтветаJSON(Значение, ТекстJSON, "Структура");                          Если ТипДанных = "Структура" Тогда                 Результат.Вставить("Значение" + ?(НомерЗначения = 0, "", НомерЗначения), Значение);                 НомерЗначения = НомерЗначения + 1;             ИначеЕсли ТипДанных = "Массив" Тогда                 Результат.Добавить(Значение);             КонецЕсли;                  ИначеЕсли ПервыйСимвол = "[" Тогда             // вложенный массив              Значение = Новый Массив;             ЗаполнитьДанныеИзОтветаJSON(Значение, ТекстJSON, "Массив");                          Если ТипДанных = "Структура" Тогда                 Результат.Вставить("Значение" + ?(НомерЗначения = 0, "", НомерЗначения), Значение);                 НомерЗначения = НомерЗначения + 1;             Иначе                 Результат.Добавить(Значение);             КонецЕсли;                      ИначеЕсли ПервыйСимвол = "}" И ТипДанных = "Структура" Тогда             // структура закончилась              ТекстJSON = СокрЛП(Сред(ТекстJSON, 2));             Если Лев(ТекстJSON, 1) = "," Тогда                 ТекстJSON = СокрЛП(Сред(ТекстJSON, 2));             КонецЕсли;                          Возврат;                      ИначеЕсли ПервыйСимвол = "]" И ТипДанных = "Массив" Тогда             // массив закончился              ТекстJSON = СокрЛП(Сред(ТекстJSON, 2));             Если Лев(ТекстJSON, 1) = "," Тогда                 ТекстJSON = СокрЛП(Сред(ТекстJSON, 2));             КонецЕсли;                          Возврат;                      Иначе                          Если ТипДанных = "Структура" Тогда                 //ПервыйКавычка = Ложь;                  //Если Лев(ТекстJSON, 1) = """" Тогда                  //    ПервыйКавычка = Истина;                  //КонецЕсли;                                   Поз = Найти(ТекстJSON, ":");                 Если Поз = 0 Тогда                     // неверный формат, прервемся                      Прервать;                 КонецЕсли;                                  //ПредпоследнийКавычка = Ложь;                  //Если Сред(ТекстJSON, Поз - 1, 1) = """" Тогда                  //    ПредпоследнийКавычка = Истина;                  //КонецЕсли;                                   ИмяЗначения = СокрЛП(Лев(ТекстJSON, Поз - 1));                 ИмяЗначения = СтрЗаменить(ИмяЗначения, """", "");                                  ТекстJSON = СокрЛП(Сред(ТекстJSON, Поз+1));                                                  Если Лев(ТекстJSON, 1) = "{" Тогда                     // значение является структурой                      Значение = Новый Структура;                     ЗаполнитьДанныеИзОтветаJSON(Значение, ТекстJSON, "Структура");                                      ИначеЕсли Лев(ТекстJSON, 1) = "[" Тогда                     // значение является массивом                      Значение = Новый Массив;                     ЗаполнитьДанныеИзОтветаJSON(Значение, ТекстJSON, "Массив");                                      Иначе                     // обычное значение                      ПервыйКавычка = Ложь;                     ПредпоследнийКавычка = Ложь;                     Поз = 0;                     Для Сч = 1 По СтрДлина(ТекстJSON) Цикл                         Символ = Сред(ТекстJSON, Сч, 1);                                                  Если Символ = """" Тогда                             Если ПервыйКавычка Тогда                                 ПредпоследнийКавычка = Истина;                             Иначе                                 ПервыйКавычка = Истина;                             КонецЕсли;                                                     КонецЕсли;                                                  Если (Символ = "," И ((ПервыйКавычка И ПредпоследнийКавычка) Или (Не ПервыйКавычка И Не ПредпоследнийКавычка))) ИЛИ Символ = "]" ИЛИ Символ = "}" Тогда                             Поз = Сч;                             Прервать;                         КонецЕсли;                     КонецЦикла;                                          //ПредпоследнийКавычка = Ложь;                      //Если Сред(ТекстJSON, Поз - 1, 1) = """" Тогда                      //    ПредпоследнийКавычка = Истина;                      //КонецЕсли;                                           Если Поз = 0 Тогда                         Значение = ТекстJSON;                         ТекстJSON = "";                                              Иначе                         Значение = Лев(ТекстJSON, Поз - 1);                         Значение = СтрЗаменить(Значение, """", "");                         ТекстJSON = СокрЛП(Сред(ТекстJSON, Поз + ?(Сред(ТекстJSON, Поз, 1) = ",", 1, 0)));                                             КонецЕсли;                                          Значение = СокрЛП(Значение);                                      КонецЕсли;                                  Попытка                 Результат.Вставить(ИмяЗначения, Значение);             Исключение             Конецпопытки;                          ИначеЕсли ТипДанных = "Массив" Тогда                                  // обычное значение                  Поз = 0;                 Для Сч = 1 По СтрДлина(ТекстJSON) Цикл                     Символ = Сред(ТекстJSON, Сч, 1);                     Если Символ = "," ИЛИ Символ = "]" ИЛИ Символ = "}" Тогда                         Поз = Сч;                         Прервать;                     КонецЕсли;                 КонецЦикла;                                  //ПредпоследнийКавычка = Ложь;                  //Если Сред(ТекстJSON, Поз - 1, 1) = """" Тогда                  //    ПредпоследнийКавычка = Истина;                  //КонецЕсли;                                   Если Поз = 0 Тогда                     Значение = ТекстJSON;                     ТекстJSON = "";                                      Иначе                     Значение = Лев(ТекстJSON, Поз - 1);                     Значение = СтрЗаменить(Значение, """", "");                     ТекстJSON = СокрЛП(Сред(ТекстJSON, Поз + ?(Сред(ТекстJSON, Поз, 1) = ",", 1, 0)));                                      КонецЕсли;                                  Значение = СокрЛП(Значение);                                  Результат.Добавить(Значение);                              КонецЕсли;                                       КонецЕсли;              КонецЦикла;      КонецПроцедуры Функция ЗаполнитьСтруктуруИзОтветаJSON(Знач ТекстJSON) Экспорт          Результат = Новый Структура;          ТекстJSON = СтрЗаменить(ТекстJSON, """", """");    // заменим последовательность " на "      ТекстJSON = СтрЗаменить(ТекстJSON, """", "");        // а теперь удалим все кавычки           Если Лев(ТекстJSON, 1) = "{" Тогда         // начало структуры          ЗаполнитьДанныеИзОтветаJSON(Результат, ТекстJSON, "Структура");              ИначеЕсли Лев(ТекстJSON, 1) = "[" Тогда         // начало массива          МассивДанных = Новый Массив;         ЗаполнитьДанныеИзОтветаJSON(МассивДанных, ТекстJSON, "Массив");                  Результат.Вставить("Значение", МассивДанных);              КонецЕсли;              Возврат Результат;      КонецФункции

dezss

41 — 14.05.20 — 09:59

(38) Хм..а это идея…вот даже не думал, что кто-то догадается такое делать.

I_learn_1c

42 — 14.05.20 — 09:59

(36) там большая строка, прошлую ветку закрыли, за то что вставила

arsik

43 — 14.05.20 — 10:01

trad

44 — 14.05.20 — 10:01

(42) облако

I_learn_1c

45 — 14.05.20 — 10:05

(38) похоже работает... если не ставить точку на самой строке  РезультатСоответствие = ПрочитатьJSON(тЧтение,Истина);

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

I_learn_1c

46 — 14.05.20 — 10:08

(45) точнее точку поставить можно, в табло не надо выводить…  спасибо большое

RomanYS

47 — 14.05.20 — 10:23

(46) Именно: не надо в табло вызывать методы, которые изменяют контекст

  

dezss

48 — 14.05.20 — 10:24

Хм…а фотки в качестве награды не будет?)))

1С: Предприятие 8.3.14.Документация

Формат JSON является универсальным способом представления при обмене данными (RFC 7159, https://tools.ietf.org/html/rfc7159). Данные в формате JSON представляют собой (в закодированном виде):
Объект – неупорядоченное множество пар ключ:значение, заключенный в фигурные скобки ({}). Пары ключ:значение разделяются запятыми (,).
Массив – множество значений. Массив заключается в квадратные скобки ([]). Значения разделяются запятыми (,).
● Значение – может быть строкой, числом, объектом, массивов или литералом true, false, null.
● Строка – набор символов, заключенный в двойные кавычки (“”).
● Число – сериализуется с разделителем точка (.). Точность числа не ограничена.
Таким образом, с помощью вышеперечисленных элементов допускается описание объектов любой сложности для представления в формате JSON. Например, некоторый код на встроенном языке, формирует некоторый набор данных (в структуре):

Данные = Новый Структура;
Данные.Вставить("Фамилия", "Иванов");
Данные.Вставить("Имя", "Иван");
Данные.Вставить("Отчество", "Иванович");
Данные.Вставить("ДеньРождения", ДатаРождения);
Телефоны = Новый Массив;
Телефоны.Добавить("+7-987-123-45-67");
Телефоны.Добавить("+7-986-987-65-43");
Данные.Вставить("Телефоны", Телефоны);

Сериализуя этот объект в JSON, может быть получен следующий документ:

 {
"Фамилия": "Иванов",
"Имя": "Иван",
"Отчество": "Иванович",
"ДатаРождения": "2009-02-15T00:00:00Z",
"Телефоны": [
"+7-987-123-45-67",
"+7-986-987-65-43"
]
}

JSON не стандартизует формат представления даты. В силу этого представление даты в JSON-документе определяется предпочтениями прикладного разработчика, который формирует документ, и требованиями системы, которая будет обрабатывать JSON-документ. Система «1С:Предприятие» поддерживает несколько форматов представления даты (задается с помощью системного перечисления ФорматДатыJSON):
1. Формат ISO (значение ФорматДатыJSON.ISO). В этом случае дата сериализуется следующим образом: “2009-02-15T00:00:00+0400”.
2. Формат JavaScript (значение ФорматДатыJSON.JavaScript). В этом случае дата сериализуется следующим образом: “new Date
(1234656000000)”.
3. Формат Microsoft (значение ФорматДатыJSON.Microsoft). В этом случае дата сериализуется следующим образом: “/Date(1234656000000)/”
или “/Date(1234656000000)/” (в зависимости от режима экранирования символов).
Дата может записываться несколькими вариантами (для примера используется дата 10 мая 2014 13:14:15 в зоне UTC+4):
● как локальная дата: 2014-05-10T13:14:15.
● как локальная дата с указанием смещения: 2014-05-10T13:14:15+04:00.
● как дата в UTC: 2014-05-10T09:14:15Z.
Управлять этим можно с помощью системного перечисления ВариантЗаписиДатыJSON. Дату в варианте UTC можно записать в любом формате (ISO, JavaScript и Microsoft), остальные варианты представления даты возможны только в том случае, если сериализация выполняется в формате ISO.
При записи JSON-документа предоставляются возможности по управлению формируемыми данными: настраивать перенос строк, формат сериализации даты, обработка символа “/” и т. д. Эти настройки можно выполнять с помощью объектов НастройкиСериализацииJSON и ПараметрыЗаписиJSON.
Работа с данными в формате JSON может выполняться в нескольких техниках:
● Объектная техника – позволяет формировать простые и небольшие JSON-документы для обмена с внешними приложениями или веб-сервисами. Структура JSON-документа автоматически формируется системой «1С:Предприятие» во время записи документа. Более подробно описание данной техники см. раздел 16.2.2. Специальным вариантом такой техники является возможность сериализации в формате JSON для XDTO-
объектов системы «1С:Предприятие». Более подробное описание работы с XDTO-объектами см. раздел 16.2.3.
● Потоковая техника – позволяет работать с данными большого объема без загрузки их в память приложения. Навигация по JSON-документу  полностью ложится на прикладного разработчика (как при записи, так и при чтении документа). Более подробно описание данной техники см. раздел 16.2.4.
● Совмещенная техника – позволяет сочетать гибкость потоковой техники и простоту объектной техники. Более подробно описание данной техники см. раздел 16.2.5.

2. Объектная техника работы

2.1. Общая информация

Система «1С:Предприятие» поддерживает сериализацию следующих данных в формат JSON:
● Строка – сериализуется в строку;
● Число – сериализуется в число;
● Булево – сериализуется в литералы true и false;
● Неопределено – сериализуется в null
● Массив, ФиксированныйМассив – сериализуется в массив JSON в том случае, если любой элемент массива может быть сериализован в JSON.
● Структура, ФиксированнаяСтруктура – сериализуется в объект JSON:
● Ключ – ключ элемента структуры.
● Значение – значение элемента структуры в том случае, если значение может быть                 сериализовано в JSON.
● Соответствие, ФиксированноеСоответствие – сериализуется в объект JSON:
● Ключ – ключ элемента соответствия. Ключ может быть только значением типа Строка, в противном случае будет генерироваться исключение.
● Значение – значение элемента соответствия в том случае, если значение может быть сериализовано в JSON.
● Дата – формат сериализации определяется настройками.
● Если выполняется попытка сериализации типа, отсутствующего в данном списке – будет вызвано исключение.
При работе с объектной техникой, имеется возможность читать (и писать) данные в соответствие или структуру. Основное отличие между этими объектами состоит в том, что ключ элемента структуры подчиняется правилам формирования переменной на встроенном языке, а ключ элемента соответствия может быть любым. С учетом того, чтоб JSON не накладывает ограничений на значение ключа, не все JSON-документы можно
прочитать в структуру. Еще одним различием между структурой и соответствием является то, что к элементам структуры можно обращаться «через точку», а к элементам соответствия такой доступ не предоставляется. В связи с этим, может оказаться удобным получать данные в виде структуры, если ключи из JSON-документа соответствуют требованиям к ключам структур системы «1С:Предприятие».
Объектная техника предполагает достаточно простую работу с данными, однако платой за это является большой расход памяти, т. к. весь JSON-документ обрабатывается целиком в оперативной памяти.

2.2. Запись

Для того чтобы выполнить запись объекта в формате JSON, необходимо использовать (в простейшем случае) следующие объекты:
1. Собственно записываемый объект, например типа Структура.
2. Объект, обеспечивающий низкоуровневую запись данных в формате JSON – ЗаписьJSON.
3. Объект настроек сериализации НастройкиСериализацииJSON.
Метод глобального контекста ЗаписатьJSON() оперирует вышеперечисленными объектами. Рассмотрим пример, в котором потребуется записать структуру, которая состоит из трех элементов разного типа (но типы являются примитивными):

Запись = Новый ЗаписьJSON;
Запись.ОткрытьФайл("c:tempsimpleWrite.json");
Данные = Новый Структура;
Данные.Вставить("ДлинаЗаписи", 20);
Данные.Вставить("КлючЗаписи", "abcdefgh");
Данные.Вставить("ДатаИзменения", ТекущаяДата());
ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON);
Запись.Закрыть();

В результате работы данный пример сформирует следующий JSON-документ:

{
“ДлинаЗаписи”: 20,
“КлючЗаписи”: “abcdefgh”,
“ДатаИзменения”: “2014-09-24T17:32:11”
}
Если в сериализуемых данных участвуют значения типа Дата, то может потребоваться управлять форматом сериализации. Для этого необходимо установить параметры объекта НастройкиСериализацииJSON. В следующем примере дата будет сериализоваться в формате JavaScript:

НастройкиСериализации = Новый НастройкиСериализацииJSON;
НастройкиСериализации.ФорматСериализацииДат = ФорматДатыJSON.JavaScript;
НастройкиСериализации.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.УниверсальнаяДата;
Запись = Новый ЗаписьJSON;
Запись.ОткрытьФайл("c:tempsimpleWrite.json");
Данные = Новый Структура;
Данные.Вставить("ДлинаЗаписи", 20);
Данные.Вставить("КлючЗаписи", "abcdefgh");
Данные.Вставить("ДатаИзменения", ТекущаяДата());
ЗаписатьJSON(Запись, Данные, НастройкиСериализации);
Запись.Закрыть();

В результате работы данный пример сформирует следующий JSON-документ:

{
"ДлинаЗаписи": 20,
"КлючЗаписи": "abcdefgh",
"ДатаИзменения": "new Date(1411565832000)"
}

Если несколько расширить набор записываемых данных, например, добавить к ним значение типа УникальныйИдентификатор, то запись не будет выполнена. В результате исполнения кода:

Запись = Новый ЗаписьJSON;
Запись.ОткрытьФайл("c:tempsimpleWrite.json");
Данные = Новый Структура;
Данные.Вставить("ДлинаЗаписи", 20);
Данные.Вставить("КлючЗаписи", "abcdefgh");
Данные.Вставить("ДатаИзменения", ТекущаяДата());
Данные.Вставить("UID", Новый УникальныйИдентификатор);
ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON);
Запись.Закрыть();

Будет вызвано исключение:

Ошибка при вызове метода контекста (ЗаписатьJSON)
ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON);
по причине:
Передано значение недопустимого типа

Причиной такого поведения является то, что тип УникальныйИдентификатор не входит в состав JSON-сериализуемых типов данных системы «1С:Предприятие». Однако система предоставляет возможность «обойти» это ограничение: необходимо передать в функцию ЗаписатьJSON() имя функции обратного вызова, которая будет заниматься JSON-сериализацией неподдерживаемых объектов. Эта функция будет называться
функцией преобразования. При этом формат такой сериализации будет разрабатывать непосредственно сам прикладной разработчик. Надо понимать, что такая сериализация не будет универсальной, т. к. принимающая сторона, не обладающая знаниями о формате сериализации, не сможет прочитать переданные данные. Другими словами, формат сериализации необходимо разрабатывать совместно всеми сторонами обмена
такого рода данными.
С учетом вышесказанного, более сложный вариант обмена теперь происходит следующим образом:
● Вызывается функция сериализации объекта в формат JSON (ЗаписатьJSON()).
● Система «1С:Предприятие» для каждого элемента структуры, тип значения которого не сериализуется в формат JSON, будет вызываться функция преобразования.
● Функция преобразования анализирует переданный объект и принимает решение – отказаться от его записи или вернуть платформе значение, которое может быть сериализовано в JSON.
Доработанный код записи будет выглядеть следующим образом:

&НаСервере
Процедура ЗаписьНаСервере()
Запись = Новый ЗаписьJSON;
Запись.ОткрытьФайл("c:tempcompositeWrite.json");
Данные = Новый Структура;
Данные.Вставить("ДлинаЗаписи", 20);
Данные.Вставить("КлючЗаписи", "abcdefgh");
Данные.Вставить("ДатаИзменения", ТекущаяДата());
Данные.Вставить("UID", Новый УникальныйИдентификатор);
ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON, "ФункцияПреобразованияЗаписи", ЭтотОбъект);
Запись.Закрыть();
КонецПроцедуры
&НаСервере
Функция ФункцияПреобразованияЗаписи(Свойство, Значение, ДополнительныеПараметры, Отказ) Экспорт
Если ТипЗнч(Значение) = Тип("УникальныйИдентификатор") Тогда
Возврат Строка(Значение);
КонецЕсли;
Отказ = Истина;
КонецФункции

Следует обратить внимание, что функция преобразования должна быть объявлена с указанием ключевого слова Экспорт. Также следует помнить, что функция преобразования (в модуле управляемой формы) может быть описана только в «контекстной» части модуля, т. е. с использованием директивы компиляции &НаКлиенте или &НаСервере.
В результате работы приведенного примера будет сформирован следующий JSON-документ:

{
"ДлинаЗаписи": 20,
"КлючЗаписи": "abcdefgh",
"ДатаИзменения": "2014-09-24T18:09:13",
"UID": "5a80e5dc-252b-416f-b487-d9ddcebc523e"
}

При создании функции преобразования следует помнить о следующих особенностях:
● Функция преобразования вызывается для значений всех типов, которые не поддерживают сериализацию в JSON (см. раздел 16.2.1).
● Если функция преобразования вернет значение, которое не может быть сериализовано в JSON – будет вызвано исключение.
● Если переданное значение является структурой, то вызов функции преобразования для элементов этой структуры будет вызваться до того, как в поток будет записано имя свойства этого элемента. В результате функция преобразования может отказаться от записи значения и структура формируемого JSON-документа не будет нарушена.
● Имя свойства будет передано в функцию преобразования только для элементов структур и соответствий.

2.3. Чтение

2.3.1. Общая схема

Чтение данных в объектной технике выглядит аналогично записи. Рассмотрим пример чтения файлов, которые формировались во время рассмотрения объектной записи (предыдущий раздел).

Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempsimpleWrite.json");
Данные = ПрочитатьJSON(Чтение, Ложь, "ДатаИзменения", ФорматДатыJSON.JavaScript);
Чтение.Закрыть();

Документ имеет следующее содержание (с точностью до значения даты):

{
"ДлинаЗаписи": 20,
"КлючЗаписи": "abcdefgh",
"ДатаИзменения": "new Date(1411565832000)"
}

При чтении JSON-документа в переменную Данные будет сформирована структура вида:

Ключ = ДлинаЗаписи, значение = 20
Ключ = КлючЗаписи, значение = abcdefgh
Ключ = ДатаИзменения, значение = <значение даты и времени>

Такой вариант чтения хорошо подходит в том случае, если читаемые данные могут быть преобразованы в структуру или соответствие и все читаемые данные могут быть однозначно десериализованы без потери информации о типе. Если читаемые данные обладают сложной структурой или требуют выполнения дополнительных преобразований при чтении, то можно пойти двумя путями:
1. Получить соответствие (или структуру), в которое будет полностью загружен JSON-документ, и потом завершить преобразование с помощью обхода получившегося объекта.
2. Заниматься необходимым преобразованием непосредственно во время загрузки данных.

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

{
"id":524901,"name":"Moscow","dt":1411464940000,
"coord": { "lon":37.62,"lat":55.75 },
"sys": { "country":"RU","sunrise":1411442400000,"sunset":1411485660000 },
"weather": [
{ "main":"Clouds","description":"пасмурно" }
],
"main": { "temp":282.93,"pressure":1014,"humidity":93 },
"wind": { "speed":4,"deg":350 },
"clouds": { "all":90 }
}

Кратко рассмотрим описание формата:
● id – идентификатор города;
● name – имя города;
● dt – дата и время получения погоды, в формате Unix, GMT;
● coord – местоположение города:
● lon – долгота;
● lan – широта.
● sys – дополнительная информация:
● country – страна расположения города;
● sunrise – время восхода Солнца в формате Unix, GMT;
● sunset – время заката Солнца, в формате Unix, GMT.
● weather – дополнительная информация о погоде:
● main – общая характеристика погоды;
● description – описание погоды.
● main – собственно описание погоды:
● temp – температура, в градусах Кельвина. Для получения градусов Цельсия необходимо вычесть 273.15;
● pressure – давление в гектопаскалях. Для перевода в миллиметры ртутного столба, надо значение давления умножить на 0,75.
● humidity – влажность в %.
● wind – параметры ветра:
● speed – скорость в милях в час. Для перевода в километры в час необходимо умножить на 1,61.
● deg – направление ветра, в градусах.
● clouds – информация об осадках:
● all – вероятность возникновения осадков, в %.
В результате загрузки этих данных должна получиться структура, где все времена представлены стандартным типом Дата, температура – в градусах Цельсия, скорость – в километрах в час, а давление – в миллиметрах ртутного столба.
Рассмотрим загрузку данной информации обоими способами. Данные записаны в файле c:tempweather.json.

2.3.2. Чтение с постобработкой

Собственно процесс чтения выглядит просто:

Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempweather.json");
Данные = ПрочитатьJSON(Чтение, Ложь);
Чтение.Закрыть();

В результате в переменной Данные будет следующая информация:

Рис. 3 Результат загрузки

Без учета необходимости конвертации все выглядит предсказуемо. Однако дата и время автоматически не преобразовались. Можно попробовать указать системе на то, что поле dt (например) является полем, где находится дата и время:

Чтение = Новый ЧтениеJSON; Чтение.ОткрытьФайл("c:tempweather.json");
Данные = ПрочитатьJSON(Чтение, Ложь, "dt", ФорматДатыJSON.JavaScript);
Чтение.Закрыть();

В результате получим сообщение об ошибке следующего вида:

Ошибка при вызове метода контекста (ПрочитатьJSON)
Данные = ПрочитатьJSON(Чтение, Ложь, "dt", ФорматДатыJSON.JavaScript);
по причине:
Представление даты имеет неверный формат

Ошибка произошла потому, что система не понимает формат даты и времени, выраженной простым числом. Программный интерфейс работы с JSON предлагает функцию, помогающую выполнить конвертацию полей типа Дата – ПрочитатьДатуJSON(). Для использования этой функции необходимо привести десериализованную строку к формату, принятому, например, в JavaScript. В рассматриваемом примере получится
следующий программный текст:

Данные.dt = ПрочитатьДатуJSON(“new Date(“+Формат(Данные.dt, “ЧГ=”)+”)”, ФорматДатыJSON.JavaScript);

В результате значение свойства Данные.dt станет равно значению 23.09.2014 13:35:40 (типа Дата). Остальная конвертация выполняется аналогичным образом.

2.3.3. Чтение с функцией восстановления

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

&НаСервере
Функция ФункцияВосстановленияЧтения(Свойство, Значение, ДополнительныеПараметры) Экспорт
Если Свойство = "dt" ИЛИ Свойство = "sunrise" ИЛИ Свойство = "sunset" Тогда
Возврат ПрочитатьДатуJSON("new Date("+Формат(Значение, "ЧГ=")+")", ФорматДатыJSON.JavaScript);
КонецЕсли;
Если Свойство = "pressure" Тогда
Возврат Значение*0.75;
КонецЕсли;
Если Свойство = "temp" Тогда
Возврат Значение-273.15;
КонецЕсли;
Если Свойство = "speed" Тогда
Возврат Значение*1.61;
КонецЕсли;
КонецФункции
&НаСервере
Процедура ЧтениеНаСервере()
Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempweather.json");
Данные = ПрочитатьJSON(Чтение, Ложь, , , "ФункцияВосстановленияЧтения", ЭтотОбъект);
Чтение.Закрыть();
КонецПроцедуры

В вышеуказанном примере присутствует особенность – функция восстановления будет вызвана для всех свойств, которые будут обнаружены в JSON-документе. Это не всегда удобно и, кроме того, существенно снижает производительность чтения JSON-документа (за счет вызова функции восстановления). Например, при чтении метеорологических данных нам необходимо выполнять особое преобразование только для свойств, в
которых содержится дата и время, а остальные свойства мы конвертировать не собираемся. Чтобы не анализировать в функции восстановления имя реквизита (как в вышеприведенном примере), можно поступить другим способом: явным образом передать в функцию чтения JSON-документа список реквизитов, которые содержат дату и время, а функцию восстановления написать исходя из того, что эта функция будет вызвана только для необходимых свойств. В результате получится следующий код:

&НаСервере
Процедура ЧтениеНаСервере()
Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempweather.json");
Реквизиты = Новый Массив;
Реквизиты.Добавить("dt");
Реквизиты.Добавить("sunrise");
Реквизиты.Добавить("sunset");
Данные = ПрочитатьJSON(Чтение, Ложь, , , "ФункцияВосстановленияЧтения", ЭтотОбъект, , Реквизиты);
Чтение.Закрыть();
КонецПроцедуры
&НаСервере
Функция ФункцияВосстановленияЧтения(Свойство, Значение, ДополнительныеПараметры) Экспорт
Возврат ПрочитатьДатуJSON("new Date("+Формат(Значение, "ЧГ=")+")", ФорматДатыJSON.JavaScript);
КонецФункции

Следует обратить внимание, что функция восстановления должна быть объявлена с указанием ключевого слова Экспорт. Также следует помнить, что функция восстановления (в модуле управляемой формы) может быть описана только в «контекстной» части модуля, т. е. с использованием директивы компиляции &НаКлиенте или &НаСервере. При разработке функции восстановления необходимо принимать во внимание тот факт, что свойства документа считываются не в том порядке, как они представлены в файле.
Рассмотрим последовательность, в которой свойства JSON-документа попадают в функцию восстановления. Для этого разместим в таблице каждое свойство файла и то, в каком порядке будет прочитано свойство:

В общем случае, можно сформулировать следующее правило обхода: первым будет прочитано свойство, которому не подчинено ни одно другое свойство. Например, свойству id не подчинено никакое свойство, и оно считывается первым. Однако свойству coord подчинено свойства lon и lat, поэтому вначале будут считаны эти свойства, а лишь затем – свойство coord, которое в качестве значения получит структуру (или соответствие) из подчиненных свойств документа.

3. Работа с XDTO-объектами

3.1. Общая информация

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

3.2. Запись

Для того чтобы выполнить запись XDTO-объекта в формате JSON, необходимо использовать (в простейшем случае) следующие объекты:
1. Собственно записываемый объект, поддерживающий преобразование в/из XDTO, например, элемент справочника.
2. Сериализатор XDTO-объектов – СериализаторXDTO;
3. Объект, обеспечивающий низкоуровневую запись данных в формате JSON – ЗаписьJSON.
4. Объект настроек сериализации НастройкиСериализацииJSON.
Собственно сериализация выполняется с помощью метода ЗаписатьJSON() объекта СериализаторXDTO. Рассмотрим пример сериализации данных типа СправочникОбъект. В качестве примера используется справочник Валюты, который содержит поля Курс (типа Число) и ДатаКурса (типа Дата):

 Данные = Справочники.Валюты.НайтиПоКоду("978").ПолучитьОбъект();
Запись = Новый ЗаписьJSON;
Запись.ОткрытьФайл("c:tempsimpleXDTOWrite.json");
СериализаторXDTO.ЗаписатьJSON(Запись, Данные);
Запись.Закрыть();
В результате работы данный пример сформирует следующий JSON-документ:

{ “#value”: { “Ref”: “5b65bd8e-ea70-11e4-af93-e03f49b16069”, “DeletionMark”: false, “Code”: “978”, “Description”: “Евро”, “Курс”: 54.659, “ДатаКурса”: “2015-04-25T00:00:00” } }

Сериализация значений типа Дата выполняется в формате ISO (определяется механизмом XDTO) и не управляется при записи данных. Также не поддерживается использование функции преобразования при операции сериализации, в отличие от потоковой (см. раздел 16.2.4) и объектной (см. раздел 16.2.2) техник.
Также следует помнить о следующей особенности: при записи объекта не формируется его тип, поэтому после JSON-сериализации XDTO-объекта отсутствует возможность выполнить десериализацию без указания типа считываемого объекта. Предыдущий пример сериализации элемента справочника Валюты будет невозможно десериализовать без явного указания типа значения. Чтобы упростить ситуацию, можно воспользоваться
параметром НазначениеТипаXML метода ЗаписатьJSON() объекта СериализаторXDTO. Если в качестве значения этого параметра указать НазначениеТипаXML.Явное, то появится возможность выполнить десериализацию без явного указания типа, а сформированный файл будет выглядеть следующим образом:

{ “#type”: “jcfg:CatalogObject.Валюты”, “#value”: { “Ref”: “5b65bd8e-ea70-11e4-af93-e03f49b16069”, “DeletionMark”: false, “Code”: “978”, “Description”: “Евро”, “Курс”: 54.659, “ДатаКурса”: “2015-04-25T00:00:00” } }

В данном примере особого внимания заслуживает элемент #type, который и описывает тип текущего элемента. Описание префиксов пространств имен см. приложение
Общие принципы JSON-сериализации объектов XDTO идентичны XML-сериализации:
● Структура данных соответствует структуре XML-документа.
● Имеются незначительные отличия, связанные с особенностями хранения типов и представлением массивов в JSON:
● Порядок и состав свойств определен в модели XDTO и не может быть изменен.
● Если тип записываемого значения однозначно определяется из типа, определенного в         соответствующем свойстве XDTO-модели, то записывается только значение без                    идентификации типа.
● Если тип записываемого значения неоднозначно определяется из типа, определенного       в соответствующем свойстве XDTO-модели (например, значение составного типа), то           значение будет записано в виде сложного объекта JSON с отдельными свойствами для         типа (свойство #type) и значения (свойство #value). В следующем примере записаны           эквивалентные варианты представления значения типа Строка. Первая запись                         используется при неоднозначном определении типа, вторая – при однозначном:

Первая запись
{
“#type”: “jxs:string”,
“#value”: “Строка с примером”
}
Вторая запись
“Строка с примером”
JSON-сериализация объектов XDTO имеет ряд особенностей (по сравнению с XML-сериализацией):

● Коллекции значений (например, значения типа Массив, Структура и т. д.) всегда записываются виде массива JSON.
● Тип значения реквизита записывается в специальное свойство JSON с именем #type.
● Пространство имен типов записывается в специальное свойство JSON с именем #ns:
● Для встроенных в платформу пространств имен типы записываются без использования свойства #ns, но с указанием префикса:
jxс:ChartOfCharacteristicTypesObject.ДемоПланВидовХарактеристик
jxs:string
jxs:decimal

Соответствие префиксов и пространств имен см.в приложении.
● Если встретится схема, которая не имеет префикса, то имя схемы явно записывается с        помощью свойства #ns:

{
"#ns": "http://mycompany.com/data/enterprise/myscheme",
"#type": "СпециальныйОбъект",
"#value": …
}
Значения Неопределено и NULL сериализуются особым образом:
1. Неопределено:
{
"#type": "jv8:Null",
"#value": ""
}
2. NULL:
{
"ИмяРеквизита": null
}

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

{
"#type": "jxs:anyType",
"#value": {
"Filters": {
"Filter": {
"Name": "Recorder",
"Value": {
"#type": "jxs:anySimpleType",
"#value": "acc2d259-c8f3-11e2-b5da-5404a6a68c42"
}
}
},
"Record": {
"Recorder": {
"#type": "jxs:anySimpleType",
"#value": "acc2d259-c8f3-11e2-b5da-5404a6a68c42"
},
"Period": {
"#type": "jxs:anySimpleType",
"#value": "2012-09-08T00:00:00"
},
"Active": {
"#type": "jxs:anySimpleType",
"#value": "true"
},
},
"Record": {
"Recorder": {
"#type": "jxs:anySimpleType",
"#value": "acc2d259-c8f3-11e2-b5da-5404a6a68c42"
},
"Period": {
"#type": "jxs:anySimpleType",
"#value": "2012-09-08T00:00:00"
},
"Active": {
"#type": "jxs:anySimpleType",
"#value": "true"
},
},
}
}
3.3. Чтение

В общем случае, чтение XDTO-объекта из JSON-документа аналогично записи. Чтение выполняется с помощью механизма чтения XDTO-объектов из XML-файла, поэтому чтение выполняется со следующими ограничениями:
● Возможно чтение только тех объектов, для которых существует XDTO-сериализация.
● Свойства в JSON-документе должны следовать в том же порядке, как и в XDTO-объекте.
● В случае если читаемый объект не соответствует схеме – будет вызвано исключение.
● Имеется возможность выполнять чтение произвольного JSON-документа в объект XDTO (ОбъектXDTO) с помощью фабрики XDTO (ФабрикаXDTO). Такое чтение возможно в том случае, если:
● фабрика XDTO, с помощью которой выполняется чтение, «знает» о типах, которые присутствуют в JSON-документе, из которого производится чтение.
● все элементы JSON указаны без явного указания типов и элементов, специфичных для JSON-документов, формируемых при сериализации объектов XDTO.
Выполнить чтение JSON-документа в том случае, если в нем используются типы, которые неизвестны фабрике XDTO, с помощью которой выполняется чтение документа – невозможно.
Рассмотрим пример чтения некоторого JSON-документа, например, полученного при работе примера работы со справочником Валюты из предыдущего раздела .

Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempsimpleXDTOWrite.json");
Данные = СериализаторXDTO.ПрочитатьJSON(Чтение);
Чтение.Закрыть();

В результате работы примера в переменно Данные будет помещен объект типа СправочникОбъект.Валюты для валюты с кодом 978. Однако данное поведение будет наблюдаться только в том случае, если при выполнении JSON-сериализация значение параметра НазначениеТипаXML было установлено в значение Явное. В противном случае при попытке чтения (как указано выше) будет вызвано исключение. При чтении объекта с
неявным указанием типа объекта, читаемый тип можно передать в виде параметра метода ПрочитатьJSON(). В этом случае пример будет выглядеть следующим образом:

Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempsimpleXDTOWrite.json");
Данные = СериализаторXDTO.ПрочитатьJSON(Чтение, Тип("СправочникОбъект.Валюты"));
Чтение.Закрыть();

При обмене данными между прикладными решениями с помощью объектов XDTO может возникать задача, когда требуется выполнить некоторую предобработку данных, которые поступают в пакете обмена. Например, заменить любое значение некоторого типа на фиксированное значение того же типа. Для упрощения такой предобработки предназначена функция восстановления. Имя функции восстановления передается в
функцию чтения из JSON-документа для сериализатора или фабрики XDTO. При чтении объекта функция восстановления будет вызываться при десериализации значений следующих типов:
● Булево;
● Число;
● Строка;
● Дата;
● УникальныйИдентификатор;
● ДвоичныеДанные;
● ХранилищеЗначения;
● Значения перечислений;
● Значения системных перечислений;
● Ссылки на объекты базы данных.
Для значений Неопределено функция восстановления не вызывается.
При разработке функции восстановления необходимо помнить, что в этой функции можно заменить значение, которое считано из JSON-документа, но нельзя изменить тип считываемого объекта. Функция восстановления также не будет вызываться для служебных свойств, которые создаются и используются системой «1С:Предприятие», например, #type, #ns и т. д.

4. Потоковая техника работы

4.1. Общая информация

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

4.2. Запись

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

Рассмотрим простой пример записи документа:

ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, " ", Истина);
Запись = Новый ЗаписьJSON;
Запись.ПроверятьСтруктуру = Истина;
Запись.ОткрытьФайл("c:tempstreamWrite.json", , , ПараметрыJSON);
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("ДлинаЗаписи");
Запись.ЗаписатьЗначение(20);
Запись.ЗаписатьИмяСвойства("Товар");
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("Код");
Запись.ЗаписатьЗначение("0020");
Запись.ЗаписатьИмяСвойства("Наименование");
Запись.ЗаписатьЗначение("Товар");
Запись.ЗаписатьКонецОбъекта();
Запись.ЗаписатьИмяСвойства("МассивЧисел");
Запись.ЗаписатьНачалоМассива();
Запись.ЗаписатьЗначение(3.141592654, Истина);
Запись.ЗаписатьЗначение(2.718281828, Ложь);
Запись.ЗаписатьКонецМассива();
Запись.ЗаписатьКонецОбъекта();
Запись.Закрыть();

В результате исполнения этого программного кода будет сформирован следующий документ:

{
"ДлинаЗаписи": 20,
"Товар": {
"Код": "0020",
"Наименование": "Товар"
},
"МассивЧисел": [
3.141592654E0,
2.718281828
]
}

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

{“ДлинаЗаписи”:20,”Товар”:{“Код”:”0020″,”Наименование”:”Товар”},”МассивЧисел”:[3.141592654E0,2.718281828]}
Если необходимо получить JSON-документ без формирования файла, то можно использовать метод УстановитьСтроку() объекта ЗаписьJSON.
После вызова этого метода, для получения строки со сформированным JSON-документом, достаточно просто завершить запись документа методом Закрыть() объекта ЗаписьJSON:

ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, ” “, Истина);
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку(ПараметрыJSON);

Документ = Запись.Закрыть();
Теперь данный документ (из переменной Документ) можно передавать, например, в тело HTTP-запроса.

4.3. Чтение

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

Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempstreamWrite.json");
Пока Чтение.Прочитать() Цикл
Сообщить("Тип текущего элемента " + Чтение.ТипТекущегоЗначения);
Если Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.ИмяСвойства Тогда
Сообщить("Имя = " + Чтение.ТекущееЗначение);
КонецЕсли;
Если Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Булево Или
Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Строка Или
Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Число Или
Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Комментарий Тогда
Сообщить("Значение = " + Чтение.ТекущееЗначение);
КонецЕсли;
КонецЦикла;
Чтение.Закрыть();

Тогда при чтении документа, сформированного при рассмотрении потоковой записи JSON-документа , будет сформирован следующий результат:

Тип текущего элемента Начало объекта
Тип текущего элемента Имя свойства
Имя = ДлинаЗаписи
Тип текущего элемента Число
Значение = 20
Тип текущего элемента Имя свойства
Имя = Товар
Тип текущего элемента Начало объекта
Тип текущего элемента Имя свойства
Имя = Код
Тип текущего элемента Строка
Значение = 0020
Тип текущего элемента Имя свойства
Имя = Наименование
Тип текущего элемента Строка
Значение = Товар
Тип текущего элемента Конец объекта
Тип текущего элемента Имя свойства
Имя = МассивЧисел
Тип текущего элемента Начало массива
Тип текущего элемента Число
Значение = 3,141592654
Тип текущего элемента Число
Значение = 2,718281828
Тип текущего элемента Конец массива
Тип текущего элемента Конец объекта5. Совмещение техник

Для упрощения работы с JSON, можно совмещать различные техники при формировании одного документа. Например, необходимо сформировать документ, который содержит в себе некоторый набор структур и массив. В этом случае можно все оформление документа
выполнять с помощью потоковой техники, а уже готовые структуры и массив записывать с помощью объектной техники. Важно только обеспечить корректную структуру документа перед началом объектной записи.
Приведем пример совмещения техник на следующем примере:
● В ответ на запрос внешней системы, этой системе необходимо возвращать список заказов.
● Список должен содержать дату формирования и набор заказов (соответствующий некоторому критерию).
● Каждый заказ описывается следующими параметрами:
1. Номер заказа;
2. Дата формирования заказа;
3. Контрагент по заказу;
4. Уникальный идентификатор заказа, по которому впоследствии можно получить всю информацию по заказу.
Фрагмент кода на встроенном языке, который формирует JSON-документ, будет иметь следующий вид:

НастройкиСериализации = Новый НастройкиСериализацииJSON;
НастройкиСериализации.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.УниверсальнаяДата;
НастройкиСериализации.ФорматСериализацииДат = ФорматДатыJSON.ISO;
НастройкиСериализации.СериализовыватьМассивыКакОбъекты = Истина;
ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, " ", Истина);
Запись = Новый ЗаписьJSON;
Запись.ПроверятьСтруктуру = Истина;
Запись.ОткрытьФайл("c:tempcombinedWrite.json", , , ПараметрыJSON);
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("ДатаФормирования");
Запись.ЗаписатьЗначение(ЗаписатьДатуJSON(КогдаСформировано, ФорматДатыJSON.ISO, ВариантЗаписиДатыJSON.УниверсальнаяДата));
Запись.ЗаписатьИмяСвойства("Заказы");
Заказы = Новый Массив;
Для каждого Заказ Из СписокЗаказов Цикл
ОписаниеЗаказа = Новый Структура("Ссылка, Номер, Дата, Контрагент");
ОписаниеЗаказа.Ссылка = Строка(Заказ.Ссылка);
ОписаниеЗаказа.Номер = Заказ.Номер;
ОписаниеЗаказа.Дата = Заказ.Дата;
ОписаниеЗаказа.Контрагент = Строка(Заказ.Контрагент);
Заказы.Добавить(ОписаниеЗаказа);
КонецЦикла;
ЗаписатьJSON(Запись, Заказы, НастройкиСериализации);
Запись.ЗаписатьКонецОбъекта();
Запись.Закрыть();

При исполнении данного кода предполагается, что:
● Переменная КогдаСформировано содержит значение типа Дата. Содержит дату и время формирования JSON-документа.
● Переменная СписокЗаказов является массивом ссылок на документы заказов.
Исполнение данного код приведет к формированию следующего JSON-документа:

{
"ДатаФормирования": "2014-10-06T12:57:35Z",
"Заказы": {
"0": {
"Ссылка": "f4d1495a-02b5-4d56-92c6-840c11dfb592",
"Номер": 234,
"Дата": "2014-09-30T20:00:00Z",
"Контрагент": "Иванов И.И."
},
"1": {
"Ссылка": "ee821799-2d57-475e-a330-f414e53b8bda",
"Номер": 436,
"Дата": "2014-09-24T20:00:00Z",
"Контрагент": "Петров А.П."
},
"2": {
"Ссылка": "e058a5a8-3c0d-453b-8b1c-963a35fe2b7a",
"Номер": 118,
"Дата": "2014-08-31T20:00:00Z",
"Контрагент": "Иванов И.И."
}
}
}

Изменяя значения параметров объектов НастройкиСериализации и ПараметрыJSON, а также манипулируя параметрами метода ЗаписатьДатуJSON(), можно изменять результирующий JSON-документ для максимального соответствия «ожиданиям» принимающей системы.

Приложение . Префиксы пространств имен при JSON-сериализации

Префиксы пространств имен


При входе в базу 1с вы можете увидеть “Ошибка преобразования данных XDTO:

Начало Свойства: errorProcessingSettings

Форма: Элемент

Тип: {http://v8.1c.ru/8.2/managed-application/core}ErrorProcessingSettings по причине

Чаще всего ошибка возникает при определенном типе запуска: это либо через тонкий клиент, либо через линк42, случаи бывают разные. Через браузер такие базы запускаются без ошибок.

Есть простое решение данной проблемы.

Достаточно запустить базу доступным нам способом (где нет ошибки) включить Функции тех. специалиста (Меню — Настройки — Параметры — Режим технического специалиста)

В Функциях для технического специалиста ищем Управление настройками обработки ошибок (Стандартные)

Запускаем

Готово!

Уже более 10 000 компаний работают
в облачной 1С от 42Clouds

— Консультация по 1С Бесплатно!

— Поддержка 24/7 по техническим вопросам: в чате, по телефону, по почте

— Все типовые конфигурации онлайн, доступ через RDP, Remote App, Web

Студворк — интернет-сервис помощи студентам

Добрый день!
Сливаю две базы(базы разнородные, но в данном случае объекты совпадают), использую обработку Выгрузка и загрузка данных XML.
Дошел до того, что пытаюсь загрузить всего один элемент, корневую группу справочника физ лиц

Кликните здесь для просмотра всего текста

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<V8Exch:_1CV8DtUD xmlns:V8Exch="http://www.1c.ru/V8/1CV8DtUD/" xmlns:core="http://v8.1c.ru/data" xmlns:v8="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <V8Exch:Data>
        <v8:CatalogObject.ФизическиеЛица>
            <v8:IsFolder>true</v8:IsFolder>
            <v8:Ref xsi:type="v8:CatalogRef.ФизическиеЛица">6b90e188-c868-11ec-97a4-00d8616e2fe4</v8:Ref>
            <v8:DeletionMark>false</v8:DeletionMark>
            <v8:Parent xsi:type="v8:CatalogRef.ФизическиеЛица">00000000-0000-0000-0000-000000000000</v8:Parent>
            <v8:Code>001900001</v8:Code>
            <v8:Description>Кочубеевский</v8:Description>
        </v8:CatalogObject.ФизическиеЛица>
    </V8Exch:Data>
    <PredefinedData/>
</V8Exch:_1CV8DtUD>

Элемент не грузит, падает на функции ЗаписанноеЗначение = Сериализатор.ПрочитатьXML(ЧтениеXML);
с ошибкой:
Ошибка преобразования данных XDTO:
НачалоСвойства: {http://v8.1c.ru/8.1/data/enterprise/current-config}CatalogObject.ФизическиеЛица Форма: Элемент Тип: {http://v8.1c.ru/8.1/data/enterprise/current-config}CatalogObject.ФизическиеЛица
по причине:
Ошибка преобразования данных XDTO:
КонецСвойства: {http://v8.1c.ru/8.1/data/enterprise/current-config}CatalogObject.ФизическиеЛица Форма: Элемент Тип: {http://v8.1c.ru/8.1/data/enterprise/current-config}CatalogObject.ФизическиеЛица

Я выгрузил аналогичную группу из базы приемника:

Кликните здесь для просмотра всего текста

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<V8Exch:_1CV8DtUD xmlns:V8Exch="http://www.1c.ru/V8/1CV8DtUD/" xmlns:core="http://v8.1c.ru/data" xmlns:v8="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <V8Exch:Data>
        <v8:CatalogObject.ФизическиеЛица>
            <v8:IsFolder>true</v8:IsFolder>
            <v8:Ref xsi:type="v8:CatalogRef.ФизическиеЛица">cd4c4ee4-7fbd-11e0-8751-00155d006422</v8:Ref>
            <v8:DeletionMark>false</v8:DeletionMark>
            <v8:Parent xsi:type="v8:CatalogRef.ФизическиеЛица">00000000-0000-0000-0000-000000000000</v8:Parent>
            <v8:Code>1000000001</v8:Code>
            <v8:Description>НОВОАЛЕКСАНДРОВСКИЙ</v8:Description>
        </v8:CatalogObject.ФизическиеЛица>
    </V8Exch:Data>
    <PredefinedData/>
</V8Exch:_1CV8DtUD>

Она обратно загружается без проблем.
из отличий только ссылка на объект, код и наименование.
Я в тупике, подскажите, в чем может быть причина.

1С: Предприятие 8.3.14.Документация

1 Общая информация

Формат JSON является универсальным способом представления при обмене данными (RFC 7159, https://tools.ietf.org/html/rfc7159). Данные в формате JSON представляют собой (в закодированном виде):
Объект – неупорядоченное множество пар ключ:значение, заключенный в фигурные скобки ({}). Пары ключ:значение разделяются запятыми (,).
Массив – множество значений. Массив заключается в квадратные скобки ([]). Значения разделяются запятыми (,).
● Значение – может быть строкой, числом, объектом, массивов или литералом true, false, null.
● Строка – набор символов, заключенный в двойные кавычки (“”).
● Число – сериализуется с разделителем точка (.). Точность числа не ограничена.
Таким образом, с помощью вышеперечисленных элементов допускается описание объектов любой сложности для представления в формате JSON. Например, некоторый код на встроенном языке, формирует некоторый набор данных (в структуре):

Данные = Новый Структура;
 Данные.Вставить("Фамилия", "Иванов");
 Данные.Вставить("Имя", "Иван");
 Данные.Вставить("Отчество", "Иванович");
 Данные.Вставить("ДеньРождения", ДатаРождения);
 Телефоны = Новый Массив;
 Телефоны.Добавить("+7-987-123-45-67");
 Телефоны.Добавить("+7-986-987-65-43");
 Данные.Вставить("Телефоны", Телефоны);

Сериализуя этот объект в JSON, может быть получен следующий документ:

 {
 "Фамилия": "Иванов",
 "Имя": "Иван",
 "Отчество": "Иванович",
 "ДатаРождения": "2009-02-15T00:00:00Z",
 "Телефоны": [
 "+7-987-123-45-67",
 "+7-986-987-65-43"
 ]
 }

JSON не стандартизует формат представления даты. В силу этого представление даты в JSON-документе определяется предпочтениями прикладного разработчика, который формирует документ, и требованиями системы, которая будет обрабатывать JSON-документ. Система «1С:Предприятие» поддерживает несколько форматов представления даты (задается с помощью системного перечисления ФорматДатыJSON):
1. Формат ISO (значение ФорматДатыJSON.ISO). В этом случае дата сериализуется следующим образом: “2009-02-15T00:00:00+0400”.
2. Формат JavaScript (значение ФорматДатыJSON.JavaScript). В этом случае дата сериализуется следующим образом: “new Date
(1234656000000)”.
3. Формат Microsoft (значение ФорматДатыJSON.Microsoft). В этом случае дата сериализуется следующим образом: “/Date(1234656000000)/”
или “/Date(1234656000000)/” (в зависимости от режима экранирования символов).
Дата может записываться несколькими вариантами (для примера используется дата 10 мая 2014 13:14:15 в зоне UTC+4):
● как локальная дата: 2014-05-10T13:14:15.
● как локальная дата с указанием смещения: 2014-05-10T13:14:15+04:00.
● как дата в UTC: 2014-05-10T09:14:15Z.
Управлять этим можно с помощью системного перечисления ВариантЗаписиДатыJSON. Дату в варианте UTC можно записать в любом формате (ISO, JavaScript и Microsoft), остальные варианты представления даты возможны только в том случае, если сериализация выполняется в формате ISO.
При записи JSON-документа предоставляются возможности по управлению формируемыми данными: настраивать перенос строк, формат сериализации даты, обработка символа “/” и т. д. Эти настройки можно выполнять с помощью объектов НастройкиСериализацииJSON и ПараметрыЗаписиJSON.
Работа с данными в формате JSON может выполняться в нескольких техниках:
● Объектная техника – позволяет формировать простые и небольшие JSON-документы для обмена с внешними приложениями или веб-сервисами. Структура JSON-документа автоматически формируется системой «1С:Предприятие» во время записи документа. Более подробно описание данной техники см. раздел 16.2.2. Специальным вариантом такой техники является возможность сериализации в формате JSON для XDTO-
объектов системы «1С:Предприятие». Более подробное описание работы с XDTO-объектами см. раздел 16.2.3.
● Потоковая техника – позволяет работать с данными большого объема без загрузки их в память приложения. Навигация по JSON-документу  полностью ложится на прикладного разработчика (как при записи, так и при чтении документа). Более подробно описание данной техники см. раздел 16.2.4.
● Совмещенная техника – позволяет сочетать гибкость потоковой техники и простоту объектной техники. Более подробно описание данной техники см. раздел 16.2.5.

2. Объектная техника работы

2.1. Общая информация

Система «1С:Предприятие» поддерживает сериализацию следующих данных в формат JSON:
● Строка – сериализуется в строку;
● Число – сериализуется в число;
● Булево – сериализуется в литералы true и false;
● Неопределено – сериализуется в null
● Массив, ФиксированныйМассив – сериализуется в массив JSON в том случае, если любой элемент массива может быть сериализован в JSON.
● Структура, ФиксированнаяСтруктура – сериализуется в объект JSON:
● Ключ – ключ элемента структуры.
● Значение – значение элемента структуры в том случае, если значение может быть                 сериализовано в JSON.
● Соответствие, ФиксированноеСоответствие – сериализуется в объект JSON:
● Ключ – ключ элемента соответствия. Ключ может быть только значением типа Строка, в противном случае будет генерироваться исключение.
● Значение – значение элемента соответствия в том случае, если значение может быть сериализовано в JSON.
● Дата – формат сериализации определяется настройками.
● Если выполняется попытка сериализации типа, отсутствующего в данном списке – будет вызвано исключение.
При работе с объектной техникой, имеется возможность читать (и писать) данные в соответствие или структуру. Основное отличие между этими объектами состоит в том, что ключ элемента структуры подчиняется правилам формирования переменной на встроенном языке, а ключ элемента соответствия может быть любым. С учетом того, чтоб JSON не накладывает ограничений на значение ключа, не все JSON-документы можно
прочитать в структуру. Еще одним различием между структурой и соответствием является то, что к элементам структуры можно обращаться «через точку», а к элементам соответствия такой доступ не предоставляется. В связи с этим, может оказаться удобным получать данные в виде структуры, если ключи из JSON-документа соответствуют требованиям к ключам структур системы «1С:Предприятие».
Объектная техника предполагает достаточно простую работу с данными, однако платой за это является большой расход памяти, т. к. весь JSON-документ обрабатывается целиком в оперативной памяти.

2.2. Запись

Для того чтобы выполнить запись объекта в формате JSON, необходимо использовать (в простейшем случае) следующие объекты:
1. Собственно записываемый объект, например типа Структура.
2. Объект, обеспечивающий низкоуровневую запись данных в формате JSON – ЗаписьJSON.
3. Объект настроек сериализации НастройкиСериализацииJSON.
Метод глобального контекста ЗаписатьJSON() оперирует вышеперечисленными объектами. Рассмотрим пример, в котором потребуется записать структуру, которая состоит из трех элементов разного типа (но типы являются примитивными):

Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempsimpleWrite.json");
 Данные = Новый Структура;
 Данные.Вставить("ДлинаЗаписи", 20);
 Данные.Вставить("КлючЗаписи", "abcdefgh");
 Данные.Вставить("ДатаИзменения", ТекущаяДата());
 ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON);
 Запись.Закрыть();

В результате работы данный пример сформирует следующий JSON-документ:

{
“ДлинаЗаписи”: 20,
“КлючЗаписи”: “abcdefgh”,
“ДатаИзменения”: “2014-09-24T17:32:11”
}
Если в сериализуемых данных участвуют значения типа Дата, то может потребоваться управлять форматом сериализации. Для этого необходимо установить параметры объекта НастройкиСериализацииJSON. В следующем примере дата будет сериализоваться в формате JavaScript:

НастройкиСериализации = Новый НастройкиСериализацииJSON;
 НастройкиСериализации.ФорматСериализацииДат = ФорматДатыJSON.JavaScript;
 НастройкиСериализации.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.УниверсальнаяДата;
 Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempsimpleWrite.json");
 Данные = Новый Структура;
 Данные.Вставить("ДлинаЗаписи", 20);
 Данные.Вставить("КлючЗаписи", "abcdefgh");
 Данные.Вставить("ДатаИзменения", ТекущаяДата());
 ЗаписатьJSON(Запись, Данные, НастройкиСериализации);
 Запись.Закрыть();

В результате работы данный пример сформирует следующий JSON-документ:

{
 "ДлинаЗаписи": 20,
 "КлючЗаписи": "abcdefgh",
 "ДатаИзменения": "new Date(1411565832000)"
 }

Если несколько расширить набор записываемых данных, например, добавить к ним значение типа УникальныйИдентификатор, то запись не будет выполнена. В результате исполнения кода:

Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempsimpleWrite.json");
 Данные = Новый Структура;
 Данные.Вставить("ДлинаЗаписи", 20);
 Данные.Вставить("КлючЗаписи", "abcdefgh");
 Данные.Вставить("ДатаИзменения", ТекущаяДата());
 Данные.Вставить("UID", Новый УникальныйИдентификатор);
 ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON);
 Запись.Закрыть();

Будет вызвано исключение:

Ошибка при вызове метода контекста (ЗаписатьJSON)
 ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON);
 по причине:
 Передано значение недопустимого типа

Причиной такого поведения является то, что тип УникальныйИдентификатор не входит в состав JSON-сериализуемых типов данных системы «1С:Предприятие». Однако система предоставляет возможность «обойти» это ограничение: необходимо передать в функцию ЗаписатьJSON() имя функции обратного вызова, которая будет заниматься JSON-сериализацией неподдерживаемых объектов. Эта функция будет называться
функцией преобразования. При этом формат такой сериализации будет разрабатывать непосредственно сам прикладной разработчик. Надо понимать, что такая сериализация не будет универсальной, т. к. принимающая сторона, не обладающая знаниями о формате сериализации, не сможет прочитать переданные данные. Другими словами, формат сериализации необходимо разрабатывать совместно всеми сторонами обмена
такого рода данными.
С учетом вышесказанного, более сложный вариант обмена теперь происходит следующим образом:
● Вызывается функция сериализации объекта в формат JSON (ЗаписатьJSON()).
● Система «1С:Предприятие» для каждого элемента структуры, тип значения которого не сериализуется в формат JSON, будет вызываться функция преобразования.
● Функция преобразования анализирует переданный объект и принимает решение – отказаться от его записи или вернуть платформе значение, которое может быть сериализовано в JSON.
Доработанный код записи будет выглядеть следующим образом:

&НаСервере
 Процедура ЗаписьНаСервере()
 Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempcompositeWrite.json");
 Данные = Новый Структура;
 Данные.Вставить("ДлинаЗаписи", 20);
 Данные.Вставить("КлючЗаписи", "abcdefgh");
 Данные.Вставить("ДатаИзменения", ТекущаяДата());
 Данные.Вставить("UID", Новый УникальныйИдентификатор);
 ЗаписатьJSON(Запись, Данные, Новый НастройкиСериализацииJSON, "ФункцияПреобразованияЗаписи", ЭтотОбъект);
 Запись.Закрыть();
 КонецПроцедуры
 &НаСервере
 Функция ФункцияПреобразованияЗаписи(Свойство, Значение, ДополнительныеПараметры, Отказ) Экспорт
 Если ТипЗнч(Значение) = Тип("УникальныйИдентификатор") Тогда
 Возврат Строка(Значение);
 КонецЕсли;
 Отказ = Истина;
 КонецФункции

Следует обратить внимание, что функция преобразования должна быть объявлена с указанием ключевого слова Экспорт. Также следует помнить, что функция преобразования (в модуле управляемой формы) может быть описана только в «контекстной» части модуля, т. е. с использованием директивы компиляции &НаКлиенте или &НаСервере.
В результате работы приведенного примера будет сформирован следующий JSON-документ:

{
 "ДлинаЗаписи": 20,
 "КлючЗаписи": "abcdefgh",
 "ДатаИзменения": "2014-09-24T18:09:13",
 "UID": "5a80e5dc-252b-416f-b487-d9ddcebc523e"
 }

При создании функции преобразования следует помнить о следующих особенностях:
● Функция преобразования вызывается для значений всех типов, которые не поддерживают сериализацию в JSON (см. раздел 16.2.1).
● Если функция преобразования вернет значение, которое не может быть сериализовано в JSON – будет вызвано исключение.
● Если переданное значение является структурой, то вызов функции преобразования для элементов этой структуры будет вызваться до того, как в поток будет записано имя свойства этого элемента. В результате функция преобразования может отказаться от записи значения и структура формируемого JSON-документа не будет нарушена.
● Имя свойства будет передано в функцию преобразования только для элементов структур и соответствий.

2.3. Чтение

2.3.1. Общая схема

Чтение данных в объектной технике выглядит аналогично записи. Рассмотрим пример чтения файлов, которые формировались во время рассмотрения объектной записи (предыдущий раздел).

Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempsimpleWrite.json");
 Данные = ПрочитатьJSON(Чтение, Ложь, "ДатаИзменения", ФорматДатыJSON.JavaScript);
 Чтение.Закрыть();

Документ имеет следующее содержание (с точностью до значения даты):

{
 "ДлинаЗаписи": 20,
 "КлючЗаписи": "abcdefgh",
 "ДатаИзменения": "new Date(1411565832000)"
 }

При чтении JSON-документа в переменную Данные будет сформирована структура вида:

Ключ = ДлинаЗаписи, значение = 20
Ключ = КлючЗаписи, значение = abcdefgh
Ключ = ДатаИзменения, значение = <значение даты и времени>

Такой вариант чтения хорошо подходит в том случае, если читаемые данные могут быть преобразованы в структуру или соответствие и все читаемые данные могут быть однозначно десериализованы без потери информации о типе. Если читаемые данные обладают сложной структурой или требуют выполнения дополнительных преобразований при чтении, то можно пойти двумя путями:
1. Получить соответствие (или структуру), в которое будет полностью загружен JSON-документ, и потом завершить преобразование с помощью обхода получившегося объекта.
2. Заниматься необходимым преобразованием непосредственно во время загрузки данных.

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

{
 "id":524901,"name":"Moscow","dt":1411464940000,
 "coord": { "lon":37.62,"lat":55.75 },
 "sys": { "country":"RU","sunrise":1411442400000,"sunset":1411485660000 },
 "weather": [
 { "main":"Clouds","description":"пасмурно" }
 ],
 "main": { "temp":282.93,"pressure":1014,"humidity":93 },
 "wind": { "speed":4,"deg":350 },
 "clouds": { "all":90 }
 }

Кратко рассмотрим описание формата:
● id – идентификатор города;
● name – имя города;
● dt – дата и время получения погоды, в формате Unix, GMT;
● coord – местоположение города:
● lon – долгота;
● lan – широта.
● sys – дополнительная информация:
● country – страна расположения города;
● sunrise – время восхода Солнца в формате Unix, GMT;
● sunset – время заката Солнца, в формате Unix, GMT.
● weather – дополнительная информация о погоде:
● main – общая характеристика погоды;
● description – описание погоды.
● main – собственно описание погоды:
● temp – температура, в градусах Кельвина. Для получения градусов Цельсия необходимо вычесть 273.15;
● pressure – давление в гектопаскалях. Для перевода в миллиметры ртутного столба, надо значение давления умножить на 0,75.
● humidity – влажность в %.
● wind – параметры ветра:
● speed – скорость в милях в час. Для перевода в километры в час необходимо умножить на 1,61.
● deg – направление ветра, в градусах.
● clouds – информация об осадках:
● all – вероятность возникновения осадков, в %.
В результате загрузки этих данных должна получиться структура, где все времена представлены стандартным типом Дата, температура – в градусах Цельсия, скорость – в километрах в час, а давление – в миллиметрах ртутного столба.
Рассмотрим загрузку данной информации обоими способами. Данные записаны в файле c:tempweather.json.

2.3.2. Чтение с постобработкой

Собственно процесс чтения выглядит просто:

Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempweather.json");
 Данные = ПрочитатьJSON(Чтение, Ложь);
 Чтение.Закрыть();

В результате в переменной Данные будет следующая информация:

Рис. 3 Результат загрузки

Без учета необходимости конвертации все выглядит предсказуемо. Однако дата и время автоматически не преобразовались. Можно попробовать указать системе на то, что поле dt (например) является полем, где находится дата и время:

Чтение = Новый ЧтениеJSON; Чтение.ОткрытьФайл("c:tempweather.json");
Данные = ПрочитатьJSON(Чтение, Ложь, "dt", ФорматДатыJSON.JavaScript);
 Чтение.Закрыть();

В результате получим сообщение об ошибке следующего вида:

Ошибка при вызове метода контекста (ПрочитатьJSON)

Данные = ПрочитатьJSON(Чтение, Ложь, "dt", ФорматДатыJSON.JavaScript);

по причине:

Представление даты имеет неверный формат

Ошибка произошла потому, что система не понимает формат даты и времени, выраженной простым числом. Программный интерфейс работы с JSON предлагает функцию, помогающую выполнить конвертацию полей типа Дата – ПрочитатьДатуJSON(). Для использования этой функции необходимо привести десериализованную строку к формату, принятому, например, в JavaScript. В рассматриваемом примере получится
следующий программный текст:

Данные.dt = ПрочитатьДатуJSON(“new Date(“+Формат(Данные.dt, “ЧГ=”)+”)”, ФорматДатыJSON.JavaScript);

В результате значение свойства Данные.dt станет равно значению 23.09.2014 13:35:40 (типа Дата). Остальная конвертация выполняется аналогичным образом.

2.3.3. Чтение с функцией восстановления

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

&НаСервере
 Функция ФункцияВосстановленияЧтения(Свойство, Значение, ДополнительныеПараметры) Экспорт
 Если Свойство = "dt" ИЛИ Свойство = "sunrise" ИЛИ Свойство = "sunset" Тогда
 Возврат ПрочитатьДатуJSON("new Date("+Формат(Значение, "ЧГ=")+")", ФорматДатыJSON.JavaScript);
 КонецЕсли;
 Если Свойство = "pressure" Тогда
 Возврат Значение*0.75;
 КонецЕсли;
 Если Свойство = "temp" Тогда
 Возврат Значение-273.15;
 КонецЕсли;
 Если Свойство = "speed" Тогда
 Возврат Значение*1.61;
 КонецЕсли;
 КонецФункции
 &НаСервере
 Процедура ЧтениеНаСервере()
 Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempweather.json");
 Данные = ПрочитатьJSON(Чтение, Ложь, , , "ФункцияВосстановленияЧтения", ЭтотОбъект);
 Чтение.Закрыть();
 КонецПроцедуры

В вышеуказанном примере присутствует особенность – функция восстановления будет вызвана для всех свойств, которые будут обнаружены в JSON-документе. Это не всегда удобно и, кроме того, существенно снижает производительность чтения JSON-документа (за счет вызова функции восстановления). Например, при чтении метеорологических данных нам необходимо выполнять особое преобразование только для свойств, в
которых содержится дата и время, а остальные свойства мы конвертировать не собираемся. Чтобы не анализировать в функции восстановления имя реквизита (как в вышеприведенном примере), можно поступить другим способом: явным образом передать в функцию чтения JSON-документа список реквизитов, которые содержат дату и время, а функцию восстановления написать исходя из того, что эта функция будет вызвана только для необходимых свойств. В результате получится следующий код:

&НаСервере
Процедура ЧтениеНаСервере()
Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempweather.json");
Реквизиты = Новый Массив;
Реквизиты.Добавить("dt");
Реквизиты.Добавить("sunrise");
Реквизиты.Добавить("sunset");
Данные = ПрочитатьJSON(Чтение, Ложь, , , "ФункцияВосстановленияЧтения", ЭтотОбъект, , Реквизиты);
Чтение.Закрыть();
КонецПроцедуры
&НаСервере
Функция ФункцияВосстановленияЧтения(Свойство, Значение, ДополнительныеПараметры) Экспорт
Возврат ПрочитатьДатуJSON("new Date("+Формат(Значение, "ЧГ=")+")", ФорматДатыJSON.JavaScript);
КонецФункции

Следует обратить внимание, что функция восстановления должна быть объявлена с указанием ключевого слова Экспорт. Также следует помнить, что функция восстановления (в модуле управляемой формы) может быть описана только в «контекстной» части модуля, т. е. с использованием директивы компиляции &НаКлиенте или &НаСервере. При разработке функции восстановления необходимо принимать во внимание тот факт, что свойства документа считываются не в том порядке, как они представлены в файле.
Рассмотрим последовательность, в которой свойства JSON-документа попадают в функцию восстановления. Для этого разместим в таблице каждое свойство файла и то, в каком порядке будет прочитано свойство:

В общем случае, можно сформулировать следующее правило обхода: первым будет прочитано свойство, которому не подчинено ни одно другое свойство. Например, свойству id не подчинено никакое свойство, и оно считывается первым. Однако свойству coord подчинено свойства lon и lat, поэтому вначале будут считаны эти свойства, а лишь затем – свойство coord, которое в качестве значения получит структуру (или соответствие) из подчиненных свойств документа.

3. Работа с XDTO-объектами

3.1. Общая информация

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

3.2. Запись

Для того чтобы выполнить запись XDTO-объекта в формате JSON, необходимо использовать (в простейшем случае) следующие объекты:
1. Собственно записываемый объект, поддерживающий преобразование в/из XDTO, например, элемент справочника.
2. Сериализатор XDTO-объектов – СериализаторXDTO;
3. Объект, обеспечивающий низкоуровневую запись данных в формате JSON – ЗаписьJSON.
4. Объект настроек сериализации НастройкиСериализацииJSON.
Собственно сериализация выполняется с помощью метода ЗаписатьJSON() объекта СериализаторXDTO. Рассмотрим пример сериализации данных типа СправочникОбъект. В качестве примера используется справочник Валюты, который содержит поля Курс (типа Число) и ДатаКурса (типа Дата):

 Данные = Справочники.Валюты.НайтиПоКоду("978").ПолучитьОбъект();
 Запись = Новый ЗаписьJSON;
 Запись.ОткрытьФайл("c:tempsimpleXDTOWrite.json");
 СериализаторXDTO.ЗаписатьJSON(Запись, Данные);
 Запись.Закрыть();
 
 В результате работы данный пример сформирует следующий JSON-документ:

{ “#value”: { “Ref”: “5b65bd8e-ea70-11e4-af93-e03f49b16069”, “DeletionMark”: false, “Code”: “978”, “Description”: “Евро”, “Курс”: 54.659, “ДатаКурса”: “2015-04-25T00:00:00” } }

Сериализация значений типа Дата выполняется в формате ISO (определяется механизмом XDTO) и не управляется при записи данных. Также не поддерживается использование функции преобразования при операции сериализации, в отличие от потоковой (см. раздел 16.2.4) и объектной (см. раздел 16.2.2) техник.
Также следует помнить о следующей особенности: при записи объекта не формируется его тип, поэтому после JSON-сериализации XDTO-объекта отсутствует возможность выполнить десериализацию без указания типа считываемого объекта. Предыдущий пример сериализации элемента справочника Валюты будет невозможно десериализовать без явного указания типа значения. Чтобы упростить ситуацию, можно воспользоваться
параметром НазначениеТипаXML метода ЗаписатьJSON() объекта СериализаторXDTO. Если в качестве значения этого параметра указать НазначениеТипаXML.Явное, то появится возможность выполнить десериализацию без явного указания типа, а сформированный файл будет выглядеть следующим образом:

{ “#type”: “jcfg:CatalogObject.Валюты”, “#value”: { “Ref”: “5b65bd8e-ea70-11e4-af93-e03f49b16069”, “DeletionMark”: false, “Code”: “978”, “Description”: “Евро”, “Курс”: 54.659, “ДатаКурса”: “2015-04-25T00:00:00” } }

В данном примере особого внимания заслуживает элемент #type, который и описывает тип текущего элемента. Описание префиксов пространств имен см. приложение
Общие принципы JSON-сериализации объектов XDTO идентичны XML-сериализации:
● Структура данных соответствует структуре XML-документа.
● Имеются незначительные отличия, связанные с особенностями хранения типов и представлением массивов в JSON:
● Порядок и состав свойств определен в модели XDTO и не может быть изменен.
● Если тип записываемого значения однозначно определяется из типа, определенного в         соответствующем свойстве XDTO-модели, то записывается только значение без                    идентификации типа.
● Если тип записываемого значения неоднозначно определяется из типа, определенного       в соответствующем свойстве XDTO-модели (например, значение составного типа), то           значение будет записано в виде сложного объекта JSON с отдельными свойствами для         типа (свойство #type) и значения (свойство #value). В следующем примере записаны           эквивалентные варианты представления значения типа Строка. Первая запись                         используется при неоднозначном определении типа, вторая – при однозначном:

Первая запись
{
“#type”: “jxs:string”,
“#value”: “Строка с примером”
}
Вторая запись
“Строка с примером”
JSON-сериализация объектов XDTO имеет ряд особенностей (по сравнению с XML-сериализацией):

● Коллекции значений (например, значения типа Массив, Структура и т. д.) всегда записываются виде массива JSON.
● Тип значения реквизита записывается в специальное свойство JSON с именем #type.
● Пространство имен типов записывается в специальное свойство JSON с именем #ns:
● Для встроенных в платформу пространств имен типы записываются без использования свойства #ns, но с указанием префикса:
jxс:ChartOfCharacteristicTypesObject.ДемоПланВидовХарактеристик
jxs:string
jxs:decimal

Соответствие префиксов и пространств имен см.в приложении.
● Если встретится схема, которая не имеет префикса, то имя схемы явно записывается с        помощью свойства #ns:

{
"#ns": "http://mycompany.com/data/enterprise/myscheme",
"#type": "СпециальныйОбъект",
"#value": …
}
Значения Неопределено и NULL сериализуются особым образом:
1. Неопределено:
{
"#type": "jv8:Null",
"#value": ""
}
2. NULL:
{
"ИмяРеквизита": null
}

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

{
"#type": "jxs:anyType",
"#value": {
"Filters": {
"Filter": {
"Name": "Recorder",
"Value": {
"#type": "jxs:anySimpleType",
"#value": "acc2d259-c8f3-11e2-b5da-5404a6a68c42"
}
}
},
"Record": {
"Recorder": {
"#type": "jxs:anySimpleType",
"#value": "acc2d259-c8f3-11e2-b5da-5404a6a68c42"
},
"Period": {
"#type": "jxs:anySimpleType",
"#value": "2012-09-08T00:00:00"
},
"Active": {
"#type": "jxs:anySimpleType",
"#value": "true"
},
},
"Record": {
"Recorder": {
"#type": "jxs:anySimpleType",
"#value": "acc2d259-c8f3-11e2-b5da-5404a6a68c42"
},
"Period": {
"#type": "jxs:anySimpleType",
"#value": "2012-09-08T00:00:00"
},
"Active": {
"#type": "jxs:anySimpleType",
"#value": "true"
},
},
}
}
3.3. Чтение

В общем случае, чтение XDTO-объекта из JSON-документа аналогично записи. Чтение выполняется с помощью механизма чтения XDTO-объектов из XML-файла, поэтому чтение выполняется со следующими ограничениями:
● Возможно чтение только тех объектов, для которых существует XDTO-сериализация.
● Свойства в JSON-документе должны следовать в том же порядке, как и в XDTO-объекте.
● В случае если читаемый объект не соответствует схеме – будет вызвано исключение.
● Имеется возможность выполнять чтение произвольного JSON-документа в объект XDTO (ОбъектXDTO) с помощью фабрики XDTO (ФабрикаXDTO). Такое чтение возможно в том случае, если:
● фабрика XDTO, с помощью которой выполняется чтение, «знает» о типах, которые присутствуют в JSON-документе, из которого производится чтение.
● все элементы JSON указаны без явного указания типов и элементов, специфичных для JSON-документов, формируемых при сериализации объектов XDTO.
Выполнить чтение JSON-документа в том случае, если в нем используются типы, которые неизвестны фабрике XDTO, с помощью которой выполняется чтение документа – невозможно.
Рассмотрим пример чтения некоторого JSON-документа, например, полученного при работе примера работы со справочником Валюты из предыдущего раздела .

Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempsimpleXDTOWrite.json");
 Данные = СериализаторXDTO.ПрочитатьJSON(Чтение);
 Чтение.Закрыть();

В результате работы примера в переменно Данные будет помещен объект типа СправочникОбъект.Валюты для валюты с кодом 978. Однако данное поведение будет наблюдаться только в том случае, если при выполнении JSON-сериализация значение параметра НазначениеТипаXML было установлено в значение Явное. В противном случае при попытке чтения (как указано выше) будет вызвано исключение. При чтении объекта с
неявным указанием типа объекта, читаемый тип можно передать в виде параметра метода ПрочитатьJSON(). В этом случае пример будет выглядеть следующим образом:

Чтение = Новый ЧтениеJSON;
 Чтение.ОткрытьФайл("c:tempsimpleXDTOWrite.json");
 Данные = СериализаторXDTO.ПрочитатьJSON(Чтение, Тип("СправочникОбъект.Валюты"));
 Чтение.Закрыть();

При обмене данными между прикладными решениями с помощью объектов XDTO может возникать задача, когда требуется выполнить некоторую предобработку данных, которые поступают в пакете обмена. Например, заменить любое значение некоторого типа на фиксированное значение того же типа. Для упрощения такой предобработки предназначена функция восстановления. Имя функции восстановления передается в
функцию чтения из JSON-документа для сериализатора или фабрики XDTO. При чтении объекта функция восстановления будет вызываться при десериализации значений следующих типов:
● Булево;
● Число;
● Строка;
● Дата;
● УникальныйИдентификатор;
● ДвоичныеДанные;
● ХранилищеЗначения;
● Значения перечислений;
● Значения системных перечислений;
● Ссылки на объекты базы данных.
Для значений Неопределено функция восстановления не вызывается.
При разработке функции восстановления необходимо помнить, что в этой функции можно заменить значение, которое считано из JSON-документа, но нельзя изменить тип считываемого объекта. Функция восстановления также не будет вызываться для служебных свойств, которые создаются и используются системой «1С:Предприятие», например, #type, #ns и т. д.

4. Потоковая техника работы

4.1. Общая информация

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

4.2. Запись

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

Рассмотрим простой пример записи документа:

ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, " ", Истина);
Запись = Новый ЗаписьJSON;
Запись.ПроверятьСтруктуру = Истина;
Запись.ОткрытьФайл("c:tempstreamWrite.json", , , ПараметрыJSON);
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("ДлинаЗаписи");
Запись.ЗаписатьЗначение(20);
Запись.ЗаписатьИмяСвойства("Товар");
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("Код");
Запись.ЗаписатьЗначение("0020");
Запись.ЗаписатьИмяСвойства("Наименование");
Запись.ЗаписатьЗначение("Товар");
Запись.ЗаписатьКонецОбъекта();
Запись.ЗаписатьИмяСвойства("МассивЧисел");
Запись.ЗаписатьНачалоМассива();
Запись.ЗаписатьЗначение(3.141592654, Истина);
Запись.ЗаписатьЗначение(2.718281828, Ложь);
Запись.ЗаписатьКонецМассива();
Запись.ЗаписатьКонецОбъекта();
Запись.Закрыть();

В результате исполнения этого программного кода будет сформирован следующий документ:

{
"ДлинаЗаписи": 20,
"Товар": {
"Код": "0020",
"Наименование": "Товар"
},
"МассивЧисел": [
3.141592654E0,
2.718281828
]
}

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

{“ДлинаЗаписи”:20,”Товар”:{“Код”:”0020″,”Наименование”:”Товар”},”МассивЧисел”:[3.141592654E0,2.718281828]}
Если необходимо получить JSON-документ без формирования файла, то можно использовать метод УстановитьСтроку() объекта ЗаписьJSON.
После вызова этого метода, для получения строки со сформированным JSON-документом, достаточно просто завершить запись документа методом Закрыть() объекта ЗаписьJSON:

ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, ” “, Истина);
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку(ПараметрыJSON);

Документ = Запись.Закрыть();
Теперь данный документ (из переменной Документ) можно передавать, например, в тело HTTP-запроса.

4.3. Чтение

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

Чтение = Новый ЧтениеJSON;
Чтение.ОткрытьФайл("c:tempstreamWrite.json");
Пока Чтение.Прочитать() Цикл
Сообщить("Тип текущего элемента " + Чтение.ТипТекущегоЗначения);
Если Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.ИмяСвойства Тогда
Сообщить("Имя = " + Чтение.ТекущееЗначение);
КонецЕсли;
Если Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Булево Или
Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Строка Или
Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Число Или
Чтение.ТипТекущегоЗначения = ТипЗначенияJSON.Комментарий Тогда
Сообщить("Значение = " + Чтение.ТекущееЗначение);
КонецЕсли;
 КонецЦикла;
Чтение.Закрыть();

Тогда при чтении документа, сформированного при рассмотрении потоковой записи JSON-документа , будет сформирован следующий результат:

Тип текущего элемента Начало объекта
Тип текущего элемента Имя свойства
Имя = ДлинаЗаписи
Тип текущего элемента Число
Значение = 20
Тип текущего элемента Имя свойства
Имя = Товар
Тип текущего элемента Начало объекта
Тип текущего элемента Имя свойства
Имя = Код
Тип текущего элемента Строка
Значение = 0020
Тип текущего элемента Имя свойства
Имя = Наименование
Тип текущего элемента Строка
Значение = Товар
Тип текущего элемента Конец объекта
Тип текущего элемента Имя свойства
Имя = МассивЧисел
Тип текущего элемента Начало массива
Тип текущего элемента Число
Значение = 3,141592654
Тип текущего элемента Число
Значение = 2,718281828
Тип текущего элемента Конец массива
Тип текущего элемента Конец объекта5. Совмещение техник

Для упрощения работы с JSON, можно совмещать различные техники при формировании одного документа. Например, необходимо сформировать документ, который содержит в себе некоторый набор структур и массив. В этом случае можно все оформление документа
выполнять с помощью потоковой техники, а уже готовые структуры и массив записывать с помощью объектной техники. Важно только обеспечить корректную структуру документа перед началом объектной записи.
Приведем пример совмещения техник на следующем примере:
● В ответ на запрос внешней системы, этой системе необходимо возвращать список заказов.
● Список должен содержать дату формирования и набор заказов (соответствующий некоторому критерию).
● Каждый заказ описывается следующими параметрами:
1. Номер заказа;
2. Дата формирования заказа;
3. Контрагент по заказу;
4. Уникальный идентификатор заказа, по которому впоследствии можно получить всю информацию по заказу.
Фрагмент кода на встроенном языке, который формирует JSON-документ, будет иметь следующий вид:

НастройкиСериализации = Новый НастройкиСериализацииJSON;
НастройкиСериализации.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.УниверсальнаяДата;
НастройкиСериализации.ФорматСериализацииДат = ФорматДатыJSON.ISO;
НастройкиСериализации.СериализовыватьМассивыКакОбъекты = Истина;
ПараметрыJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, " ", Истина);
Запись = Новый ЗаписьJSON;
Запись.ПроверятьСтруктуру = Истина;
Запись.ОткрытьФайл("c:tempcombinedWrite.json", , , ПараметрыJSON);
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("ДатаФормирования");
Запись.ЗаписатьЗначение(ЗаписатьДатуJSON(КогдаСформировано, ФорматДатыJSON.ISO, ВариантЗаписиДатыJSON.УниверсальнаяДата));
Запись.ЗаписатьИмяСвойства("Заказы");
Заказы = Новый Массив;
Для каждого Заказ Из СписокЗаказов Цикл
ОписаниеЗаказа = Новый Структура("Ссылка, Номер, Дата, Контрагент");
ОписаниеЗаказа.Ссылка = Строка(Заказ.Ссылка);
ОписаниеЗаказа.Номер = Заказ.Номер;
ОписаниеЗаказа.Дата = Заказ.Дата;
ОписаниеЗаказа.Контрагент = Строка(Заказ.Контрагент);
Заказы.Добавить(ОписаниеЗаказа);
КонецЦикла;
ЗаписатьJSON(Запись, Заказы, НастройкиСериализации);
Запись.ЗаписатьКонецОбъекта();
Запись.Закрыть();

При исполнении данного кода предполагается, что:
● Переменная КогдаСформировано содержит значение типа Дата. Содержит дату и время формирования JSON-документа.
● Переменная СписокЗаказов является массивом ссылок на документы заказов.
Исполнение данного код приведет к формированию следующего JSON-документа:

{
"ДатаФормирования": "2014-10-06T12:57:35Z",
"Заказы": {
"0": {
"Ссылка": "f4d1495a-02b5-4d56-92c6-840c11dfb592",
"Номер": 234,
"Дата": "2014-09-30T20:00:00Z",
"Контрагент": "Иванов И.И."
},
"1": {
"Ссылка": "ee821799-2d57-475e-a330-f414e53b8bda",
"Номер": 436,
"Дата": "2014-09-24T20:00:00Z",
"Контрагент": "Петров А.П."
},
"2": {
"Ссылка": "e058a5a8-3c0d-453b-8b1c-963a35fe2b7a",
"Номер": 118,
"Дата": "2014-08-31T20:00:00Z",
"Контрагент": "Иванов И.И."
}
}
}

Изменяя значения параметров объектов НастройкиСериализации и ПараметрыJSON, а также манипулируя параметрами метода ЗаписатьДатуJSON(), можно изменять результирующий JSON-документ для максимального соответствия «ожиданиям» принимающей системы.

Приложение . Префиксы пространств имен при JSON-сериализации

Префиксы пространств имен


  • Ошибка при вызове метода контекста создать ошибка подключения внешних метаданных файл не обнаружен
  • Ошибка при вызове метода контекста прочитатьjson недопустимое состояние потока записи json
  • Ошибка при вызове метода контекста получитьссылку
  • Ошибка при вызове метода контекста создать нарушение прав доступа
  • Ошибка при вызове метода контекста прочитать формат файла не поддерживается