- Всё о программировании на 1С:Предприятие - http://life1c.ru -

Использование COM-соединения, выгрузка в Excel через COM-объект Excel.Application

Для более глубокого изучения 1С скачайте книгу "Программирование в 1С за 9 шагов" [1]

Вообще COM-объекты используют для соединения информационной базы 1С с файлом Word, Excel, Outlook или любой другой программой, поддерживающей данный интерфейс обмена данными. В этой статье рассмотрим задачу выгрузки/загрузки данных из/в MS Excel. Чтобы это осуществить воспользуемся COM-соединением и объектом Excel.Application. Для примера возьмём задачу выгрузки/загрузки данных о номенклатуре. Пример рассмотрим ниже.

 

COM-соединение

Что же такое COM-соединение? Component Object Model (или COM) – это технология (фирмы Microsoft) взаимодействующих компонентов, которые одновременно могут быть использованы в разных приложениях. При этом весь функционал соответствующего компонента наследуется внутрь разрабатываемого приложения. В нашем случае COM-объект Excel.Application используется внутри кода 1С для операций с файлом книги MS Excel.

 

Объект Excel.Application

У объекта Excel.Application существует ряд методов, которые нам могут пригодиться для реализации нижепоставленной задачи:

 

Постановка задачи

Итак, предположим, что в обработке 1С у нас имеется табличная часть, состоящая из следующих колонок:

Необходимо реализовать 2 функционала (сделать на форме 2 основные кнопки):

  1. Выгрузка табличной части в подготовленный файл MS Excel
  2. Загрузка табличной части из файла.


 

Алгоритм выгрузки/загрузки в MS Excel

Алгоритм выгрузки следующий:

  1. Выгружаем табличную часть в таблицу значений
  2. Создаём новый COM-объект Excel.Application
  3. Выбираем файл, открываем файл книги MS Excel
  4. Переходим на заданный лист книги
  5. Выгружаем данные в файл
  6. Закрываем книгу, выходим из COM-объекта.

Алгоритм загрузки следующий:

  1. Создаём новый COM-объект Excel.Application
  2. Выбираем файл, открываем файл книги MS Excel
  3. Переходим на заданный лист книги
  4. Загружаем данные из файла в таблицу значений
  5. Закрываем книгу, выходим из COM-объекта
  6. Таблицу значений выгружаем в табличную часть.

Операция выгрузки и загрузки данных о номенклатуре происходит в заранее подготовленный шаблон MS Excel.


 

Пример кода 1С

Код 1С я постарался разделить на отдельные функции, чтобы, скопировав, с ними можно было работать где угодно. На форме обработки 1С были созданы 3 кнопки:


В итоге в реализации алгоритма получились следующие основные процедуры и функции 1С:

Для начала приведу вспомогательную функцию для открытия/сохранения файла на диске:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#Если Клиент Тогда
// Функция выбора файла.
//
// Параметры:
// 	РежимВыбора - <РежимДиалогаВыбораФайла> - Выбор каталога, открытие или сохранение файла;
//	Расширение - <Строка>, <Массив> - Список расширений файла.
//
// Возвращаемое значение:
//	<Строка> - Путь к выбранному файлу.
//
Функция ВыбратьФайлДокумента(РежимВыбора, Расширение = "*") Экспорт
 
	ИмяФайла = "";
	//ФорматМассив = РазобратьСтрокуВМассивПоРазделителю(Расширение);
	ФорматМассив = ПреобразоватьВМассив(Расширение);
 
	ДиалогФайла = Новый ДиалогВыбораФайла(РежимВыбора);
	Если РежимВыбора = РежимДиалогаВыбораФайла.Открытие Тогда
		ДиалогФайла.Заголовок = "Открыть документ";
	ИначеЕсли РежимВыбора = РежимДиалогаВыбораФайла.Сохранение Тогда
		ДиалогФайла.Заголовок = "Сохранить документ";
	ИначеЕсли РежимВыбора = РежимДиалогаВыбораФайла.ВыборКаталога Тогда
		ДиалогФайла.Заголовок = "Выбрать каталог";
	КонецЕсли;
 
	Фильтр = "";
	Для Каждого ЭлементМассив Из ФорматМассив Цикл
		Если ЭлементМассив = "*" Тогда
			Фильтр = Фильтр + "|" + НСтр("ru = ""Все файлы""; en = ""All files""");
		ИначеЕсли ВРег(ЭлементМассив) = ВРег("TXT") Тогда
			Фильтр = Фильтр + "|" + НСтр("ru = ""Текстовый документ""; en = ""Text document""");
		ИначеЕсли ВРег(ЭлементМассив) = ВРег("MXL") Тогда
			Фильтр = Фильтр + "|" + НСтр("ru = ""Табличный документ""; en = ""Table document""");
		ИначеЕсли ВРег(ЭлементМассив) = ВРег("XLS") ИЛИ ВРег(ЭлементМассив) = ВРег("XLSX") ИЛИ ВРег(ЭлементМассив) = ВРег("XLSM") Тогда
			Фильтр = Фильтр + "|" + НСтр("ru = ""Табличный документ MS Excel""; en = ""Table document MS Excel""");
		ИначеЕсли ВРег(ЭлементМассив) = ВРег("XML") Тогда
			Фильтр = Фильтр + "|" + НСтр("ru = ""Документ XML""; en = ""Document XML""");
		ИначеЕсли ВРег(ЭлементМассив) = ВРег("HTML") ИЛИ ВРег(ЭлементМассив) = ВРег("HTM") Тогда
			Фильтр = Фильтр + "|" + НСтр("ru = ""HTML документ""; en = ""HTML document""");
		Иначе
			Фильтр = Фильтр + "|" + НСтр("ru = ""Файл " + ВРег(ЭлементМассив) + """; en = ""File " + ВРег(ЭлементМассив) + """");
		КонецЕсли;
		Фильтр = Фильтр + " (*." + НРег(ЭлементМассив) + ")|*." + НРег(ЭлементМассив);
	КонецЦикла;
	Фильтр = Сред(Фильтр, 2);
 
	ДиалогФайла.Фильтр = Фильтр;
	ДиалогФайла.МножественныйВыбор = Ложь;
 
	Если ДиалогФайла.Выбрать() Тогда
		ИмяФайла = ?(РежимВыбора = РежимДиалогаВыбораФайла.ВыборКаталога, ДиалогФайла.Каталог, ДиалогФайла.ПолноеИмяФайла);
	Иначе
		Текст = "ru = ""Файл не выбран!""; en = ""File(s) not selected!""";
		Предупреждение(НСтр(Текст));
	КонецЕсли;
 
	Возврат ИмяФайла;
КонецФункции	
#КонецЕсли

Также в реализации алгоритма были задействованы следующие вспомогательные функции:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Преобразует в массив переменную любого типа данных.
//
// Параметры:
//	Объект - Произвольный - произвольный объект данных;
//	Проверка - <Булево> - Осуществление проверки на заполненное значение.
//
// Возвращаемое значение:
//	<Массив> - Массив с теми же данными.
//
Функция ПреобразоватьВМассив(Объект, Проверка = Ложь) Экспорт
 
	ОбъектМассив = Новый Массив;
 
	Если НЕ Проверка ИЛИ ЗначениеЗаполнено(Объект) Тогда
		Если ТипЗнч(Объект) = Тип("Массив") Тогда
			ОбъектМассив = Объект;
		ИначеЕсли ТипЗнч(Объект) = Тип("СписокЗначений") Тогда
			ОбъектМассив = Объект.ВыгрузитьЗначения();
		ИначеЕсли ТипЗнч(Объект) = Тип("Строка") Тогда
			ОбъектМассив = РазобратьСтрокуВМассивПоРазделителю(Объект);
		ИначеЕсли ТипЗнч(Объект) = Тип("Структура") Тогда
			Для Каждого Элемент Из Объект Цикл
				ОбъектМассив.Добавить(Элемент.Значение);
			КонецЦикла;
		Иначе
			ОбъектМассив.Добавить(Объект);
		КонецЕсли;
	КонецЕсли;
 
	Возврат ОбъектМассив;
КонецФункции;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Разбирает строку в массив подстрок по разделителю. 
// При этом пробелы между подстроками не учитываются.
//
// Параметры:
//	Стр - исходная строка;
//	СтрРазделитель - разделитель, по умолчанию ",";
//	ИгнорироватьПустые - игнорировать ли пустые места между разделителями.
//
// Возвращаемое значение:
//	Массив строк
//
Функция РазобратьСтрокуВМассивПоРазделителю(Знач Стр, СтрРазделитель = ",", ИгнорироватьПустые = Ложь) Экспорт
 
	Результат = Новый Массив;
 
	ВхождениеРазделителя = Найти(Стр, СтрРазделитель);
	Пока ВхождениеРазделителя <> 0 Цикл
		ЧастьДоРазделителя = СокрЛП(Лев(Стр, ВхождениеРазделителя - 1));
		Если НЕ (ИгнорироватьПустые И ПустаяСтрока(ЧастьДоРазделителя)) Тогда
			Результат.Добавить(ЧастьДоРазделителя);
		КонецЕсли;
		Стр = СокрЛП(Сред(Стр, ВхождениеРазделителя + 1));
		ВхождениеРазделителя = Найти(Стр, СтрРазделитель);
	КонецЦикла;
 
	Если НЕ (ИгнорироватьПустые И ПустаяСтрока(Стр)) Тогда
		Результат.Добавить(СокрЛП(Стр));
	КонецЕсли;
 
	Возврат Результат;	
КонецФункции;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Создаёт новую таблицу значений с заданными колонками.
//
// Параметры:
//	пКолонки - <Строка>, <Структура>, <Массив>, <СписокЗначений>, <ТаблицаЗначений> - 
//	 Набор колонок для таблицы значений.
//	
// Возвращаемое значение:
//	<ТаблицаЗначений> - Созданная таблица.
//
Функция ПолучитьТаблицуВывода(пКолонки) Экспорт
 
	ТЗ = Новый ТаблицаЗначений;
 
	Если пКолонки <> Неопределено Тогда 
 
		Если ТипЗнч(пКолонки) = Тип("Строка") Тогда
			пКолонки = РазобратьСтрокуВМассивПоРазделителю(пКолонки);
		КонецЕсли;
 
		Если ТипЗнч(пКолонки) = Тип("Структура") Тогда
			Для Каждого Поле Из пКолонки Цикл	
				СтрокаТабл = ТЗ.Колонки.Добавить(Поле.Ключ, Поле.Значение);	
			КонецЦикла;
		ИначеЕсли ТипЗнч(пКолонки) = Тип("СписокЗначений") Тогда
			Для Каждого Поле Из пКолонки Цикл	
				Если Поле.Пометка Тогда
					СтрокаТабл = ТЗ.Колонки.Добавить(Поле.Значение, пКолонки.ТипЗначения, Поле.Представление);
				КонецЕсли;
			КонецЦикла;
		ИначеЕсли ТипЗнч(пКолонки) = Тип("ТаблицаЗначений") Тогда
			ЕстьНаименование = (пКолонки.Колонки.Найти("Наименование") <> Неопределено);
			ЕстьТипЗначения = (пКолонки.Колонки.Найти("ТипЗначения") <> Неопределено);
			ЕстьЗаголовок = (пКолонки.Колонки.Найти("Заголовок") <> Неопределено);
			ЕстьШирина = (пКолонки.Колонки.Найти("Ширина") <> Неопределено);
			Для Каждого Поле Из пКолонки Цикл
				СтрокаТабл = ТЗ.Колонки.Добавить(?(ЕстьНаименование, Поле.Наименование, ""), ?(ЕстьТипЗначения, Поле.ТипЗначения, Новый ОписаниеТипов), ?(ЕстьЗаголовок, Поле.Заголовок, ""), ?(ЕстьШирина, Поле.Ширина, 0));	
			КонецЦикла;
		Иначе
			Для Каждого Поле Из пКолонки Цикл	
				СтрокаТабл = ТЗ.Колонки.Добавить(Поле);	
			КонецЦикла;
		КонецЕсли;
 
	КонецЕсли;
 
	Возврат ТЗ;	
КонецФункции;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Создаёт структуру колонок из таблицы значений.
//
// Параметры:
//	ТабЗначений - <ТаблицаЗначений> - Любая таблица.
//	
// Возвращаемое значение:
//	<Структура> - Созданная таблица.
//
Функция ПолучитьСтруктуруКолонокИзТаблицы(ТабЗначений) Экспорт
 
	СтруктураКолонок = Новый Структура;
	Для Каждого ЭлементКолонка Из ТабЗначений.Колонки Цикл
		СтруктураКолонок.Вставить(ЭлементКолонка.Имя, ЭлементКолонка.ТипЗначения);
	КонецЦикла;
 
	Возврат СтруктураКолонок;
КонецФункции;

Основные функции обработки алгоритма следующие:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Получает объект файла MS Excel.
//
// Параметры:
//	ИмяФайла - <Строка> - Путь к файлу XLS.
//	
// Возвращаемое значение:
//	<COMОбъект> - Полученный объект. Если объект не найден, то возвращается "Неопределено".
//
Функция ПолучитьExcel(ИмяФайла) Экспорт
 
	ФайлНаДиске = Новый Файл(ИмяФайла);
 
	Excel = Неопределено;
	Если нРег(ФайлНаДиске.Расширение) = ".xls" 
	 ИЛИ нРег(ФайлНаДиске.Расширение) = ".xlsx"
	 ИЛИ нРег(ФайлНаДиске.Расширение) = ".xlsm"
	Тогда
 
		Если НЕ ФайлНаДиске.Существует() Тогда
			Сообщить("Файл не существует!", СтатусСообщения.Внимание);
			Возврат Неопределено;
		КонецЕсли;
 
		Попытка
			Excel = Новый COMОбъект("Excel.Application");
			Excel.WorkBooks.Open(ИмяФайла);
		Исключение
			Сообщить("Не удалось инициализировать Excel!", СтатусСообщения.Внимание);
			Возврат Неопределено;
		КонецПопытки;
 
	КонецЕсли;	
 
	Возврат Excel;
КонецФункции;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Закрывает файл MS Excel.
//
// Параметры:
//	Excel - <COMОбъект> - Объект файла MS Excel;
//	Сохранить - <Булево> - Указывает сохранять файл при закрытии или нет. По умолчанию
//	 пользователю предлагается выбрать это самому.
//
Процедура ЗакрытьExcel(Excel, Сохранить = Неопределено) Экспорт
 
	Попытка
		#Если Клиент Тогда
		Состояние("Закрытие файла Microsoft Excel...");
		#КонецЕсли
		Если Сохранить = Неопределено Тогда
			Excel.ActiveWorkbook.Close();
		Иначе
			Excel.ActiveWorkbook.Close(Сохранить);
		КонецЕсли;
		Excel.Quit();
	Исключение
		Сообщить("Ошибка закрытия Excel!", СтатусСообщения.Внимание);
	КонецПопытки;
 
	Excel = Неопределено;	
КонецПроцедуры;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Получает лист из файла книги MS Excel.
//
// Параметры:
//	Excel - <COMОбъект> - Объект файла MS Excel;
//	ИмяЛиста - <Строка> - Имя листа книги MS Excel.
//	
// Возвращаемое значение:
//	<COMОбъект> - Полученный лист. Если объект не найден, то возвращается "Неопределено".
//
Функция ПолучитьЛистExcel(Excel, ИмяЛиста) Экспорт
 
	Попытка
		ExcelЛист = Excel.Sheets(ИмяЛиста);
	Исключение
		Сообщить("Не удалось прочитать лист Excel!", СтатусСообщения.Внимание);
		Возврат Неопределено;
	КонецПопытки;
 
	Возврат ExcelЛист;	
КонецФункции;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Записывает данные из табличного документа в файл MS Excel.
//
// Параметры:
//	ЛистExcel - <COMОбъект> - Лист из файла MS Excel;
//	Таблица - <ТабличныйДокумент> - Документ, по порядку следования колонок и строк 
//	 соответствующий листу файла MS Excel;
//	Шапка - <Число> - Количество первых строк для шапки в файле MS Excel;
//	СписокСтолбцов - <Строка>, <Массив> - Список номеров столбцов, которые будут выгружены 
//	 в файл MS Excel;
//	СписокСтрокЗапрета - <Строка>, <Массив> - Список номеров строк, которые не должны
//	 выгружаться в файл MS Excel. Если этот параметр не задан, то выгружаются все строки;
//	ПроверятьЗначения - <Булево> - Определяет будут ли проверяться ячейки табличного 
//	 документа на содержание в них значения, а не текстовое представление этого значения. 
//	 По умолчанию этот параметр "Ложь".
//
Процедура ДобавитьТабличныйДокументВExcel(ЛистExcel, Таблица, Шапка, СписокСтолбцов, СписокСтрокЗапрета = Неопределено, ПроверятьЗначения = Ложь) Экспорт
 
	Если ТипЗнч(СписокСтолбцов) = Тип("Строка") Тогда
		СписокСтолбцов = РазобратьСтрокуВМассивПоРазделителю(СписокСтолбцов);
	КонецЕсли;
	Если ТипЗнч(СписокСтрокЗапрета) = Тип("Строка") Тогда
		СписокСтрокЗапрета = РазобратьСтрокуВМассивПоРазделителю(СписокСтрокЗапрета);
	КонецЕсли;
 
	ЕстьМассив = (СписокСтрокЗапрета = Неопределено);
	Если ЕстьМассив Тогда
		Попытка
			МассивCOM = Новый COMSafeArray("VT_VARIANT", 1, Таблица.ВысотаТаблицы - Шапка);
		Исключение
			ЕстьМассив = Ложь;
		КонецПопытки;
	КонецЕсли;
 
	Для Каждого НомерСтолбца Из СписокСтолбцов Цикл
 
		Для НомерСтроки = Шапка+1 По Таблица.ВысотаТаблицы Цикл 
 
			Если СписокСтрокЗапрета = Неопределено 
				ИЛИ (СписокСтрокЗапрета.Найти(Строка(НомерСтроки)) = Неопределено И СписокСтрокЗапрета.Найти(Число(НомерСтроки)) = Неопределено) 
			Тогда
				Область = Таблица.Область(НомерСтроки, Число(НомерСтолбца));
				Значение = ?(ПроверятьЗначения И Область.СодержитЗначение, Область.Значение, Область.Текст);
				Если ЕстьМассив Тогда
					МассивCOM.SetValue(0, НомерСтроки-Шапка-1, Значение);
				Иначе
					ЛистExcel.Cells(НомерСтроки, Число(НомерСтолбца)).Value = Значение;
				КонецЕсли;
			КонецЕсли;
 
		КонецЦикла;
 
		Если ЕстьМассив Тогда 
			ЛистExcel.Range(ЛистExcel.Cells(Шапка+1, Число(НомерСтолбца)), ЛистExcel.Cells(Таблица.ВысотаТаблицы, Число(НомерСтолбца))).Value = МассивCOM;
		КонецЕсли;
 
	КонецЦикла;
 
КонецПроцедуры;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// Читает область ячеек из MS Excel в табличный документ.
//
// Параметры:
//	ЛистExcel - <COMОбъект> - Лист из файла MS Excel;
//	ТабДок - <ТабличныйДокумент> - Исходный табличный документ, поле табличного 
//	 документа или таблица значений. Если этот параметр не задан, то создаётся
//	 новый табличный документ;
//	НачалоСтрока - <Число> - Начальная строка в файле MS Excel;
//	НачалоСтолбец - <Число> - Начальный столбец в файле MS Excel;
//	КонецСтрока - <Число> - Конечная строка в файле MS Excel;
//	КонецСтолбец - <Число> - Конечный столбец в файле MS Excel.
//	
// Возвращаемое значение:
//	<ТабличныйДокумент> - Возвращает прочитанный из области в MS Excel табличный 
//	 документ, который передавался в эту функцию параметром "ТабДок".
//
Функция ПрочитатьОбластьИзExcel(ЛистExcel, ТабДок = Неопределено, НачалоСтрока, НачалоСтолбец, КонецСтрока, КонецСтолбец) Экспорт
 
	Если ТабДок = Неопределено Тогда
		ТабДок = Новый ТабличныйДокумент;
	КонецЕсли;
 
	Попытка
		МассивCOM = Новый COMSafeArray("VT_VARIANT", КонецСтолбец - НачалоСтолбец + 1, КонецСтрока - НачалоСтрока + 1);
		ЕстьМассив = Истина;
	Исключение
		ЕстьМассив = Ложь;
	КонецПопытки;
 
	Если ЕстьМассив Тогда
		МассивCOM = ЛистExcel.Range(ЛистExcel.Cells(НачалоСтрока, НачалоСтолбец), ЛистExcel.Cells(КонецСтрока, КонецСтолбец)).Value;
 
		Для ИндексКолонка = НачалоСтолбец По КонецСтолбец Цикл
			Для ИндексСтрока = НачалоСтрока По КонецСтрока Цикл
				Значение = МассивCOM.GetValue(ИндексКолонка - НачалоСтолбец + 1, ИндексСтрока - НачалоСтрока + 1);
				ТабДок.Область(ИндексСтрока, ИндексКолонка).СодержитЗначение = Истина;
				ТабДок.Область(ИндексСтрока, ИндексКолонка).Значение = Значение;
			КонецЦикла;
		КонецЦикла;	
	Иначе
		Для ИндексКолонка = НачалоСтолбец По КонецСтолбец Цикл
			Для ИндексСтрока = НачалоСтрока По КонецСтрока Цикл
				Значение = ЛистExcel.Cells(ИндексСтрока, ИндексКолонка).Value;
				ТабДок.Область(ИндексСтрока, ИндексКолонка).СодержитЗначение = Истина;
				ТабДок.Область(ИндексСтрока, ИндексКолонка).Значение = Значение;
			КонецЦикла;
		КонецЦикла;
	КонецЕсли;
 
	Возврат ТабДок;
КонецФункции;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Определяет ширину листа MS Excel.
//
// Параметры:
//	ЛистExcel - <COMОбъект> - Лист из файла MS Excel.
//	
// Возвращаемое значение:
//	<Число> - Количество столбцов в таблице.
//
Функция ШиринаЛистаExcel(ЛистExcel) Экспорт
 
	ЕстьЗащита = ЛистExcel.ProtectContents;
	Возврат ?(ЕстьЗащита, ЛистExcel.UsedRange.Columns.Count, ЛистExcel.Cells.SpecialCells(11).Column);
 
КонецФункции;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Определяет высоту листа MS Excel.
//
// Параметры:
//	ЛистExcel - <COMОбъект> - Лист из файла MS Excel.
//	
// Возвращаемое значение:
//	<Число> - Количество строк в таблице.
//
Функция ВысотаЛистаExcel(ЛистExcel) Экспорт
 
	ЕстьЗащита = ЛистExcel.ProtectContents;
	Возврат ?(ЕстьЗащита, ЛистExcel.UsedRange.Rows.Count, ЛистExcel.Cells.SpecialCells(11).Row);
 
КонецФункции;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Преобразовать табличный документ в таблицу значений.
//
// Параметры:
//	ТабДок - <ТабличныйДокумент> - Исходный табличный документ;
//	СтруктураКолонок - <Структура>, <ТаблицаЗначений> - Структура колонок;
//	НачалоСтрока - <Число> - Строка начала области;
//	НачалоСтолбец - <Число> - Столбец начала области;
//	КонецСтрока - <Число> - Строка конца области;
//	КонецСтолбец - <Число> - Столбец конца области.
//	
// Возвращаемое значение:
//	<ТаблицаЗначений> - Полученная таблица значений.
//
Функция ПреобразоватьТДвТЗ(ТабДок, СтруктураКолонок, Знач НачалоСтрока = Неопределено, Знач НачалоСтолбец = Неопределено, Знач КонецСтрока = Неопределено, Знач КонецСтолбец = Неопределено) Экспорт
 
	// Определение габаритов таблицы
	Если НачалоСтрока = Неопределено И НачалоСтолбец = Неопределено Тогда
		НачалоСтрока = 1;
		НачалоСтолбец = 1;
	КонецЕсли;
 
	Если НачалоСтрока = Неопределено Тогда
		НачалоСтрока = 1;
		Пока НЕ ТабДок.Область(НачалоСтрока, НачалоСтолбец).СодержитЗначение 
		 И НачалоСтрока < ТабДок.ВысотаТаблицы 
		Цикл
			НачалоСтрока = НачалоСтрока + 1;
		КонецЦикла;
	ИначеЕсли НачалоСтолбец = Неопределено Тогда
		НачалоСтолбец = 1;
		Пока НЕ ТабДок.Область(НачалоСтрока, НачалоСтолбец).СодержитЗначение 
		 И НачалоСтолбец < ТабДок.ШиринаТаблицы
		Цикл
			НачалоСтолбец = НачалоСтолбец + 1;
		КонецЦикла;
	КонецЕсли;
 
	КонецСтрока = ?(КонецСтрока = Неопределено, ТабДок.ВысотаТаблицы, КонецСтрока);
	КонецСтолбец = ?(КонецСтолбец = Неопределено, ТабДок.ШиринаТаблицы, КонецСтолбец);
 
	// Преобразование
	ЭтоТаблица = (ТипЗнч(СтруктураКолонок) = Тип("ТаблицаЗначений"));
	ТабЗначений = ПолучитьТаблицуВывода(СтруктураКолонок);
 
	Для ИндексСтроки = НачалоСтрока По КонецСтрока Цикл
		СтрокаТЗ = ТабЗначений.Добавить();
 
		ИндексКолонки = НачалоСтолбец;
		Для Каждого Колонка Из СтруктураКолонок Цикл
			НаименованиеКолонки = ?(ЭтоТаблица, Колонка.Наименование, Колонка.Ключ);
			пИндексКолонки = ?(ЭтоТаблица, Колонка.СтолбецОтчёт, ИндексКолонки);
 
			Если ТабДок.Область(ИндексСтроки, пИндексКолонки).СодержитЗначение Тогда
				СтрокаТЗ[НаименованиеКолонки] = ТабДок.Область(ИндексСтроки, пИндексКолонки).Значение;
			Иначе
				СтрокаТЗ[НаименованиеКолонки] = ТабДок.Область(ИндексСтроки, пИндексКолонки).Текст;
			КонецЕсли;
 
			ИндексКолонки = ИндексКолонки + 1;
		КонецЦикла;
	КонецЦикла;
 
	Возврат ТабЗначений;
КонецФункции;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Преобразовать таблицу значений в табличный документ.
//
// Параметры:
//	ТабЗначений - <ТаблицаЗначений> - Исходная таблица значений;
//	ТабДок - <ТабличныйДокумент> - Полученный табличный документ. Если параметр не задан, 
//	 то документ создаётся заново и возвращается функцией;
//	НачалоСтрока - <Число> - Строка начала области;
//	НачалоСтолбец - <Число> - Столбец начала области;
//	ВыводитьЗаголовки - <Булево> - Определяет выводить ли имена колонок или нет.
//	
// Возвращаемое значение:
//	<ТабличныйДокумент> - Полученный табличный документ (возвращает параметр "ТабДок").
//
Функция ПреобразоватьТЗвТД(ТабЗначений, ТабДок = Неопределено, Знач НачалоСтрока = Неопределено, Знач НачалоСтолбец = Неопределено, ВыводитьЗаголовки = Ложь) Экспорт
 
	Если ТабДок = Неопределено Тогда
		ТабДок = Новый ТабличныйДокумент;
	КонецЕсли;
 
	// Определение габаритов таблицы
	НачалоСтрока = ?(НачалоСтрока = Неопределено, 1, НачалоСтрока);
	НачалоСтолбец = ?(НачалоСтолбец = Неопределено, 1, НачалоСтолбец);
 
	// Преобразование
	ИндексСтроки = НачалоСтрока;
	Если ВыводитьЗаголовки Тогда
		ИндексКолонки = НачалоСтолбец;
		Для Каждого Колонка Из ТабЗначений.Колонки Цикл
			ТабДок.Область(ИндексСтроки, ИндексКолонки).Текст = ?(ПустаяСтрока(Колонка.Заголовок), Колонка.Имя, Колонка.Заголовок);
			ИндексКолонки = ИндексКолонки + 1;
		КонецЦикла;
		ИндексСтроки = ИндексСтроки + 1;
	КонецЕсли;
 
	Для Каждого Элемент Из ТабЗначений Цикл
		ИндексКолонки = НачалоСтолбец;
		Для Каждого Колонка Из ТабЗначений.Колонки Цикл
			ТабДок.Область(ИндексСтроки, ИндексКолонки).СодержитЗначение = Истина;
			ТабДок.Область(ИндексСтроки, ИндексКолонки).ТипЗначения = Новый ОписаниеТипов(Колонка.ТипЗначения);
			ТабДок.Область(ИндексСтроки, ИндексКолонки).Значение = Элемент[Колонка.Имя];
			ИндексКолонки = ИндексКолонки + 1;
		КонецЦикла;
		ИндексСтроки = ИндексСтроки + 1;
	КонецЦикла;
 
	Возврат ТабДок;
КонецФункции;

В реализации алгоритма был дополнительно использован объект COMSafeArray с типом VT_VARIANT. Этот COM-объект выступает в качестве двумерного массива, в котором удобно хранить значения ячеек. Также использование данного объекта повышает быстродействие операций чтения/записи для ячеек таблицы.

Целиком получившуюся обработку 1С, а также шаблон для загрузки/выгрузки можно скачать по ссылке ниже [2].

Указанные здесь процедуры и функции я постарался сделать универсальными. Они могут быть применены для широкого круга прикладных задач.

Скачать

 

Нравится статья? Подпишитесь прямо сейчас и получайте обновления на свой E-Mail:

БЕСПЛАТНЫЕ материалы по изучению конфигурации 1С:Бухгалтерия 8 (ред. 2 и новая ред. 3) [3]