Каталог решений - Практика XDTO. Нюансы

Практика XDTO. Нюансы

Практика XDTO. Нюансы

В наличии

Некоторые практические моменты работы с XDTO. Дополнения к очевидному.

Категория:

Описание

Основой работы является принцип создания экземпляров данных на основании метаданных, т.е. так же, как в "обычной" 1С. Метаданными выступают XDTO-пакеты, в которых прописаны типы и свойства объектов, допустимые значения, форматы значений, словом — та же конфигурация (недаром и саму конфигурацию можно выгрузить в xsd, а по утверждениям некоторых, 1С так внутри себя и работает). Экземплярами выступают конкретные XDTO-объекты и значения. Созданием и управлением всем этим занимаются фабрики XDTO, а если речь идёт о встроенных объектах 1С, то ещё сериализаторы. И об объектах, и о свойствах, и о фабриках есть множество хороших статей, поэтому баянить не буду, а обозначу некоторые тонкости, которые недостаточно освещены. Поскольку в чести последнее время практика, то ею и займёмся, а теория — в другой раз.

Для работы нужны: пространство имён, в пределах которого уникальны имена метаданных, и фабрика, в пакеты которой входят все нужные описания всех типов, их форматов и допустимых значений.

Фабрики или создают "по месту", или используют синглтон ФабрикаXDTO. Основное их различие при этом — наборы пакетов, которые у этих фабрик будут в доступности.

Пространства имён обычно получают так:

УРИ=Метаданные.ПакетыXDTO.<ИмяВашегоПакета>.ПространствоИмен; // если он встроен в метаданные
// или
УРИ=ФабрикаXDTO.Пакеты.Получить(УРИилиНомерВашегоПакета).URIПространстваИмен; // в общем случае

Создание экземпляра по метаданным это, как мы знаем:

хдтоОбъект=ФабрикаXDTO.Создать(хдтоТип);

Но откуда берётся сам тип? В простейшем случае он описан и получается по имени и пространству имён, например:

 

 

Тип напрямую чётко указан и так же просто берётся:

типКонтрагент=ФабрикаXDTO.Тип(УРИ,"Контрагент");

Возможна следующая ситуация, когда тип не самостоятелен, а описан в свойстве:

 

 

В этом случае тип следует получать из свойства исходного типа, а если у этого свойства есть своё определение, то разыменовывая из него:

типСтавкиНалогов=ФабрикаXDTO.Тип(УРИ,"Товар").Свойства.Получить("СтавкиНалогов").Тип;
типСтавкаНалога=ТипСтавкиНалогов.Свойства.Получить("СтавкаНалога").Тип;

Типизация некоего свойства может указывать на корневое:

 

 

Аналогично, тип для создания экземпляра получаем из свойства:

типПакет=ФабрикаXDTO.Пакеты.Получить(<УРИилиНомерВашегоПакета>).КорневыеСвойства.Получить("ПакетПредложений").Тип;

также, если значение есть, можно вытащить из него:

типХДТО=ОбъектИлиЗначение.Тип;

Ещё, работая с дочерними полями, удобно использовать метод ВладеющееСвойство().

 

И вот, мы можем создать наш объект: хдтоОбъект=ФабрикаXDTO.Создать(типОбъекта).

Свойствам (реквизитам, так сказать) этого объекта присваиваются значения. Каковы они, мы можем узнать из изучения пакета, объявленных там типов, их фасетов и ограничений (желающим ненавязчиво советую мою обработку-браузер XDTO). Если идут ссылки на другие пакеты, то проверьте, чтоб они были в вашей фабрике. Также следите, чтобы пространства имён были бы объявлены чётко и явно, см. чуть ниже).

С присвоением свойств есть несколько тонкостей.

Во-первых, вроде бы подходящее значение "не лезет" — или ругается при присвоении, или при сериализации в строку бредово выглядит, или ресурс, которому такой хмл пихают, обижается. Помогает предельно скрупулёзное следование типизации:

// вместо
хдтоТовар.Артикул=СокрЛП(Артикул);
// если объявлен тип, то надо так:
хдтоТовар.Артикул=ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(УРИ,"АртикулТип"),СокрЛП(Артикул));

Во-вторых, реквизиты, имеющие списочный тип (список XDTO может начинаться с 0, с 1, с любой мин.границы, но всегда верхняя будет -1) — так вот списочные иногда требуют создания промежуточной переменной-списка:

// простой случай
хдтоОбъект.СписочноеСвойство.Добавить(хдтоЭлементСписка);
// через объект-коллекцию
хдтоСписок=ФабрикаXDTO.Создать(типСписка);
хдтоСписок.СписочноеСвойство.Добавить(хдтоЭлементСписка);
хдтоОбъект.СписочноеСвойство=хдтоСписок;

и иногда это единственно верный вариант.

В третьих, наивно ожидать от просмотра в отладчике, что вам откроется истина. В огромном количестве случаев значения реквизитов объекта будут пусты, а их тип "Неопределено", и вы ничего не поймёте. Поэтому — смотрите объявления в пакете, смотрите свойства. Наиболее важны для объектов — базовый тип, упорядоченность, смешанность; для свойств — тип и возможность пустого. Не верьте отладчику.

 

Некоторые сетуют, что-де формат XDTO есть данность и её не расширить. Это не совсем так, и этим пакеты отличаются от метаданных 1С. Если тип объекта имеет свойство "Открытый" = Истина, то можно прямо на лету добавлять всё, что заблагорассудится, в рамках допустимых типов, конечно:

знч=ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(УРИ,"СтрокаТип"),"Добавляю, как хочу");
хдтоОбъект.Добавить(ФормаXML.Элемент,УРИ,"МоеДопПоле",знч);
//
// и будет это <МоеДопПоле>Добавляю, как хочу</МоеДопПоле>	

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

 

Когда объект создан, его можно записать в реквизит некоего "старшего" объекта, или добавить в коллекцию однотипных собратьев. Можно и просто засунуть в нужное место хмл-текста. Прямо целиком. Например:

// в этом примере УРИ взято из CML 2.Х
Запись=Новый ЗаписьXML;
Запись.УстановитьСтроку("UTF-8");
Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("КоммерческаяИнформация");
ФабрикаXDTO.ЗаписатьXML(Запись,хдтоКонтрагент,,УРИ,ФормаXML.Элемент,НазначениеТипаXML.Неявное);

Тут есть тонкость, связанная с пространством имён и локальными именами. Третьим параметром рекомендую указывать локальное имя, если оно есть или возможен конфликт с контекстом, куда пихается хдто. Для экземпляров "старших" типов оно совпадает с именем типа, для остальных можно получать его через ВладеющееСвойство() или Свойство.

А вот с пространством имён сложнее. У 1С всегда есть пространство по умолчанию, и пишется оно в xmlns без префикса. И вот если, впихивая хдто в ЗаписьХМЛ, вы его не укажете, то оно будет дописано в тег сериализованного экземпляра, т.е. в нашем случае <Контрагент xmlns="urn:1C.ru:commerceml_2">. Если тегу, в который вносится хдто, указать пространство имён в виде 

Запись.ЗаписатьНачалоЭлемента("КоммерческаяИнформация", УРИ);

то 1С сгенерирует явный префикс и всё вложенное пустит с уточнением, какое это пространство имён:

<d1p1:КоммерческаяИнформация xmlns:d1p1="urn:1C.ru:commerceml_2">
и все вложенные без конкретизации будут идти с ним же: <d1p1:Контрагент>

Поэтому рекомендую и при обычной, и при смешанной записи хдто в хмл явно указывать сопоставления, например:

Запись.ЗаписатьСоответствиеПространстваИмен("","urn:1C.ru:commerceml_2"); // так делается УРИ по умолчанию
Запись.ЗаписатьСоответствиеПространстваИмен("xsi","http://www.w3.org/2001/XMLSchema-instance");

ну и так далее.

Кстати, превращение хдто в хмл, а его в текст, и затем ЗаписатьБезОбработки — тоже полезная штука, но тут примеров и без меня полно.

Читать экземпляры, между прочим, тоже можно с произвольного места хмл-текста, чередуя с обычным чтением хмл:

Пока Чтение.Прочитать() Цикл
	Если Чтение.ЛокальноеИмя="НужноеНам" Тогда // например, так нашли нужное
		хдтоОбъект=ФабрикаXDTO.ПрочитатьXML(Чтение,типОбъекта); Прервать
	КонецЕсли;
КонецЦикла;

 

Собственно, всё. Ну и советую не забывать про хдтоОбъект.Проверить(), иногда реально ловит невалидные и незаметные ситуации.

Советую всем статьи Evil Beaver’a, ибо они полны, точны и актуальны, и вообще труЪ.

has been added to your cart:
Оформление заказа