Основой работы является принцип создания экземпляров данных на основании метаданных, т.е. так же, как в "обычной" 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, ибо они полны, точны и актуальны, и вообще труЪ.