Основой работы является принцип создания экземпляров данных на основании метаданных, т.е. так же, как в "обычной" 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, ибо они полны, точны и актуальны, и вообще труЪ.
Коллеги, у меня одного картинка задвоилась, или это реально так?
(1)
у меня норм
(2) и вот такой ерунды, как на скриншоте, не наблюдается?
(3) не наблюдается
Еще есть вариант отображения
(5)У меня также
(3)
Не — все прям норм )
Короче руки у меня кривые, или браузер… Печаль… Спасибо, коллеги, а то даже проверить было не на чем.
Поправка: в строке кода
типПакет=ФабрикаXDTO.Пакеты.Получить().КорневыеСвойства.Получить(«ПакетПредложений»).Тип;
естественно Пакеты.Получить(<НомерПакетаИлиУРИ>)
Доступно написано, спасибо.
как хранить xsd схему в общих макетах ? для мобильного приложения
(11) Можно как файл, можно как текстовый макет; без разницы. Она по сути есть плоский текст, не более. А дальше прочитать из макета, загнать в DOM, оттуда в построитель схем ХМЛ, метод СоздатьСхемуXML и всё.
(12)
На моей картинке только несколько вариантов, можно пример с двоичными данными ?
(13) Да без разницы, двоичные или нет.
Показать
Спасибо за статью.
У меня такой вопрос, можно ли каким-то образом дополнить стандартную фабрику XTDO дополнительным пакетом «на лету»? Например, загрузить дополнительную схему xsd из макета.
На сколько я знаю, нет. Но может быть я ошибаюсь…
(15) Первое, что приходит в голову, это вывалить схему в файл, тупо его покрыжить как текст, вставив в нужное место нужный блок, и прочитать обратно. Но это всё равно не «стандартная фабрика», а новую фабрику делать придётся на основании этой дополненной схемы.
Следует отметить, что в реализации XDTO есть проблемы, некоторые валидные XSD-схемы оно не понимает, и в этом случае понять, что не так, достаточно сложно. Например, обсуждение здесьhttps://forum.mista.ru/topic.php?id=840840
(16) С новой то фабрикой все понятно. Я имел в виду именно основную. Но похоже нет такой возможности
Не соглашусь насчёт «полноты» и «тру». Если бы кто-то занимался плотно хдто, он давно бы озвучил в своих статьях, что у платформы 1С есть большие проблемы.
* Определяем тип объекта, реквизит и значение по умолчанию для него. Создаём объект. Видим в окне отладки, что реквизиту присвоено дефолтное значение. Сериализуем в json — реквизита нет (в xml не проверял, но думаю, так же). Нет его потому, что значение по умолчанию просто показывается нам в окне отладки, но на самом деле не присваивается реквизиту полноценно. Ошибка зарегана в 1С для рассмотрения. Не знаю уж, примут или нет.
* Создаём пустой список xdto, сериализуем в json. Списка нет. Вообще.
* Окей, может это проблема сериализации? Определяем пустой массив в соответствии с RFC8259: «array»:[] Пытаемся его десериализовать в объект с реквизитом-списком: ошибка. Говорит, странное окончание тега в районе «]».
* Сейчас точно не вспомню, но есть сложности с сериализацией/десериализацией «null».
Открытые типы, как верно было сказано, ставят крест на десериализации. У вас описана схема, вы по ней работаете год и тут бац — механизм накрылся. Смотрим — новое св-во зашло в объект. Или вдруг целое значение стало дробным. По хорошему, поставщикам API нужно версионировать схемы и предоставлять возможность подписки на эти изменения, чтобы пользователи схемы имели время перестроить свои системы на новую версию к сроку её включения. Но это уже не проблемы платформы…
(17) О дааа. Сколько я мучился, пытаясь в своё время скормить схему, валидную с точки зрения других приложений, 1С — это была песня. Экспериментально выявил ряд мест, которые 1С не нравятся, но иногда из-за них надо по смыслу курочить схему, поэтому упс.
Согласен.
(18) Похоже, нет. Это всё равно что новый объект в метаданные «на лету» добавлять. Может, сборка/разборка в файлы и даст эффект, но всё равно костыль, а других вариантов не вижу.
(19) Согласен.
1. Да, есть такой эффект, потому и написал, что отладчику веры нет.
2. В хмл одно время была та же фигня, не проверял, есть ли такое в наши дни.
3. А вот на скобку у меня не жаловался. Какие были свойства у этого списка в хдто-пакете? Было разрешено, что он с 0 элементов, пустой?
4. Был какой-то релиз 8.3.8, который литерал null чуть ли не как директиву воспринимал. Других эффектов не помню.
(23) ну красота, что тут скажешь… спасибо за информацию.