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