Как программно обработать результат отчета СКД и выгрузить данные в XML

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

При работе с Системой компоновки данных (СКД) программисты часто сталкиваются с задачей не просто вывести отчет на экран для пользователя, но и произвести программную обработку этих данных. Типичный сценарий — выгрузка сформированного отчета во внешний файл, например, в формате XML. В данной статье мы детально разберем, почему перебор ячеек табличного документа является не самым эффективным методом, и рассмотрим правильные архитектурные подходы для решения этой задачи.

Проблема использования табличного документа для обработки данных

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

Решение №1: Вывод результата СКД в таблицу или дерево значений

Самый удобный способ для последующей итерации и формирования XML — это вывод результата во внутреннюю коллекцию 1С. Рассмотрим, как изменить стандартный программный вывод СКД, чтобы получить ТаблицаЗначений.

Для этого нам понадобится использовать специальный тип генератора макета — ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений. Разберем пошагово программный код:


// 1. Получаем схему и настройки
СхемаСКД = Отчеты.НашОтчет.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = СхемаСКД.НастройкиПоУмолчанию;

// 2. Создаем компоновщик макета, указывая тип генерации для коллекции
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаСКД, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

// 3. Инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

// 4. Используем ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ТаблицаРезультат = Новый ТаблицаЗначений;
ПроцессорВывода.УстановитьОбъект(ТаблицаРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

После выполнения этого кода в переменной ТаблицаРезультат окажутся все данные отчета. Теперь мы можем легко перебрать их в цикле для записи в XML:


ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\report.xml");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("ДанныеОтчета");

Для Каждого СтрокаДанных Из ТаблицаРезультат Цикл
    ЗаписьXML.ЗаписатьНачалоЭлемента("Строка");
    // Предположим, в отчете есть поля "Номенклатура" и "Количество"
    ЗаписьXML.ЗаписатьАтрибут("Товар", Строка(СтрокаДанных.Номенклатура));
    ЗаписьXML.ЗаписатьАтрибут("Кол", Строка(СтрокаДанных.Количество));
    ЗаписьXML.ЗаписатьКонецЭлемента();
КонецЦикла;

ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();

Решение №2: Использование прямого обхода процессора компоновки

Если отчет содержит огромный объем данных, выгрузка его сначала в ТаблицаЗначений может занять много оперативной памяти. В таких случаях проанализируем ситуацию и применим метод последовательного чтения данных напрямую из ПроцессорКомпоновкиДанных. Это позволит обрабатывать результат порционно, «на лету».

Выясним, как организовать такой цикл:


ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

Пока Истина Цикл
    ЭлементРезультата = ПроцессорКомпоновки.Следующий();
    Если ЭлементРезультата = Неопределено Тогда
        Прервать;
    КонецЕсли;

    // Проверяем, что это элемент данных, а не заголовок или группировка
    Если ЭлементРезультата.ЗначенияПараметров.Количество() > 0 Тогда
        // Здесь мы получаем доступ к значениям полей через структуру ЗначенияПараметров
        // Это максимально быстрый способ доступа к данным
        Для Каждого Параметр Из ЭлементРезультата.ЗначенияПараметров Цикл
            ИмяПоля = Параметр.Имя;
            ЗначениеПоля = Параметр.Значение;
            // Логика записи в XML
        КонецЦикла;
    КонецЕсли;
КонецЦикла;

Комбинированный подход: и вывод на экран, и обработка

Рассмотрим ситуацию, когда пользователь должен сначала увидеть отчет на форме в ТабличномДокументе, а затем по нажатию кнопки эти же данные должны выгрузиться в файл. Чтобы не выполнять тяжелый запрос к базе данных дважды, мы можем использовать один и тот же ПроцессорКомпоновкиДанных для двух разных процессоров вывода.

Разберем алгоритм совместной работы:

  1. Сначала мы подготавливаем ПроцессорКомпоновкиДанных стандартным способом (с генерацией макета для обычного вывода).
  2. Инициализируем ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент и выводим результат в поле формы Результат. Это обеспечит визуализацию.
  3. Для получения данных для XML мы можем либо повторно инициализировать процессор с типом генерации «Для коллекции значений», либо (что более правильно) использовать расшифровку строк в табличном документе.

Важный момент: Если в настройках СКД используются иерархические группировки, вместо ТаблицаЗначений лучше использовать ДеревоЗначений. Это позволит сохранить вложенность элементов в вашем XML-файле, превращая уровни дерева в соответствующие вложенные теги.

Практические советы по работе с XML и СКД

Проанализируем несколько нюансов, которые помогут избежать ошибок при реализации:

  1. Типизация данных: В XML важно передавать данные в строковом виде, но при этом соблюдать формат. Используйте функцию XDTOСериализатор.ЗаписатьXML(), если вам нужно сохранить сложные типы данных 1С.
  2. Имена полей: Помните, что в коллекции значений (таблице) колонки будут называться так, как заданы Пути к данным в схеме СКД. Если вы используете пользовательские поля, их имена могут генерироваться платформой автоматически (например, Поле1), поэтому старайтесь задавать понятные псевдонимы в настройках компоновки.
  3. Параметры данных: Перед вызовом компоновщика макета обязательно проверяйте заполнение параметров (НачалоПериода, КонецПериода и т.д.), как это было показано в исходном коде автора темы. Без установленных параметров ПроцессорКомпоновки.Инициализировать() может выдать пустой результат.

Таким образом, мы выяснили, что для программной обработки результатов СКД наиболее эффективным и надежным методом является вывод данных в ТаблицуЗначений или ДеревоЗначений. Это освобождает нас от необходимости анализировать сложную структуру ячеек табличного документа и дает прямой доступ к типизированным данным для формирования качественных XML-выгрузок.

← На главную