Как выгрузить табличную часть документа 1С в массив структур для передачи во внешнюю DLL или API?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Для решения этой задачи данные необходимо предварительно преобразовать в универсальные коллекции, которые легко транслируются в любые форматы данных. К таким коллекциям относятся Массивы (в JSON они превращаются в списки []) и Структуры (в JSON превращаются в объекты {}). В этой статье мы подробно разберем, как элегантно и быстро выгрузить табличную часть в массив структур, рассмотрим типичные ошибки новичков и предложим оптимальные варианты решения как с использованием БСП (Библиотеки стандартных подсистем), так и на чистом коде.

В чем заключается проблема и почему возникает ошибка перезаписи?

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


ЗапросПараметры = Новый Структура;
ЗапросПараметры.Вставить("П1", "Параметр1");

ТабЧасть = Новый Массив;
ТабЧасть.Добавить(1);
ТабЧасть.Добавить("Товар1");
ЗапросПараметры.Вставить("ТабЧасть", ТабЧасть); // Первая строка

ТабЧасть = Новый Массив;
ТабЧасть.Добавить(2);
ТабЧасть.Добавить("Товар2");
ЗапросПараметры.Вставить("ТабЧасть", ТабЧасть); // Ошибка: ключ "ТабЧасть" перезапишется!

Выясним причину этой ошибки. Объект Структура в 1С работает по принципу «ключ — значение», где каждый ключ должен быть уникальным. При повторном вызове метода Вставить() с тем же самым именем ключа (в нашем примере — "ТабЧасть") старое значение просто заменяется новым. В итоге в структуре останется только последняя добавленная строка.

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

Рассмотрим правильную схему компоновки данных:


[Главная Структура (Документ)]
   ├── ПараметрШапки1 (Значение)
   ├── ПараметрШапки2 (Значение)
   └── ТабличнаяЧасть (Массив)
          ├── [Структура Строки 1] -> (Товар, Количество, Цена)
          ├── [Структура Строки 2] -> (Товар, Количество, Цена)
          └── [Структура Строки 3] -> (Товар, Количество, Цена)

Такой формат является стандартным для передачи данных (например, в JSON) и легко «переваривается» любыми внешними библиотеками.

Решение 1. Ручное формирование массива структур

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

Допустим, у нас есть документ «Реализация товаров и услуг» с табличной частью «Товары». Нам необходимо выгрузить реквизиты шапки (Номер, Дата) и строки табличной части (Номенклатура, Количество, Цена).

Напишем следующий код:


// Шаг 1. Создаем корневую структуру документа
ДанныеЭкспорта = Новый Структура;
ДанныеЭкспорта.Вставить("Номер", ЭтотОбъект.Номер);
ДанныеЭкспорта.Вставить("Дата", ЭтотОбъект.Дата);

// Шаг 2. Создаем массив, который будет содержать строки табличной части
МассивСтрок = Новый Массив;

// Шаг 3. Обходим строки табличной части в цикле
Для Каждого СтрокаТЧ Из ЭтотОбъект.Товары Цикл
    
    // Для каждой строки создаем свою отдельную структуру
    СтруктураСтроки = Новый Структура;
    СтруктураСтроки.Вставить("Товар", Строка(СтрокаТЧ.Номенклатура)); // Ссылочные типы лучше сразу приводить к строке
    СтруктураСтроки.Вставить("Количество", СтрокаТЧ.Количество);
    СтруктураСтроки.Вставить("Цена", СтрокаТЧ.Цена);
    
    // Добавляем заполненную структуру строки в общий массив
    МассивСтрок.Добавить(СтруктураСтроки);
    
КонецЦикла;

// Шаг 4. Помещаем готовый массив строк в корневую структуру под уникальным ключом
ДанныеЭкспорта.Вставить("СтрокиДокумента", МассивСтрок);

// Теперь объект "ДанныеЭкспорта" готов к передаче во внешнюю DLL или для сериализации

Этот способ абсолютно надежен, прост для понимания и не зависит от наличия в конфигурации других подсистем. Однако, если в табличной части много колонок, писать для каждой из них метод Вставить() вручную становится довольно рутинной задачей.

Решение 2. Использование готовых функций БСП (самый элегантный способ)

Если ваша конфигурация разработана на базе БСП (Библиотека стандартных подсистем), что справедливо для большинства современных типовых конфигураций (УТ, ERP, КА, БП, УНФ), то изобретать велосипед не нужно. В составе БСП есть готовый оптимизированный общий модуль ОбщегоНазначения, содержащий нужные нам функции.

Для быстрой конвертации всей таблицы значений в массив структур используем метод ТаблицаЗначенийВМассив(). Проанализируем пример кода:


// Шаг 1. Выгружаем табличную часть в обычную Таблицу Значений
ТаблицаТоваров = ЭтотОбъект.Товары.Выгрузить();

// Шаг 2. Вызываем функцию БСП для мгновенной конвертации
МассивСтрок = ОбщегоНазначения.ТаблицаЗначенийВМассив(ТаблицаТоваров);

// Шаг 3. Упаковываем в общую структуру вместе с шапкой
ДанныеЭкспорта = Новый Структура;
ДанныеЭкспорта.Вставить("Номер", ЭтотОбъект.Номер);
ДанныеЭкспорта.Вставить("СтрокиДокумента", МассивСтрок);

Метод БСП автоматически берет имена колонок таблицы значений в качестве ключей для создаваемых структур, а значения строк — в качестве значений этих структур. Это исключает необходимость ручного обхода колонок и написания громоздкого кода.

Решение 3. Быстрый универсальный конвертер без БСП

Что делать, если конфигурация самописная, БСП в ней нет, а колонок в табличной части слишком много, чтобы перебирать их вручную? Напишем универсальную и высокопроизводительную функцию конвертации ТЧ в массив структур, использующую платформенный метод ЗаполнитьЗначенияСвойств().

Секрет высокой скорости этого метода заключается в том, что мы заранее подготавливаем список колонок в виде строки через запятую. Конструктор Новый Структура(СписокКолонок) инициализирует структуру мгновенно, а метод ЗаполнитьЗначенияСвойств() в один прием копирует все данные из строки таблицы в структуру.

Реализуем этот алгоритм:


Функция ТабличнаяЧастьВМассивСтруктур(ТабличнаяЧасть) Экспорт
    
    // Получаем таблицу значений для удобства работы с колонками
    ТЗ = ТабличнаяЧасть.Выгрузить();
    
    // Сформируем список колонок через запятую для конструктора структур
    СписокКолонок = "";
    Для Каждого Колонка Из ТЗ.Колонки Цикл
        СписокКолонок = СписокКолонок + ?(СписокКолонок = "", "", ",") + Колонка.Имя;
    КонецЦикла;
    
    РезультатМассив = Новый Массив;
    
    // Заполняем массив структур в один быстрый проход
    Для Каждого СтрокаТЗ Из ТЗ Цикл
        
        // Создаем структуру с готовыми ключами по шаблону колонок
        СтруктураСтроки = Новый Структура(СписокКолонок);
        
        // Быстро копируем данные из строки таблицы значений в структуру
        ЗаполнитьЗначенияСвойств(СтруктураСтроки, СтрокаТЗ);
        
        // Добавляем готовую строку в массив
        РезультатМассив.Добавить(СтруктураСтроки);
        
    КонецЦикла;
    
    Возврат РезультатМассив;
    
КонецФункции

Использовать эту функцию в коде очень просто:


ДанныеЭкспорта = Новый Структура;
ДанныеЭкспорта.Вставить("Номер", ЭтотОбъект.Номер);

// Быстро конвертируем табличную часть "Товары" любой сложности
ДанныеЭкспорта.Вставить("СтрокиДокумента", ТабличнаяЧастьВМассивСтруктур(ЭтотОбъект.Товары));

Решение 4. Альтернативный вариант: Структура структур

Иногда внешние библиотеки или старые API-интерфейсы не поддерживают массивы на корневом уровне табличных частей и требуют передачу данных в формате "ключ-значение", где ключом строки выступает её уникальный индекс. В таком случае вместо массива строк нам потребуется сформировать структуру структур.

Посмотрим на пример реализации такой задачи:


ТЗ = ЭтотОбъект.Товары.Выгрузить();

// Подготовим список колонок
СписокКолонок = "Номенклатура,Количество,Цена";

СтруктураСтрок = Новый Структура;
Индекс = 0;

Для Каждого СтрокаТЗ Из ТЗ Цикл
    
    СтруктураСтроки = Новый Структура(СписокКолонок);
    ЗаполнитьЗначенияСвойств(СтруктураСтроки, СтрокаТЗ);
    
    // Ключ структуры не может начинаться с цифры, поэтому добавляем буквенный префикс
    ИмяКлючаСтроки = "Строка_" + Формат(Индекс, "ЧГ=0");
    
    СтруктураСтрок.Вставить(ИмяКлючаСтроки, СтруктураСтроки);
    Индекс = Индекс + 1;
    
КонецЦикла;

// Теперь у нас есть структура, свойствами которой являются другие структуры

Важные рекомендации при подготовке данных для внешних систем

При передаче полученного массива структур во внешнюю библиотеку (DLL) или при записи в JSON помните о следующих правилах:

  1. Избегайте ссылочных типов. Ссылки 1С (например, СправочникСсылка.Номенклатура) не могут быть корректно интерпретированы внешними программами. Перед передачей всегда преобразуйте их в простые типы данных (строковое представление, уникальный идентификатор UUID или код/артикул). Вместо передачи самой ссылки используйте: Строка(СтрокаТЧ.Номенклатура) или СтрокаТЧ.Номенклатура.УникальныйИдентификатор().
  2. Контролируйте пустые даты. Пустая дата 1С (01.01.0001) при сериализации во внешние форматы может вызывать ошибки. Рекомендуется заменять ее на пустую строку или значение Неопределено, если внешняя система это поддерживает.
  3. Типы Чисел. Обращайте внимание на разделители дробной части. При выгрузке чисел платформа 1С передает их в стандартном формате, но если вы преобразуете числа в строки вручную, следите, чтобы разделителем была точка, а не запятая (в зависимости от требований принимающей DLL).

Мы подробно разобрали, как преобразовать табличную часть документа 1С в универсальный массив структур. Используйте наиболее подходящий вам метод: элегантный вызов функций БСП для типовых конфигураций или быстрый универсальный алгоритм на основе ЗаполнитьЗначенияСвойств() для кастомных решений.

← На главную