Что такое 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</Ид>
<Наименование>Центральный склад</Наименование>
</Подразделение>
</Подразделения>
</Классификатор>
Вообще, ничего не жалко для народа — выкладываю свою наработку за недорого, если кто все же не понял, что и как.
Не понял, для чего вы создали тип УникальныйИдентификатор? Все равно вы айдишники в строку преобразуете.
Еще у вас на выходе неправильная 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</Ид>
<Наименование>Торговый зал</Наименование>
</Подразделение>
В таком случае было бы проще не упаковывать вложенные подразделения в отдельный контейнер, а добавить свойство «ИДРодителя»
(1) hulio, замечательно, что Вы заметили.
1. По вопросу у УИН, то это как пример того, как можно определять типы данных в XDTO-пакете.
2. По поводу файла, то действительно вывелось все и сразу. Причиной тому — передача «Неопределено» в функцию, в которой выбирается текущий уровень через выборку справочника. Это легко исправляется.
3. По поводу ИД родителя, то это не удовлетворяет условию разбираемой тут задачи, а именно — выгрузка иерархического справочника с помощью рекурсии.
Надеюсь, я смог ответить на все Ваши вопросы.