«[необходимо зарегистрироваться для просмотра ссылки] ште́ко будлану́ла бо́кра и курдя́чит бокрёнка»
(первая ассоциация, пришедшая в голову
после прочтения "мана" о XDTO-пакетах)
Приветствую, многоуважаемый all!
После долгого молчания, вызванного тем, что я сейчас больше читаю, чем пишу (чукча читатель, а не писатель), я решил поделиться с вами небольшим обзором, в котором хочу рассказать о том, что я узнал о XDTO-пакетах и обо всем, что с ними связано. Сразу скажу, что в интернете есть документация на эту тему и вообще гугл никто не отменял, но, на мой взгляд, ее как-то маловато. Пусть будет еще. Итак.
С чего начинается?..С чего начинаются XDTO-пакеты для неискушенного разработчика? Для меня они начались с вопроса: "А что это еще за хренотень в дереве метаданных?" И еще я знал, что это что-то про xml. Но мы начнем не с этого. А с объекта
ФабрикаXDTO. Как можно догадаться из названия, это фабрика объектов ([необходимо зарегистрироваться для просмотра ссылки] как XML Data Transfer Objects).
Небольшое лирическое отступление. Лучше понять, что такое "фабрика объектов", можно из замечательной книги "[необходимо зарегистрироваться для просмотра ссылки]" в частности, в разделе о шаблоне "[необходимо зарегистрироваться для просмотра ссылки]", или "[необходимо зарегистрироваться для просмотра ссылки]". Книга, хочу заметить, действительно стоящая, но мозголомная, скорее формата "справочник", а не "учебник". Вдобавок все, что там написано, сложно применимо к 1С. Когда-нибудь я разозлюсь и напишу здоровенную статью о шаблонах ([необходимо зарегистрироваться для просмотра ссылки]), а то досадно, что некоторые 1С-программистов [необходимо зарегистрироваться для просмотра ссылки]. Инструмент не должен стоять на пути человека к вершинам профессионализма. Но пока не об этом.
Итак, говоря простым языком, фабрика объектов - это некое "устройство", умеющее принять на входе описание объекта и сгенерировать по этому описанию объект определенного типа, "пригодный к употреблению". Или несколько. То есть это в прямом смысле фабрика: загрузили "чертеж", и она пошла штамповать "продукцию" по "чертежу" (для дотошных: "сырье" в этом случае ваше процессорное время, электричество и т.д.).

Тут я просто вынужден послать вас ознакомиться с
хорошей статьёй о простых типах в XDTO с диска ИТС. Если бы это было целесообразно, я бы всю ее скопипастил сюда, но зачем? И все же один пример я оттуда возьму. Для наглядности.
Вот так в статье описывается работа с объектом "Структура":
структурныйТип = ФабрикаXDTO.Тип("http://www.1c.ru/demos/products", "Номенклатура");
номенклатура = ФабрикаXDTO.Создать(структурныйТип);
номенклатура.Наименование = "Ботинки женские";
номенклатура.ЗакупочнаяЦена = 1000;
Для этого примера я бы нарисовал такую диаграмму:

Обратите внимание, что объект "структурныйТип" (т.н. "чертеж") тоже был создан фабрикой, на основании "загадочных" строчек. Рассмотрим, что же это за строчки. Про метод "Тип" объекта "ФабрикаXDTO" синтакс-помощник пишет:
Цитата
Синтаксис:
Тип(<URIПространстваИмен>, <Имя>)
Возвращаемое значение:
Тип: ТипЗначенияXDTO; ТипОбъектаXDTO; Неопределено.
Описание:
Получение типа XDTO.
Не слишком информативно. Тем не менее понятно, что на основании какого-то пространства имен и имени типа метод "Тип" создает нам необходимый "чертёж". Про пространства имен можно почитать, например, в статье "[необходимо зарегистрироваться для просмотра ссылки]", или терзайте жужл запросом "[необходимо зарегистрироваться для просмотра ссылки]". Вкратце же скажу, что это некая область, в которой вы можете определить свои xml-теги, и они будут означать именно то, что вы в них закладывали при определении. Например, тег <table> в пространстве имен, определяющем HTML-документ, означает описание таблицы, а в вашем собственном он может означать, например, блок описания стола. Чтобы их не путать и нужны пространства имен.
Тут есть очень важный момент, который сначала вводит в заблуждение. Название пространства имен напоминает адрес страницы в интернете, и сразу же хочется посмотреть, что там такое по этому адресу. Так вот. Технически название может быть любым, но разработчики договорились, что все будут использовать в качестве названия пространства имен URL, по которому в интернете находится страница с описанием этого пространства имен,
понятным человеку. К тому же так обеспечивается уникальность названий пространств имен, поскольку в интернете не может быть двух страниц с одинаковым адресом. И "ФабрикаXDTO" при генерации типа XDTO, конечно же,
не лезет в интернет ни за какими данными. К сожалению, не все соблюдают правило о публикации человеческих описаний (сволочи!), и уж тем более нехорошо использовать адреса на чужих доменах (как в примере). Мало ли какую информацию фирма 1С воткнет со временем на страницу [необходимо зарегистрироваться для просмотра ссылки]. Это может вводить в заблуждение, поэтому в production-коде я настойчиво рекомендую использовать собственные домены и писать описания. Коллеги разработчики, давайте заботиться друг о друге.
Все же XDTO-пакетыПоскольку мы выяснили, что данные о пространстве имен берутся не из интернета, возникает вполне резонный вопрос: откуда же тогда, черт побери?! И вот тут мы подходим к тому самому разделу "XDTO-пакеты" в дереве метаданных в конфигураторе. Внимательный читатель, наверное, заметил (если еще не забыл после моих лирических отступлений), что в примере мы использовали объект "ФабрикаXDTO", нигде его не создавая. Все верно, в глобальном контексте 1С есть такой объект (я бы сказал "синглтон"), который знает о куче разных пространств имен, уже описанных в конфигураторе и вообще в платформе. То есть для того, чтобы наш пример заработал, нам необходимо создать примерно такой XDTO-пакет:

То есть мы создали тип объекта "Номенклатура", в который добавили два свойства: "Наименование" и "ЗакупочнаяЦена". Обратите внимание, что при создании пакета мы задали ему то пространство имен, которое в дальнейшем будем использовать при создании объекта "структурныйТип". Если вы посмотрите конструктор свойств, то можете увидеть там много интересного. Например, для моего свойства "Наименование" я использовал тип "string (http://www.w3.org/2001/XMLSchema)". Запомните это пространство имен. В нем описаны все базовые типы, которые вы можете использовать в своих объектах, такие как "string", "int" и так далее. После того как мы добавили пакет, объект "ФабрикаXDTO" знает о нашем пространстве имен и описанных в нем типах.
Нужно помнить, что пространства имен, описанные в разделе дерева метаданных "XDTO-пакеты", доступны только на сервере. При попытке обратиться к ним из клиентского кода (так же как и при других ошибках) метод "Тип" вернет "Неопределено". Этот момент несколько раздражает при отладке, мне кажется, что лучше бы оно ругалось чем-нибудь вроде "Тип не найден", но "маємо те, що маємо".
В своих объектах вы можете использовать и собственные типы из вашего пространства имен. Например, давайте добавим единицы измерения:

В качестве типа для свойства "ЕдИзм" я установил тип "ЕдиницаИзмерения (http://www.1c.ru/demos/products1)", просто выбрав его из дерева определенных в конфигурации типов.
А вот код, который создает этот объект:
структурныйТип = ФабрикаXDTO.Тип("http://www.1c.ru/demos/products1", "Номенклатура1");
номенклатура = ФабрикаXDTO.Создать(структурныйТип);
номенклатура.Наименование = "Ботинки женские";
номенклатура.ЗакупочнаяЦена = 1000;
единицаТип = ФабрикаXDTO.Тип("http://www.1c.ru/demos/products1", "ЕдиницаИзмерения");
единица = ФабрикаXDTO.Создать(единицаТип);
единица.Наименование = "шт.";
единица.Коэффициент = 1.5;
номенклатура.ЕдИзм = единица;
Надеюсь, принцип понятен. Можете самостоятельно поиграться со свойствами, типами, объектами и прочим. Там есть куда "потыкать пальцем" и чего попробовать. А я тем временем продолжу.
Сериализировали-сериализировалиЧто полезного мы уже можем извлечь из того, что знаем? Во-первых, объекты XDTO прекрасно сериализуются (XML же, как вы помните). Дополним код вот таким фрагментом:
ИмяФайла = "D:\Temp\struct.xml";
МойXML = Новый ЗаписьXML;
ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
МойXML.ОткрытьФайл(ИмяФайла, ПараметрыЗаписиXML);
МойXML.ЗаписатьОбъявлениеXML();
ФабрикаXDTO.ЗаписатьXML(МойXML, номенклатура);
МойXML.Закрыть();
На выходе мы получим вот такой файл:
<Номенклатура1 xmlns="http://www.1c.ru/demos/products1"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Наименование>Ботинки женские<Наименование>
<ЗакупочнаяЦена>1000<ЗакупочнаяЦена>
<ЕдИзм>
<Наименование>шт.<Наименование>
<Коэффициент>1.5<Коэффициент>
<ЕдИзм>
<Номенклатура1>
Теперь вы можете послать его друзьям по электронной почте, если, конечно, их интересуют женские ботинки. =)
Но поскольку объекты сериализуются, то они так же замечательно и десериализуются. Давайте попробуем:
структурныйТип = ФабрикаXDTO.Тип("http://www.1c.ru/demos/products1", "Номенклатура1");
ИмяФайла = "D:\Temp\struct.xml";
МойXML = Новый ЧтениеXML;
МойXML.ОткрытьФайл(ИмяФайла);
номенклатура = ФабрикаXDTO.ПрочитатьXML(МойXML, структурныйТип);
МойXML.Закрыть();
Сообщить(номенклатура.ЕдИзм.Наименование);
Вы когда-нибудь разбирали xml-файлы построчно, вылавливая значки "больше"-"меньше" бесконечными "Найти" и "Сред/Лев/Прав"? А пользовались ли вы замечательным объектом "ЧтениеXML" для разбора файла по тегам, которые потом приходилось разгребать вручную в какую-нибудь структуру? Теперь, если у вас правильно описаны XDTO-пакеты и типы в них, вы можете загружать xml сразу в объект и дальше работать с ним как с объектом. На мой взгляд, это замечательно и удобно.
К тому же при загрузке xml-файла происходит его валидация на соответствие типу, и в случае ошибки метод вызывает исключение. Поэтому, конечно же, правильный код по загрузке xml будет такой:
Попытка
номенклатура = ФабрикаXDTO.ПрочитатьXML(МойXML, структурныйТип);
Исключение
Сообщить(ОписаниеОшибки());
// еще какая-нибудь обработка исключения
Возврат;
КонецПопытки;
Что еще полезного можно получить из XDTO-пакетов? А вот что! Также мы можем очень просто выгружать объекты метаданных. В конфигурации есть пространство имен, в котором есть все типы XDTO присутствующих в конфигурации метаданных.
Добавим справочник "Клиенты", создадим в нем один элемент и напишем такой код:
// Получим объект
СпрКлиенты = Справочники.Клиенты;
Выборка = СпрКлиенты.Выбрать();
Пока Выборка.Следующий() Цикл
КлиентОбъект = Выборка.ПолучитьОбъект();
Прервать;
КонецЦикла;
// Создадим ОбъектXDTO
клиентыТип = ФабрикаXDTO.Тип("http://v8.1c.ru/8.1/data/enterprise/current-config", "CatalogObject.Клиенты");
клиент = ФабрикаXDTO.Создать(клиентыТип);
// Заполним ОбъектXDTO и сохраним его
ЗаполнитьЗначенияСвойств(клиент,КлиентОбъект);
ИмяФайла = "D:\Temp\сlient.xml";
МойXML = Новый ЗаписьXML;
ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
МойXML.ОткрытьФайл(ИмяФайла, ПараметрыЗаписиXML);
МойXML.ЗаписатьОбъявлениеXML();
ФабрикаXDTO.ЗаписатьXML(МойXML, клиент);
МойXML.Закрыть();
В первой части кода, там, где мы получаем объект, ничего интересного не происходит, мы просто получаем объект (весьма коряво, надо отметить, но для примера пойдёт).
Зато обратите внимание на пространство имен и имя объекта в строчке, где создается объект "клиентыТип". В пространстве имен "
http://v8.1c.ru/8.1/data/enterprise/current-config" должны быть описаны все объекты метаданных конфигурации, в чем вы можете убедиться, если посмотрите его в конструкторе XDTO-пакетов.
Дальше уже знакомая процедура - сохранение объекта в XML.
Вот что получилось у меня:
Цитата
<?xml version="1.0" encoding="UTF-8" ?>
<CatalogObject.Клиенты
xmlns="http://v8.1c.ru/8.1/data/enterprise/current-config"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Ref>b0fc4df2-0a54-11e1-8797-ac728931524e</Ref>
<DeletionMark>false</DeletionMark>
<Code>000000001</Code>
<Description>Тестовый клиент 1</Description>
<ТипКлиента>непоняно</ТипКлиента>
</CatalogObject.Клиенты>
Как видите, тут есть все реквизиты, включая стандартные ("Наименование", "Код"), а также ссылка ("Ref") и пометка на удаление ("DeletionMark").
Естественно, этот файл также можно загрузить обратно в объект. Код, надеюсь, вы уже можете написать сами.
В помощь юному падавану-сериализатору в 1С есть объект "СериализаторXDTO". Он также представлен как "синглтон", доступный в глобальном контексте, и как отдельный тип. В принципе, строки:
// Создадим ОбъектXDTO
клиентыТип = ФабрикаXDTO.Тип("http://v8.1c.ru/8.1/data/enterprise/current-config", "CatalogObject.Клиенты");
клиент = ФабрикаXDTO.Создать(клиентыТип);
// Заполним ОбъектXDTO
ЗаполнитьЗначенияСвойств(клиент,КлиентОбъект);
можно смело заменить на:
// Создадим ОбъектXDTO и заполним его
клиент = СериализаторXDTO.ЗаписатьXDTO(КлиентОбъект);
Код получился короче и работает более корректно. Например, если в справочнике "Клиенты" определены табличные части, то "ЗаполнитьЗначенияСвойств" с их заполнением не справится. А сериализатор - запросто. Теперь, когда (я надеюсь) вы понимаете основные принципы работы XDTO-пакетов, вы запросто разберетесь с тем, что еще можно делать с сериализатором. Да пребудет с вами сила синтакс-помощника. А я продолжу.
XDTO-пакет? [необходимо зарегистрироваться для просмотра ссылки]!К этому моменту вы, наверное, задаете себе (а заодно и мне) вопрос: "Хорошо, ну вот у меня есть описанный в конфигурации тип в XDTO-пакете, есть xml, и все вроде бы хорошо. А что делать, если мне пришел какой-то новый xml, в другом формате, а я хочу работать с ним как с объектом? Опять конфигуратор открывать и описывать там тип?"
Конечно, без описания типа вам не обойтись. Но конфигуратор для этого не нужен. И тут нужно рассмотреть такую замечательную вещь, как xml schemа. XML-cхема - это как раз и есть описание типа, представленное (внимание!) в формате xml.
Давайте сделаем какой-нибудь небольшой XDTO-пакет, что-нибудь вроде этого:

А теперь нажмите на кнопку "Экспорт XML-схемы..." (выглядит как ящик с листиком бумаги и стрелочкой) и сохраните схему в файл address.xsd
У меня получилось вот что:
<xs:schema xmlns:tns="http://www.1c.ru/demos/products2"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.1c.ru/demos/products2"
attributeFormDefault="unqualified" elementFormDefault="qualified">
<xs:complexType name="КлассификаторАдреса">
<xs:sequence>
<xs:element name="Город" type="xs:string"/>
<xs:element name="Улица" type="xs:string"/>
<xs:element name="НомерДома" type="xs:int"/>
<xs:element name="НомерКвартиры" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Теперь удалите этот пакет из конфигурации, будто его и не было.
Попробуем прочитать схему и создать по ней объект. Вот код, который это делает:
ФайлыXSD = Новый Массив();
ФайлыXSD.Добавить("D:\Temp\adderss.xsd");
МояФабрикаXDTO = СоздатьФабрикуXDTO(ФайлыXSD);
адресТип = МояФабрикаXDTO.Тип("http://www.1c.ru/demos/products2", "КлассификаторАдреса");
адрес = МояФабрикаXDTO.Создать(адресТип);
адрес.Город = "Ленинград";
адрес.Улица = "3-я улица Строителей";
адрес.НомерДома = 25;
адрес.НомерКвартиры = 12;
ИмяФайла = "D:\Temp\address.xml";
МойXML = Новый ЗаписьXML;
ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
МойXML.ОткрытьФайл(ИмяФайла, ПараметрыЗаписиXML);
МойXML.ЗаписатьОбъявлениеXML();
МояФабрикаXDTO.ЗаписатьXML(МойXML, адрес);
МойXML.Закрыть();
Здесь мы для разнообразия не стали использовать глобальный объект "ФабрикаXDTO", а создали собственный функцией "СоздатьФабрикуXDTO". Если вы посмотрите в отладчике на нашу фабрику ("МояФабрикаXDTO"), то увидите, что в коллекции пакетов у нее всего два пакета: "http://www.w3.org/2001/XMLSchema" и "http://www.1c.ru/demos/products2", в отличие от "синглтона" "ФабрикаXDTO", где их существенно больше. В качестве бонуса мы получили то, что этот код может быть полностью исполнен на клиенте, так как не зависит от метаданных конфигурации.
На выходе я получил xml-файл, в который был сериализован мой объект:
<?xml version="1.0" encoding="UTF-8" ?>
<КлассификаторАдреса
xmlns="http://www.1c.ru/demos/products2"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Город>Ленинград</Город>
<Улица>3-я улица Строителей</Улица>
<НомерДома>25</НомерДома>
<НомерКвартиры>12</НомерКвартиры>
</КлассификаторАдреса>
Как вы видите, я поработал с объектом и сериализовал его без участия метаданных конфигурации. Таким образом, передавая вместе с xml-файлом также и XML-схему, вы можете быть уверенным, что тот, кто должен его получить, сможет разобраться, что с ним делать, а главное, как.
Пример десериализации приводить не буду, оставляю вам как самостоятельное упражнение.
Напоследок скажу, что можно выгрузить XML-схему всей вашей конфигурации, кликнув правой кнопкой по узлу "XDTO-пакеты". Результат получается поучительный, посмотрите.
Еще: если у вас есть xml-файл, с ним хочется поработать как с объектом, а XML-схему прислать никто не удосужился, вы можете воспользоваться замечательным [необходимо зарегистрироваться для просмотра ссылки]. (У себя я нашел его в папке "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\".) Пользоваться им очень просто: даете ему на вход xml, на выходе получаете xsd. Вообще-то этот xsd не всегда (или вообще никогда?) является файлом сразу же "готовым к употреблению" в 1С, но все равно это существенная помощь в создании XML-схемы.
Как видите, все оказалось достаточно просто.
На этом всёНесмотря на то что статья оказалась неожиданно длинной, нельзя сказать, что все, что здесь описано, претендует на полноту. Пытливый исследователь XML-мира с легкостью напишет целую книгу по каждому абзацу этого небольшого обзора и еще ворох по тому, о чем здесь не сказано. Например, о том, что "вся эта кухня" тесно связана с web-сервисами. Тема обширна, так что дерзайте. Также я могу в чем-то заблуждаться, поэтому пишите комментарии - буду исправлять. Давайте учиться вместе.
А я желаю вам хорошего дня и хорошего кода. До новых встре
[необходимо зарегистрироваться для просмотра ссылки]