При работе с REST API JSON быстро перестаёт быть «небольшим ответом на пару полей». В реальных интеграциях приходится искать нужное значение внутри вложенных объектов и массивов, проверять подозрительный JSON, форматировать его для чтения и сразу понимать, как обратиться к найденному узлу из кода 1С.
JSON Workbench собирает эти операции в одной внешней обработке: исходный текст можно вставить или открыть из файла, разобрать в дерево, найти нужный узел, посмотреть его путь, тип и значение, получить отдельный JSON-фрагмент и пример кода 1С.
Основной рабочий экран: дерево JSON, выбранный массив, путь к узлу и автоматически сформированный код 1С.Что умеет обработка
- проверять синтаксис JSON до передачи текста штатному парсеру;
- строить дерево объектов и массивов;
- показывать для выбранного узла путь, тип, значение и число дочерних элементов;
- искать по именам ключей и скалярным значениям;
- форматировать JSON и минифицировать его;
- показывать и копировать JSON-фрагмент выбранного узла;
- генерировать пример обращения к узлу из кода 1С, а для массива — заготовку цикла;
- открывать
.jsonчерез штатную клиент-серверную передачу файла во временное хранилище; - разворачивать и сворачивать всё дерево или только уровень выбранного узла.
Строгая проверка перед штатным разбором
Основной разбор начинается не с построения дерева, а с отдельной синтаксической проверки. После неё текст передаётся обычному ЧтениеJSON. В результате дальнейшая логика работает уже с обычными значениями 1С — Соответствие, Массив, строками, числами, булевыми значениями и Null.
&НаСервере
Функция ПрочитатьJSONИзТекста(Знач Текст)
ПроверитьСтрогийJSON(Текст);
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(Текст);
Результат = ПрочитатьJSON(Чтение, Истина);
Чтение.Закрыть();
Возврат Результат;
КонецФункции
&НаСервере
Процедура ПроверитьСтрогийJSON(Знач Текст)
Позиция = 1;
ПропуститьПробелыJSON(Текст, Позиция);
Если Позиция > СтрДлина(Текст) Тогда
ВызватьИсключение "Пустая строка не является JSON.";
КонецЕсли;
РазобратьСтрогоеЗначениеJSON(Текст, Позиция, 0);
ПропуститьПробелыJSON(Текст, Позиция);
Если Позиция <= СтрДлина(Текст) Тогда
ВызватьИсключение
"После JSON-значения найден лишний символ в позиции "
+ Строка(Позиция) + ".";
КонецЕсли;
КонецПроцедуры
Проверяющая часть идёт по тексту позиционно. Для объекта она контролирует кавычки имени свойства, двоеточие, обязательную запятую между свойствами и отсутствие «висящей» запятой перед закрывающей скобкой. Для массива действует та же идея: после значения допустимы только запятая или ]. Строки, числа и литералы true/false/null разбираются отдельными процедурами.
Разделитель = Сред(Текст, Позиция, 1);
Если Разделитель = "}" Тогда
Позиция = Позиция + 1;
Возврат;
ИначеЕсли Разделитель = "," Тогда
Позиция = Позиция + 1;
ПропуститьПробелыJSON(Текст, Позиция);
Если Позиция > СтрДлина(Текст)
Или Сред(Текст, Позиция, 1) = "}" Тогда
ВызватьИсключение
"После запятой в объекте ожидалось следующее свойство.";
КонецЕсли;
Иначе
ВызватьИсключение
"Между свойствами JSON-объекта требуется запятая в позиции "
+ Строка(Позиция) + ".";
КонецЕсли;
Из JSON-значения строим дерево
После чтения JSON корневой объект превращается в дерево значений формы. Объект JSON приходит как Соответствие, массив — как Массив. Для каждого дочернего значения сразу рассчитываются путь и выражение доступа из кода 1С.
&НаСервере
Процедура ЗаполнитьДочерниеУзлы(Родитель, Значение,
ПутьРодителя, КодРодителя, Глубина)
Если ТипЗнч(Значение) = Тип("Соответствие") Тогда
Для Каждого Элемент Из Значение Цикл
ИмяКлюча = Строка(Элемент.Ключ);
НовыйПуть = ДобавитьКлючКПути(ПутьРодителя, ИмяКлюча);
НовыйКод = КодРодителя
+ ".Получить(" + СтрокаДляКода(ИмяКлюча) + ")";
СтрокаДерева = Родитель.ПолучитьЭлементы().Добавить();
ЗаполнитьСтрокуДерева(СтрокаДерева, ИмяКлюча,
Элемент.Значение, НовыйПуть, НовыйКод);
ЗаполнитьДочерниеУзлы(СтрокаДерева, Элемент.Значение,
НовыйПуть, НовыйКод, Глубина + 1);
КонецЦикла;
ИначеЕсли ТипЗнч(Значение) = Тип("Массив") Тогда
Для Индекс = 0 По Значение.Количество() - 1 Цикл
НовыйПуть = ПутьРодителя + "[" + Строка(Индекс) + "]";
НовыйКод = КодРодителя + "[" + Строка(Индекс) + "]";
// Добавление строки дерева выполняется так же.
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Например, для суммы первого заказа путь будет orders[0].sum. Если имя свойства неудобно для точечной записи — содержит пробел, квадратную скобку или начинается с цифры — путь строится в скобочной форме с ключом в кавычках.
Карточка выбранного узла
При построении дерева в строке сохраняются не только отображаемые имя и тип, но и готовый Pretty JSON выбранного значения и пример кода. Поэтому переключение между вкладками «Значение», «JSON-фрагмент» и «Код 1С» не требует повторно разбирать исходный текст.
СтрокаДерева.ИмяУзла = Имя;
СтрокаДерева.ТипУзла = ИмяТипаJSON(Значение);
СтрокаДерева.ЗначениеУзла = ПредставлениеJSONЗначения(Значение);
СтрокаДерева.ПутьУзла = Путь;
СтрокаДерева.КодУзла = Код;
СтрокаДерева.JSONФрагмент = ЗаписатьJSONВТекст(Значение, Истина);
СтрокаДерева.КодПримера = СформироватьПримерКода1С(Значение, Код);
Генерация обращения из кода 1С
Для обычного узла обработка формирует выражение доступа через Получить() и индексы массивов. Для выбранного массива генерируется уже не одно выражение, а каркас цикла. Если первый элемент массива — объект, в цикл добавляются обращения к его свойствам.
Данные = ПрочитатьJSON(ЧтениеJSON, Истина);
МассивДанных = Данные.Получить("orders");
Для Каждого ЭлементМассива Из МассивДанных Цикл
Значение1 = ЭлементМассива.Получить("items"); // items
Значение2 = ЭлементМассива.Получить("sum"); // sum
Значение3 = ЭлементМассива.Получить("date"); // date
Значение4 = ЭлементМассива.Получить("number"); // number
КонецЦикла;
Это именно заготовка: имена переменных программист подбирает под свою задачу. Ценность генератора в том, что путь уже найден по реальной структуре JSON, включая индексы массивов и произвольные имена ключей.
Открытие JSON-файла в клиент-серверном варианте
Локальный путь пользователя на сервер не передаётся. На клиенте файл помещается на сервер асинхронно, после чего сервер получает только адрес временного хранилища. Далее двоичные данные читаются как UTF-8, при необходимости снимается BOM, и полученный текст передаётся тому же разбору, что используется для вставленного JSON.
&НаКлиенте
Асинх Процедура ОткрытьJSONОбработка(Команда)
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов(
"Выберите JSON-файл", Ложь,
"JSON (*.json)|*.json|Все файлы (*.*)|*.*", 0);
ОписаниеФайла = Ждать ПоместитьФайлНаСерверАсинх(
,,, ПараметрыДиалога, ЭтаФорма.УникальныйИдентификатор);
Если ОписаниеФайла = Неопределено Тогда
Возврат;
КонецЕсли;
ЗагрузитьJSONИзВременногоХранилища(ОписаниеФайла.Адрес);
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьJSONИзВременногоХранилища(АдресФайла)
ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресФайла);
УдалитьИзВременногоХранилища(АдресФайла);
ТекстФайла = ПолучитьСтрокуИзДвоичныхДанных(
ДвоичныеДанныеФайла, КодировкаТекста.UTF8);
Если Не ПустаяСтрока(ТекстФайла)
И Лев(ТекстФайла, 1) = Символ(65279) Тогда
ТекстФайла = Сред(ТекстФайла, 2);
КонецЕсли;
ТекстJSON = ТекстФайла;
РазобратьНаСервере();
КонецПроцедуры
Pretty Print и Minify штатной записью JSON
Для форматирования не нужен собственный сериализатор. После строгой проверки и чтения значения используется ЗаписьJSON. Разница между Pretty Print и Minify — в параметрах записи.
Функция ЗаписатьJSONВТекст(Знач Значение, Знач Красиво)
Запись = Новый ЗаписьJSON;
Если Красиво Тогда
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(
ПереносСтрокJSON.Авто, Символы.Таб, Истина);
Иначе
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(
ПереносСтрокJSON.Нет);
КонецЕсли;
Запись.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(Запись, Значение);
Возврат Запись.Закрыть();
КонецФункции
JSON после форматирования: Pretty Print выполняется штатной записью JSON платформы.Поиск по ключам и значениям
Поиск выполняется по уже построенному дереву, поэтому исходный JSON повторно не парсится. В индекс поиска попадают имя узла и его текстовое представление. В результат записываются путь, тип и значение — этого достаточно, чтобы быстро найти нужное поле даже в большом ответе.
&НаСервере
Процедура НайтиВДереве(Строки, Знач Искомое)
Для Каждого СтрокаДерева Из Строки Цикл
ТекстПроверки = ВРег(
СтрокаДерева.ИмяУзла + " " + СтрокаДерева.ЗначениеУзла);
Если СтрНайти(ТекстПроверки, Искомое) > 0 Тогда
НоваяСтрока = РезультатыПоиска.Добавить();
НоваяСтрока.Путь = СтрокаДерева.ПутьУзла;
НоваяСтрока.Тип = СтрокаДерева.ТипУзла;
НоваяСтрока.Значение = СтрокаДерева.ЗначениеУзла;
КонецЕсли;
НайтиВДереве(СтрокаДерева.ПолучитьЭлементы(), Искомое);
КонецЦикла;
КонецПроцедуры
Поиск по ключам и значениям возвращает путь, тип и представление найденного узла.Рабочий сценарий
Типичный сценарий занимает несколько действий: вставить JSON или открыть файл, нажать «Разобрать», найти интересующий участок в дереве или через поиск и выбрать узел. Дальше можно скопировать его путь, JSON-фрагмент или пример кода 1С. Для больших структур дерево можно раскрывать целиком либо работать только с уровнем текущего узла.
Такой подход особенно удобен при разборе ответов внешних API: сначала видно фактическую структуру данных, а затем нужный путь сразу превращается в понятное обращение из 1С.
Состав поставки
В поставку входит готовая внешняя обработка JSONWorkbench.epf с открытым кодом. Для работы обработки не требуются внешние сервисы или дополнительные компоненты.
Проверено на следующих конфигурациях и релизах:
- Управление нашей фирмой, редакция 3.0, релизы 3.0.14.143
Вступайте в нашу телеграмм-группу Инфостарт