Пример рекурсивной выгрузки иерархической структуры в XDTO

26.02.16

Разработка - Математика и алгоритмы

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

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
ВыгрузкаКлассификатора.epf
.epf 7,05Kb
20
20 Скачать (1 SM) Купить за 1 850 руб.

Что такое XDTO?

Ну, полагаю, тут мало людей, кто не знает, что это такое. Но т.к. я постоянно вижу выгрузку в тот же CML, реализованную от незнания через обычную запись XML, куда гонятся узлы и атрибуты, то я думаю, что XDTO просто стращно звучит для многих. Упростим выражение до примитивов, чтобы и ежу было понятно.

Итак, XDTO - это, можно сказать, и есть объектная модель XML. Да, понятнее не стало, но я уже включаю тяжелую артилерию - наглядные пособия с картинками.

Чтобы абстрагироваться от всей этой наносной терминологической мути, давайте тупо создадим пакет XDTO, замутим в нем иерархию и заставим ее выгружаться в XML-файл. И никаких дебрей терминологии - пусть терминологи идут рыть канавы - больше пользы)))

1. Создадим пакет XDTO

Для этого открываем конфигуратор и жамкаем правой кнопкой на XDTO-пакеты (в общих). Дальше нажимаем "Добавить":

Да, вот так все просто. Кстати, пакет можно импортировать из файла XSD. Дальше надо прописать пакету какое-нибудь имя и это долбанное "URI пространства имен" (это любые символы, какие вам заблагорассудятся, но они потом будут использованы, так что креативчика поубавьте, чтобы не писать три страницы). Наш пакет пустой - он предмет простой (с). Давайте усложним - добавим Тип значений и пару Типов объектов:

Я, как видите, занялся идеей выгружать иерархическую структуру предприятия (кстати, ее потом сюда - в XDTO-пакет - можно будет загрузить и обойти). Поэтому я добавил Тип "УникальныйИдентификатор" и два Типа объектов - Классификатор и Подразделение. В классификаторе я определяю первичный контейнер для данных, а подразделение будет субконтейнером. В принципе, полагаю, можно обойтись и одним Подразделением, но так обычно не бывает и иерархический элемент воткнут в какой-то внешний контейнер.

Для Классификатора и Подразделения и создаю три свойства: Ид (с типом "УникальныйИдентификатор", который определен в пакете), Наименование и Подразделения с субконтейнером "Подразделение". Для свойства "Подразделение" я указываю тип "Подразделение" и прописываю минимальное и максимальное количество (0 и -1 соответственно). Это нужно для того, чтобы мы, во-первых, могли указать, что у данного подразделения нет подчиненных, а, во-вторых, могли бы указать любое количество подчиненных подразделений.

Так, с пакетом все.

2. Напишем код выгрузки

Создали пакеты, сохранили конфигурацию и создали внешнюю обработочку, да? Тогда давайте приступим к наполнению ее кодом.

Для того, чтобы получить наш пакет и начать с ним работать, нам надо получить какой-либо тип и создать на его основе XDTO-объект. В синтаксис-помощнике нет ни одного примера, поэтому тут придется показывать. Первая часть марлезонского балета выглядит как-то так:

Пакет = ФабрикаXDTO.Пакеты.Получить("sample-my-package");

Классификатор = ФабрикаXDTO.Создать(Пакет.Получить("Классификатор"));
Классификатор.Ид = ""+ (Новый УникальныйИдентификатор);
Классификатор.Наименование = "Организационная структура";

Видите, как просто! Получаем пакет из базовой фаблики по имени URI, чтоб ему пусто было. Никак не могу понять, кто эту хрень придумал, ну да ладно - не в этом суть. Главное - мы получили пакет, из которого теперь можем дергать свойства и создавать объекты XDTO. Дальше в коде мы получили на основании типа объекта "Классификатор" соответствующий объект XDTO. Дальше заполняем поля. А вот с иерархией все сложнее. Для простого случая можно сделать так:

Подразделения = ФабрикаXDTO.Создать(Пакет.Получить("Классификатор").Свойства.Получить("Подразделения").Тип);
Подразделение = ФабрикаXDTO.Создать(Пакет.Получить("Подразделение"));
Подразделение.Ид = ""+Выборка.УИН;
Подразделение.Наименование = Выборка.Наименование;
Подразделения.Подразделение.Добавить(Подразделение);

Тут мы добавили первый элемент в список подразделений. Чтобы подразделения попали в выгрузку, нам надо поместить объект "Подразделения" в Классификатор:

Классификатор.Подразделения = Подразделения;

В итоге мы получим только такой вот файл, если выгрузим это в XML:

<?xml version="1.0" encoding="UTF-8"?>
<Классификатор xmlns="sample-my-package" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<Ид>1ea4a653-d292-4769-8ef7-91db4293f9b8</Ид>
	<Наименование>Организационная структура</Наименование>
	<Подразделения>
		<Подразделение>
			<Ид>6f87e821-722c-11df-b336-0011955cba6b</Ид>
			<Наименование>Бухгалтерия</Наименование>
		</Подразделение>
	</Подразделения>
</Классификатор>

Для того, чтобы все отработало без лишних действий, напишем рекурсивную функцию, которая будет возвращать контейнер "Подразделения" Каталога:

Классификатор.Подразделения = ВыгрузитьРекурсивно(Пакет, "СтруктураПредприятия");

Далее сама функция:

Функция ВыгрузитьРекурсивно(Пакет, Справочник, Родитель = Неопределено)
	
	Если Родитель = Неопределено Тогда 
		Уровень = ФабрикаXDTO.Создать(Пакет.Получить("Классификатор").Свойства.Получить("Подразделения").Тип);
	Иначе
		Уровень = ФабрикаXDTO.Создать(Пакет.Получить("Подразделение").Свойства.Получить("Подразделения").Тип);
	КонецЕсли;
	ЕстьОбъекты = Ложь;
	
	Для Каждого Выборка ИЗ ПолучитьМассивЗначений(Справочник, Родитель) Цикл 
		ЕстьОбъекты = Истина;
		Подразделение = ФабрикаXDTO.Создать(Пакет.Получить("Подразделение"));
		Подразделение.Ид = ""+Выборка.УИН;
		Подразделение.Наименование = Выборка.Наименование;
		ПодразделенияУровня = ВыгрузитьРекурсивно(Пакет, Справочник, Выборка.Ссылка);
		Если НЕ ПодразделенияУровня = Неопределено Тогда 
			Подразделение.Подразделения = ПодразделенияУровня;
		КонецЕсли;
		Уровень.Подразделение.Добавить(Подразделение);
	КонецЦикла;
	
	Возврат ?(ЕстьОбъекты, Уровень, Неопределено);
КонецФункции

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

В итоге вот такой файлик получился при выгрузке из демоторговли:

<?xml version="1.0" encoding="UTF-8"?>
<Классификатор xmlns="sample-my-package" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<Ид>1ea4a653-d292-4769-8ef7-91db4293f9b8</Ид>
	<Наименование>Организационная структура</Наименование>
	<Подразделения>
		<Подразделение>
			<Ид>6f87e821-722c-11df-b336-0011955cba6b</Ид>
			<Наименование>Бухгалтерия</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>c37c8fa9-7ae7-11df-b33a-0011955cba6b</Ид>
			<Наименование>Касса</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>163cab6d-35ae-11e0-aefc-0015e9b8c48d</Ид>
			<Наименование>Ларек "Розница"</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>93961168-ed19-11e2-802e-0015e9b8c48d</Ид>
			<Наименование>Магазин "Бытовая техника"</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>163cab59-35ae-11e0-aefc-0015e9b8c48d</Ид>
			<Наименование>Магазин "Продукты"</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>163cab5a-35ae-11e0-aefc-0015e9b8c48d</Ид>
			<Наименование>Магазин "Электротовары"</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>a4212b47-730a-11df-b338-0011955cba6b</Ид>
			<Наименование>Магазины (НТТ)</Наименование>
			<Подразделения>
				<Подразделение>
					<Ид>163cab6d-35ae-11e0-aefc-0015e9b8c48d</Ид>
					<Наименование>Ларек "Розница"</Наименование>
				</Подразделение>
				<Подразделение>
					<Ид>93961168-ed19-11e2-802e-0015e9b8c48d</Ид>
					<Наименование>Магазин "Бытовая техника"</Наименование>
				</Подразделение>
				<Подразделение>
					<Ид>163cab59-35ae-11e0-aefc-0015e9b8c48d</Ид>
					<Наименование>Магазин "Продукты"</Наименование>
				</Подразделение>
				<Подразделение>
					<Ид>163cab5a-35ae-11e0-aefc-0015e9b8c48d</Ид>
					<Наименование>Магазин "Электротовары"</Наименование>
				</Подразделение>
			</Подразделения>
		</Подразделение>
		<Подразделение>
			<Ид>9e5ddc14-175a-11e2-bfa2-0015e9b8c48d</Ид>
			<Наименование>Отдел доставки</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>4d9d0772-7ab1-11df-b33a-0011955cba6b</Ид>
			<Наименование>Отдел закупок</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>51ed67e2-7220-11df-b336-0011955cba6b</Ид>
			<Наименование>Отдел логистики</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>51ed67a5-7220-11df-b336-0011955cba6b</Ид>
			<Наименование>Отдел маркетинга</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>be8a7643-f8df-11e2-802f-0015e9b8c48d</Ид>
			<Наименование>Отдел оптовых продаж</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>51ed67e1-7220-11df-b336-0011955cba6b</Ид>
			<Наименование>Отдел продаж</Наименование>
			<Подразделения>
				<Подразделение>
					<Ид>be8a7643-f8df-11e2-802f-0015e9b8c48d</Ид>
					<Наименование>Отдел оптовых продаж</Наименование>
				</Подразделение>
				<Подразделение>
					<Ид>6f87e81f-722c-11df-b336-0011955cba6b</Ид>
					<Наименование>Отдел работы с дилерами</Наименование>
				</Подразделение>
				<Подразделение>
					<Ид>6f87e820-722c-11df-b336-0011955cba6b</Ид>
					<Наименование>Отдел работы с дистрибьюторами</Наименование>
				</Подразделение>
				<Подразделение>
					<Ид>be8a7644-f8df-11e2-802f-0015e9b8c48d</Ид>
					<Наименование>Отдел розничных продаж</Наименование>
				</Подразделение>
				<Подразделение>
					<Ид>49278eed-7ef4-11df-866e-00d0d0817f92</Ид>
					<Наименование>Торговые представители</Наименование>
				</Подразделение>
			</Подразделения>
		</Подразделение>
		<Подразделение>
			<Ид>6f87e81f-722c-11df-b336-0011955cba6b</Ид>
			<Наименование>Отдел работы с дилерами</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>6f87e820-722c-11df-b336-0011955cba6b</Ид>
			<Наименование>Отдел работы с дистрибьюторами</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>be8a7644-f8df-11e2-802f-0015e9b8c48d</Ид>
			<Наименование>Отдел розничных продаж</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>6f87e81d-722c-11df-b336-0011955cba6b</Ид>
			<Наименование>Сервисная служба</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>1418c674-7307-11df-b338-0011955cba6b</Ид>
			<Наименование>Склад мебели</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>6f87e81e-722c-11df-b336-0011955cba6b</Ид>
			<Наименование>Склады</Наименование>
			<Подразделения>
				<Подразделение>
					<Ид>1418c674-7307-11df-b338-0011955cba6b</Ид>
					<Наименование>Склад мебели</Наименование>
				</Подразделение>
				<Подразделение>
					<Ид>1418c675-7307-11df-b338-0011955cba6b</Ид>
					<Наименование>Торговый зал</Наименование>
				</Подразделение>
				<Подразделение>
					<Ид>1418c673-7307-11df-b338-0011955cba6b</Ид>
					<Наименование>Центральный склад</Наименование>
				</Подразделение>
			</Подразделения>
		</Подразделение>
		<Подразделение>
			<Ид>49278eed-7ef4-11df-866e-00d0d0817f92</Ид>
			<Наименование>Торговые представители</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>1418c675-7307-11df-b338-0011955cba6b</Ид>
			<Наименование>Торговый зал</Наименование>
		</Подразделение>
		<Подразделение>
			<Ид>1418c673-7307-11df-b338-0011955cba6b</Ид>
			<Наименование>Центральный склад</Наименование>
		</Подразделение>
	</Подразделения>
</Классификатор>

Вообще, ничего не жалко для народа - выкладываю свою наработку за недорого, если кто все же не понял, что и как.

XDTO XDTO иерархия XDTO иерархия рекурсия

См. также

Внешние источники данных Программист Бизнес-аналитик Пользователь Платформа 1С v8.3 Управляемые формы Анализ и прогнозирование Конфигурации 1cv8 Узбекистан Беларусь Кыргызстан Молдова Россия Казахстан Платные (руб)

Готовое решение для автоматической выгрузки данных из 1С 8.3 в базу данных ClickHouse, PostgreSQL или Microsoft SQL для работы с данными 1С в BI-системах. «Экстрактор данных 1С в BI» работает со всеми типовыми и нестандартными конфигурациями 1С 8.3 и упрощает работу бизнес-аналитиков. Благодаря этому решению, специалистам не требуется быть программистами, чтобы легко получать данные из 1С в вашей BI-системе.

28500 руб.

15.11.2022    20637    20    49    

38

Поиск данных Внешние источники данных Системный администратор Программист Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Если вам нужно автоматически генерировать представления (view) к вашей базе данных 1С (есть две версии - для СУБД MS SQL Server и для PostgreSQL) по структуре метаданных 1С, то вам необходима данная обработка. Наш "Генератор View", другими словами - это коннектор к данным 1С для Power BI - незаменимый помощник для бизнес-аналитиков, работающих с базами 1С из Yandex Datalens/Power BI и т.д. Работает для обычных и управляемых форм под 1С 8.3

230000 руб.

31.07.2020    13733    13    48    

25

Внешние источники данных Зарплата Бюджетный учет Программист Бухгалтер Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бухгалтерский учет Бюджетный учет Платные (руб)

Обработка позволяет перенести кадровую информацию и данные по заработной плате, фактических удержаниях, НДФЛ, вычетах, страховых взносах из базы Парус 7.хх учреждений в конфигурацию 1С:Зарплата и кадры государственного учреждения ред. 3 (ЗГУ) и начать с ней работать с любого месяца года.

48000 руб.

24.04.2017    51025    100    165    

89

Зарплата Внешние источники данных Бюджетный учет Перенос данных 1C Системный администратор Программист Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бухгалтерский учет Бюджетный учет Платные (руб)

Обработка позволяет перенести кадровую информацию и данные по заработной плате, фактических удержаниях, НДФЛ, вычетах, страховых взносах из базы Парус 8 учреждений в конфигурацию 1С:Зарплата и кадры государственного учреждения ред. 3 (ЗГУ) и начать с ней работать с любого месяца года.

84000 руб.

19.08.2020    25028    23    1    

25

Внешние источники данных Кадровый учет Файловый обмен (TXT, XML, DBF), FTP Перенос данных 1C Программист Платформа 1С v8.3 Сложные периодические расчеты 1С:Зарплата и кадры государственного учреждения 3 Государственные, бюджетные структуры Россия Бухгалтерский учет Бюджетный учет Платные (руб)

Обработка позволяет перенести кадровую информацию и данные по заработной плате, фактических удержаниях, НДФЛ, вычетах, страховых взносах из базы Парус 10 учреждений в конфигурацию 1С:Зарплата и кадры государственного учреждения ред. 3 (ЗГУ) и начать с ней работать с любого месяца года.

60000 руб.

05.10.2022    10771    12    8    

14

Сайты и интернет-магазины WEB-интеграция Системный администратор Программист Пользователь Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    17782    19    22    

16
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. charushkin 109 28.02.16 11:55 Сейчас в теме
Не понял, для чего вы создали тип УникальныйИдентификатор? Все равно вы айдишники в строку преобразуете.
Еще у вас на выходе неправильная XML-ка получилась - подразделения нижних уровней присутствуют и на верхнем уровне тоже. Например, подразделение "Склады" и содержит вложенные подразделения "Центральный склад", "Склад мебели" и т.д., а далее эти же подразделения идут сами по себе, без указания вложенности:
<Подразделение>
<Ид>6f87e81e-722c-11df-b336-0011955cba6b</Ид>
<Наименование>Склады</Наименование>
<Подразделения>
<Подразделение>
<Ид>1418c674-7307-11df-b338-0011955cba6b</Ид>
<Наименование>Склад мебели</Наименование>
</Подразделение>
<Подразделение>
<Ид>1418c675-7307-11df-b338-0011955cba6b</Ид>
<Наименование>Торговый зал</Наименование>

</Подразделение>
<Подразделение>
<Ид>1418c673-7307-11df-b338-0011955cba6b</Ид>
<Наименование>Центральный склад</Наименование>
</Подразделение>
</Подразделения>
</Подразделение>
<Подразделение>
<Ид>49278eed-7ef4-11df-866e-00d0d0817f92</Ид>
<Наименование>Торговые представители</Наименование>
</Подразделение>
<Подразделение>
<Ид>1418c675-7307-11df-b338-0011955cba6b</Ид>
<Наименование>Торговый зал</Наименование>

</Подразделение>

В таком случае было бы проще не упаковывать вложенные подразделения в отдельный контейнер, а добавить свойство "ИДРодителя"
2. starik-2005 3087 28.02.16 23:16 Сейчас в теме
(1) hulio, замечательно, что Вы заметили.
1. По вопросу у УИН, то это как пример того, как можно определять типы данных в XDTO-пакете.
2. По поводу файла, то действительно вывелось все и сразу. Причиной тому - передача "Неопределено" в функцию, в которой выбирается текущий уровень через выборку справочника. Это легко исправляется.
3. По поводу ИД родителя, то это не удовлетворяет условию разбираемой тут задачи, а именно - выгрузка иерархического справочника с помощью рекурсии.

Надеюсь, я смог ответить на все Ваши вопросы.
Оставьте свое сообщение