Пример рекурсивной выгрузки иерархической структуры в 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-системе.

15.11.2022    19816    18    SQV0    49    

38

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

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

84000 руб.

19.08.2020    24498    23    1    

25

Поиск данных Внешние источники данных Системный администратор Программист Платформа 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    13544    13    48    

25

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

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

60000 руб.

05.10.2022    10529    11    8    

13

WEB-интеграция Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Россия Платные (руб)

Функциональное решение для торговли на всех популярных маркетплейсах. Работает со схемами FBO и FBS. Простое в использовании и установке, не вносит изменения в код программы. Существенно упрощает работу с товарным ассортиментом, обработку заказов с площадок, работу с поставками, а также ведение аналитики по продажам и остаткам.

72000 руб.

19.07.2024    1436    52    0    

3

WEB-интеграция Программист Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Внешняя обработка разрабатывалась для загрузки документов из Ветменеджер в 1С: Бухгалтерия 3.0

12000 руб.

02.02.2021    17786    49    50    

29

Производство готовой продукции (работ, услуг) Внешние источники данных Платформа 1С v8.3 1С:Управление нашей фирмой 1.6 Лесное и деревообрабатывающее хозяйство Россия Управленческий учет Платные (руб)

Обработка предназначена для загрузки файлов, выгруженных из системы Базис-мебельщик, в справочник 1С "Спецификации" для последующих процессов учета и диспетчирования полуфабрикатов и изделий.

10200 руб.

24.06.2021    20420    57    53    

35
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. charushkin 108 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 3081 28.02.16 23:16 Сейчас в теме
(1) hulio, замечательно, что Вы заметили.
1. По вопросу у УИН, то это как пример того, как можно определять типы данных в XDTO-пакете.
2. По поводу файла, то действительно вывелось все и сразу. Причиной тому - передача "Неопределено" в функцию, в которой выбирается текущий уровень через выборку справочника. Это легко исправляется.
3. По поводу ИД родителя, то это не удовлетворяет условию разбираемой тут задачи, а именно - выгрузка иерархического справочника с помощью рекурсии.

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