При интеграции 1С с внешними API (например, криптобиржами, картографическими сервисами или социальными сетями) разработчики часто сталкиваются с форматом JSON, структура которого не является статичной. Ошибки возникают на этапе попытки преобразовать «гибкий» JSON в «жесткую» модель данных XDTO. В этой статье мы подробно разберем, почему возникают ошибки валидации и как правильно организовать чтение сложных структур данных.
Рассмотрим ситуацию, когда в JSON-ответе ключи объектов являются данными, а не именами полей. Например, map0, map1, map2 и так далее. Проанализируем типичный пример кода, который вызывает ошибку:
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(пСтрока);
// Попытка прочитать через фабрику с указанием типа
ОбъектXDTO = ФабрикаXDTO.ПрочитатьJSON(ЧтениеJSON, ФабрикаXDTO.Тип("http://mapssssss.ru", "info"));
В данном случае платформа выдает ошибку: "Структура объекта не соответствует типу. map0 — это одновременно и имя элемента и значение". Выясним причину этого поведения. Механизм XDTO (XML Data Transfer Objects) основан на строгой схеме. Когда мы указываем конкретный тип ФабрикаXDTO.Тип(...), система ожидает, что в JSON будут только те свойства, которые описаны в пакете XDTO. Если в данных приходят ключи типа map0, которые не зафиксированы в схеме как свойства, XDTO не понимает, как их интерпретировать. В XDTO невозможно (без сложных манипуляций с anyType) описать объект, ключи которого заранее неизвестны.
Другой распространенный сценарий — передача координат или значений в виде массивов без ключей, например: "plus": [[104.67, 0.01], [104.75, 11]]. При попытке прочитать такой JSON через ФабрикаXDTO.ПрочитатьJSON() часто возникает критическая ошибка или исключение "Недопустимое значение аргумента функции".
Проанализируем ситуацию: в модели XDTO массив — это список элементов определенного типа. Однако анонимный вложенный массив [104.67, 0.01] не имеет имени тега (как это было бы в XML), и фабрика XDTO не может сопоставить его ни с одним свойством объекта, если структура не описана филигранно точно. Более того, на старых версиях платформы (например, 8.3.12) такие попытки приводили к аварийному завершению работы клиента.
Для работы с динамическими структурами наиболее эффективным и стабильным решением является использование глобальной функции ПрочитатьJSON(). В отличие от метода фабрики XDTO, эта функция не требует предварительного описания схемы и преобразует JSON в стандартные коллекции 1С: Структура, Соответствие или Массив.
Разберем по шагам правильный алгоритм чтения:
ЧтениеJSON.Посмотрим на пример реализации:
// Подготовим строку JSON
ОтветJSON = "{
""map0"":{
""plus"":[[104.67, 0.01], [104.75, 11]],
""minus"":[[104.3, 5.36], [104.21, 2.57]]
}
}";
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ОтветJSON);
// Правильный способ чтения динамических данных
Данные = ПрочитатьJSON(ЧтениеJSON);
// Теперь мы можем обращаться к данным как к обычным коллекциям 1С
Для Каждого КлючИЗначение Из Данные.map0.plus Цикл
// КлючИЗначение будет массивом с двумя элементами [104.67, 0.01]
КоординатаX = КлючИЗначение[0];
КоординатаY = КлючИЗначение[1];
КонецЦикла;
ЧтениеJSON.Закрыть();
Разберем подробнее, в чем техническое различие между этими двумя подходами, чтобы понимать, когда какой использовать:
1. Глобальная функция ПрочитатьJSON():
Структуру (по умолчанию) или Соответствие. Массивы JSON превращаются в Массив 1С."MyKey" и "mykey" — разные поля), следует читать JSON в Соответствие. Для этого в функцию передается второй параметр: ПрочитатьJSON(ЧтениеJSON, Истина).2. Метод ФабрикаXDTO.ПрочитатьJSON():
ОбъектXDTO.При работе с большими числами или специфическими форматами дат (например, ISO 8601), стандартная функция ПрочитатьJSON() позволяет использовать «функцию обработки данных». Это дает возможность вручную преобразовать строку в нужный тип данных 1С прямо в процессе парсинга.
Рассмотрим пример использования функции обработки:
Функция МояФункцияОбработки(Свойство, Значение, ДополнительныеПараметры, Отказ)
// Если поле называется "server_time", преобразуем его из Unix Timestamp в Дату 1С
Если Свойство = "server_time" Тогда
Возврат Дата(1970, 1, 1, 1, 1, 1) + Значение;
КонецЕсли;
Возврат Значение;
КонецФункции
// При чтении указываем имя функции обработки
Данные = ПрочитатьJSON(ЧтениеJSON, Ложь, , "МояФункцияОбработки");
Важный момент: Если вы столкнулись с ошибкой в платформе 8.3.12 или более ранних, настоятельно рекомендуем обновить платформу до актуальных версий (8.3.15+). В них работа парсера JSON была существенно оптимизирована, добавлены проверки на корректность аргументов, что предотвращает «вылеты» клиента при получении битых или неожиданных структур от сервера.
Таким образом, для интеграции с внешними веб-сервисами, отдающими динамические ключи (как в примерах с картами или биржами), всегда выбирайте глобальную функцию ПрочитатьJSON. Это обеспечит стабильность вашей конфигурации и упростит дальнейшую поддержку кода.