В практике разработки на платформе 1С:Предприятие мы часто сталкиваемся с необходимостью обработки данных, полученных из внешних источников — для этой задачи есть универсальный ETL-инструмент загрузки данных в 1С. Это может быть результат чтения JSON, ответ от HTTP-сервиса или результат работы какого-либо алгоритма, возвращающего данные в виде массива. Часто этот массив содержит структуры.
Работать с массивом структур не всегда удобно: его нельзя напрямую выгрузить в табличное поле на форме, к нему сложно применить методы НайтиСтроки или построитель запроса. Поэтому возникает задача: как быстро и универсально преобразовать массив в Таблицу Значений (ТЗ), особенно если количество колонок велико (например, 97, как в исходном вопросе), и мы не хотим прописывать каждую колонку вручную.
Давайте разберем эффективные алгоритмы решения этой задачи, проанализируем возможные ошибки и рассмотрим примеры кода.
У нас есть переменная (допустим, МассивДанных), которая является массивом. Каждый элемент этого массива — это структура, где Ключ — это имя будущей колонки, а Значение — данные ячейки. Нам нужно получить объект ТаблицаЗначений с аналогичным набором колонок и данными.
Самый надежный и понятный способ — это использование цикла. Однако, чтобы не создавать колонки вручную, мы можем пойти на хитрость: взять структуру первого элемента массива и на ее основании построить "каркас" нашей будущей таблицы.
Давайте разберем алгоритм по шагам:
Строка.Поле = Значение), используем мощный встроенный метод платформы ЗаполнитьЗначенияСвойств.Рассмотрим готовую функцию, которую можно использовать в своих модулях (на основе решения из обсуждения):
Функция МассивСтруктурВТаблицуЗначений(МассивСтруктур) Экспорт
// Если массив пуст, возвращаем пустую таблицу (или Неопределено, зависит от вашей логики)
Если МассивСтруктур.Количество() = 0 Тогда
Возврат Новый ТаблицаЗначений;
КонецЕсли;
// 1. Создаем структуру таблицы по первому элементу
// Предполагаем, что все структуры в массиве имеют одинаковый набор ключей
СтруктураПервойСтроки = МассивСтруктур[0];
ТЗ = Новый ТаблицаЗначений;
Для Каждого ЭлементСтруктуры Из СтруктураПервойСтроки Цикл
// Добавляем колонку. Тип пока не указываем (он будет Произвольный)
ТЗ.Колонки.Добавить(ЭлементСтруктуры.Ключ);
КонецЦикла;
// 2. Заполняем данными
Для Каждого ЭлементМассива Из МассивСтруктур Цикл
НоваяСтрока = ТЗ.Добавить();
// Магия платформы: автоматически сопоставляет ключи структуры и имена колонок ТЗ
ЗаполнитьЗначенияСвойств(НоваяСтрока, ЭлементМассива);
КонецЦикла;
Возврат ТЗ;
КонецФункции
Этот код решает проблему ручного добавления 97 колонок. Вы просто передаете массив, а функция сама определяет состав полей.
В процессе реализации могут возникнуть ошибки. Разберем одну из них, упомянутую в обсуждении.
Ошибка: «Итератор для значения не определен»
Такая ошибка возникает в строке Для Каждого ... Из ... Цикл, если переменная, по которой мы пытаемся итерироваться, не является коллекцией (например, это число, строка или Неопределено, а не Структура или Массив).
Если вы столкнулись с такой ошибкой при разборе массива, это может означать, что:
В коде выше мы полагаемся на то, что МассивСтруктур[0] — это именно Структура. Если данные разнородны, стоит добавить проверку ТипЗнч().
Существует еще один элегантный способ преобразования, который не требует написания циклов для заполнения строк. Платформа 1С умеет десериализовать JSON сразу в Таблицу Значений.
Если ваши данные — это массив структур, то с точки зрения JSON это идеальный массив объектов, который полностью совместим с форматом Таблицы Значений. Мы можем "обмануть" систему: записать массив в JSON-строку, а потом прочитать эту строку, явно указав, что хотим получить ТаблицаЗначений.
Посмотрим, как это выглядит:
Функция МассивВТаблицуЧерезJSON(МассивДанных) Экспорт
// 1. Сериализуем массив в строку JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МассивДанных);
СтрокаJSON = ЗаписьJSON.Закрыть();
// 2. Читаем JSON обратно, но указываем ожидаемый тип - ТаблицаЗначений
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
// Важно: ПрочитатьJSON умеет создавать ТЗ самостоятельно
Попытка
ТЗ = ПрочитатьJSON(ЧтениеJSON, Тип("ТаблицаЗначений"));
Исключение
// Если структура данных не соответствует плоской таблице, метод упадет
ТЗ = Новый ТаблицаЗначений;
КонецПопытки;
Возврат ТЗ;
КонецФункции
Этот метод часто работает быстрее циклов на больших объемах данных, так как выполняется на уровне платформы C++.
При использовании первого метода (через цикл) мы создаем колонки так: ТЗ.Колонки.Добавить(Имя). При этом тип колонки остается "Произвольным".
Это допустимо для простых задач, но может вызвать проблемы, если:
Как улучшить код?
При создании колонок можно пытаться определять тип на лету, анализируя значения из первой структуры:
// Внутри цикла создания колонок
Для Каждого ЭлементСтруктуры Из СтруктураПервойСтроки Цикл
// Создаем описание типов на основе типа значения в первой строке
ТипКолонки = Новый ОписаниеТипов(ТипЗнч(ЭлементСтруктуры.Значение));
ТЗ.Колонки.Добавить(ЭлементСтруктуры.Ключ, ТипКолонки);
КонецЦикла;
Однако помните про "Проблему первого элемента": если в первой строке в поле "Сумма" стоит 0 (число), а во второй строке Неопределено (Null), то типизированная колонка может не принять значение из второй строки, или наоборот. Поэтому подход с произвольным типом является наиболее безопасным, если вы не уверены в качестве входящих данных на 100%.
Для преобразования массива с большим количеством колонок в Таблицу Значений:
ЗаполнитьЗначенияСвойств для быстрого переноса данных из структуры в строку таблицы.ТаблицаЗначений существует только на сервере (или в толстом клиенте). На тонком клиенте данные придется обрабатывать иначе или передавать на сервер.