gifts2017

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

Опубликовал Sergey Andreev (starik-2005) в раздел Программирование - Теория программирования

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

Что такое 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</Ид>
			<Наименование>Центральный склад</Наименование>
		</Подразделение>
	</Подразделения>
</Классификатор>

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

Скачать файлы

Наименование Файл Версия Размер Кол. Скачив.
ВыгрузкаКлассификатора.epf
.epf 7,05Kb
25.02.16
6
.epf 7,05Kb 6 Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

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

Надеюсь, я смог ответить на все Ваши вопросы.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа