При работе с Системой компоновки данных (СКД) программисты часто сталкиваются с задачей не просто вывести отчет на экран для пользователя, но и произвести программную обработку этих данных. Типичный сценарий — выгрузка сформированного отчета во внешний файл, например, в формате XML. В данной статье мы детально разберем, почему перебор ячеек табличного документа является не самым эффективным методом, и рассмотрим правильные архитектурные подходы для решения этой задачи.
Когда мы выводим результат компоновки в ТабличныйДокумент, данные превращаются в визуальное представление. Тексты в ячейках могут быть отформатированы, числа — округлены или превращены в строки, а ссылки на объекты могут быть доступны только через расшифровку. Попытка перебора строк и колонок ТабличногоДокумента с помощью циклов (например, Для НомерСтроки = 1 По ТаблДок.ВысотаТаблицы) часто приводит к ошибкам, если структура отчета меняется или добавляются группировки. Поэтому мы рассмотрим более надежные способы получения «чистых» данных.
Самый удобный способ для последующей итерации и формирования XML — это вывод результата во внутреннюю коллекцию 1С. Рассмотрим, как изменить стандартный программный вывод СКД, чтобы получить ТаблицаЗначений.
Для этого нам понадобится использовать специальный тип генератора макета — ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений. Разберем пошагово программный код:
// 1. Получаем схему и настройки
СхемаСКД = Отчеты.НашОтчет.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = СхемаСКД.НастройкиПоУмолчанию;
// 2. Создаем компоновщик макета, указывая тип генерации для коллекции
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаСКД, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// 3. Инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
// 4. Используем ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ТаблицаРезультат = Новый ТаблицаЗначений;
ПроцессорВывода.УстановитьОбъект(ТаблицаРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
После выполнения этого кода в переменной ТаблицаРезультат окажутся все данные отчета. Теперь мы можем легко перебрать их в цикле для записи в XML:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\report.xml");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("ДанныеОтчета");
Для Каждого СтрокаДанных Из ТаблицаРезультат Цикл
ЗаписьXML.ЗаписатьНачалоЭлемента("Строка");
// Предположим, в отчете есть поля "Номенклатура" и "Количество"
ЗаписьXML.ЗаписатьАтрибут("Товар", Строка(СтрокаДанных.Номенклатура));
ЗаписьXML.ЗаписатьАтрибут("Кол", Строка(СтрокаДанных.Количество));
ЗаписьXML.ЗаписатьКонецЭлемента();
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();
Если отчет содержит огромный объем данных, выгрузка его сначала в ТаблицаЗначений может занять много оперативной памяти. В таких случаях проанализируем ситуацию и применим метод последовательного чтения данных напрямую из ПроцессорКомпоновкиДанных. Это позволит обрабатывать результат порционно, «на лету».
Выясним, как организовать такой цикл:
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
Пока Истина Цикл
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
Если ЭлементРезультата = Неопределено Тогда
Прервать;
КонецЕсли;
// Проверяем, что это элемент данных, а не заголовок или группировка
Если ЭлементРезультата.ЗначенияПараметров.Количество() > 0 Тогда
// Здесь мы получаем доступ к значениям полей через структуру ЗначенияПараметров
// Это максимально быстрый способ доступа к данным
Для Каждого Параметр Из ЭлементРезультата.ЗначенияПараметров Цикл
ИмяПоля = Параметр.Имя;
ЗначениеПоля = Параметр.Значение;
// Логика записи в XML
КонецЦикла;
КонецЕсли;
КонецЦикла;
Рассмотрим ситуацию, когда пользователь должен сначала увидеть отчет на форме в ТабличномДокументе, а затем по нажатию кнопки эти же данные должны выгрузиться в файл. Чтобы не выполнять тяжелый запрос к базе данных дважды, мы можем использовать один и тот же ПроцессорКомпоновкиДанных для двух разных процессоров вывода.
Разберем алгоритм совместной работы:
ПроцессорКомпоновкиДанных стандартным способом (с генерацией макета для обычного вывода).ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент и выводим результат в поле формы Результат. Это обеспечит визуализацию.Важный момент: Если в настройках СКД используются иерархические группировки, вместо ТаблицаЗначений лучше использовать ДеревоЗначений. Это позволит сохранить вложенность элементов в вашем XML-файле, превращая уровни дерева в соответствующие вложенные теги.
Проанализируем несколько нюансов, которые помогут избежать ошибок при реализации:
XDTOСериализатор.ЗаписатьXML(), если вам нужно сохранить сложные типы данных 1С.Поле1), поэтому старайтесь задавать понятные псевдонимы в настройках компоновки.ПроцессорКомпоновки.Инициализировать() может выдать пустой результат.Таким образом, мы выяснили, что для программной обработки результатов СКД наиболее эффективным и надежным методом является вывод данных в ТаблицуЗначений или ДеревоЗначений. Это освобождает нас от необходимости анализировать сложную структуру ячеек табличного документа и дает прямой доступ к типизированным данным для формирования качественных XML-выгрузок.