среда, 15 февраля 2017 г.

HTTP-сервисы для тех, кто ничего не понимает в WEB

Если вы ничего не понимаете в WEB технологиях и такие слова, как json, get, post и прочее для вас ничего не значат и вы просто заядлый 1С-ник до мозга костей, но вам кровь из носу надо подружить 1С со сторонними приложениями или сайтом, то эта статья для вас
Начну с того, что когда-то я был вынужден самостоятельно разбираться с Web-сервисами. Тогда как-то потихоньку мне удалось освоить это дело и понять, что и куда надо нажать, чтобы все заработало. Благо конфигурация, с которой пришлось работать, уже была напичкана Web-сервисами и можно было подглядеть и сделать по аналогии, а также в интернете мне удалось найти достаточно статей по этому делу. И так, на примерах (для меня это лучший способ изучения), я освоил это дело, и теперь меня они уже не пугают.
После обновления платформы до версии 8.3 мне стало интересно попробовать новые технологии - те самые HTTP-сервисы. Тут уже воспользоваться моим любимым методом - подглядеть, как было сделано раньше, - мне не удалось - объект новый. Полистав интернет, я нашел пару статей самой фирмы 1С и чуток сторонних статей, в которых какая-то информация есть, но написана сложновато (для простого тупого 1С-ника). В итоге на своем опыте, методом проб и ошибок, я чуток приблизился к осознанию, что это за зверь, и хочу поделиться информацией с вами (может, кому-то поможет быстренько что-нибудь сделать, когда горит).
ИТАК. Основной задачей любой интеграции, будь то КД, Web-сервисы или HTTP-сервисы, является что-нибудь откуда-нибудь передать, что-нибудь с этим сделать и вернуть ответ. Вот в таком формате мы и рассмотрим новую технологию.
В дереве метаданных HTTP-сервисы располагаются в ветке Общие: 
Добавляется новый HTTP-сервис точно так же, как и любой другой объект метаданных. Имя и синоним как хотите. Тут важен только "Корневой URL" - это, собственно, и есть идентификатор HTTP-сервиса в данной базе, т.е. именно то, что вы напишете в этом свойстве, вы передадите стороннему разработчику (ну или себе) в качестве ссылки на сервис.
Уж не знаю, можно ли тут писать кириллицей, но чтобы вас в прогрессивном мире не засмеяли, пишите латиницей). 
Дальше переходим на закладку Шаблоны URL и добавляем новый шаблон.
Тут важно само свойство Шаблон:
С помощью шаблона вы впоследствии сможете обратить к тем данным, которые вам передали. ИТАК: все данные, которые вы хотите получить извне, можно разделить на 2 блока - обязательные и не обязательные.
Обязательные данные/параметры запихиваем в шаблон, тем самым если тот, кто обращается к сервису, их не заполнил, то сервис априори выдаст ошибку, а вы при разработке текста модуля обработчика будете уверены, что эти данные есть. Как это делается: в строке Шаблон в фигурных скобках "{}", чередуя с со знаком "/", пишем имена переменных. Например, нам обязательно нужен артикул - тогда пишем /{artikul}. Если нам надо получить артикул, имя и имя пользователя, строка шаблона будет выглядеть так: /{artikul}/{name}/{user} и т.д. Каждый из таких параметров в тексте модуля обработчика можно будет получить так: Запрос.ПараметрыURL["<имя параметра>"]. Если обязательных нет, то шаблон выглядит так: /*.
Не обязательные данные, которые мы хотим получать через сервис, в шаблоне НЕ описываются. При построении ссылки, для обращения к сервису они описываются в конце ссылки после знака "?", разделяются символом амперсанда "&" и имеют структуру <имя параметра>=<значение параметра>. В тексте модуля обработчика к ним можно обратиться конструкцией: Запрос.ПараметрыЗапроса.Получить("<имя параметра>"). НО: важно помнить, раз они не обязательны, то их может и не быть, соответственно значение проверяем на Неопределено.
Далее добавляем новый метод для нашего шаблона. Тут важно свойство HTTP-метод. Их тут огромное количество, НО мы не будем вдаваться во все тонкости. Для реализации любой вашей задачи вам нужны только 2: GET и POST.
Как выбрать: Если того, что мы с вами описали в двух предыдущих абзацах, для работы вам достаточно, т.е. все нужные вам данные вы сможете получить с помощью обязательных и не обязательных параметров самого запроса, то берем GET. В этом случае в любом браузере, если вы правильно введете адресную строку, вы увидите результат действия своего HTTP-сервиса - ПРОФИТ! Если вдруг для работы вашего сервиса нужны данные в более сложном виде (xml например, или еще чего), то, что нельзя запихнуть в простую адресную строку, то берем POST. Из минусов такая легкая проверка через адресную строку браузера, как с GET, не прокатит, но на просторах интернета легко можно найти какие-нибудь сайты, на которых можно проверить сервисы методом POST (например, сайт https://www.hurl.it). В случае, если выбран метод POST, то у запроса помимо URL (адреса) появляется тело, в которое можно запихнуть все, что угодно, а в обработчике метода обратиться к нему через конструкцию Запрос.ПолучитьТелоКакСтроку(). У любого шаблона может быть как GET метод, так и POST. У них будут соответственно разные обработчики, а 1С-ка в зависимости от того, как был отправлен запрос, будет выбирать тот или иной метод.
Обработчик HTTP-сервиса - это функция, которая всегда возвращает значение типа HTTPСервисОтвет, который строится конструктором Новый HTTPСервисОтвет(<КодСостояния>). <КодСостояния> - это число, чтобы не мучаться с выбором что писать, пишем: 200 - если все хорошо и вы возвращаете какое то логичное значение, 400 - если ошибка и вы возврщаете описание ошибки. У данного типа есть различные методы (можно почитать в синтакс помошнике, там все понятно написано). Опять же, всегда можно вернуть все что нужно в виде строки - метод УстановитьТелоИзСтроки(). (одна небольшая хитрость: если вы возвращаете html и хотите чтобы браузер при вводе в адресную строку адреса вашего сервиса на экране красиво отобразил его, в свойстве ответ Заголовки напишите: Ответ.Заголовки.Вставить("Content-Type","text/html; charset=utf-8") - тем самым вы укажите, что это не просто набор символов, а HTML и его надо показать соответствующе)
После того как вы все сделаете, HTTP-сервис надо опубликовать. Делается это на компьютере с установленным веб-сервером (про настройки писать не буду, есть полно статей) через меню:
Администрирование - Публикация на веб сервере.
Там закладка HTTP-сервисы. Ставим галки и нажимаем "Опубликовать"
Ну и, наконец, еще раз в картинках))):

Оригинал: infostart.ru

Недокументированное использование стандартных обработок из меню "Все функции"

Рассмотрены возможности произвольного использования стандартных функций, вызываемых из меню платформы "Все функции" - "Стандартные" (Активные пользователи, Журнал регистрации, Поиск ссылок на объект, Проведение документов ...).
В платформе 1С предприятие есть очень удобные стандартные функции:
1. Активные пользователи;
2. Журнал регистрации;
3. Поиск ссылок на объект;
4. Проведение документов;
5. Удаление помеченных объектов;
6. Управление внешними источниками данных;
7. Управление итогами;
8. Управление полнотекстовым поиском;
9. Управление расширениями конфигурации;
Однако нигде не описаны варианты их использования кроме вызова из пункта "Все функции" главного меню. Поэтому иногда встречается мнение, что эти функции являются чем-то специфичным и сложным, что они вообще написаны не на 1С, а на С++ как и сама платформа. 
На самом деле технически эти функции являются самыми обычными 1С обработками, включенными в состав платформы, и ими можно пользоваться полностью аналогично любым другим привычным обработкам.
Рассмотрим несколько способов их использования на примере стандартной обработки "Поиск ссылок на объекты".
1. Вызов стандартной обработки из любого пункта меню. Обработка "Поиск ссылок на объекты" достаточно удобна и может пригодиться обычным пользователям. Однако не всегда возможно давать им доступ к меню "Все функции" из-за ограниченного уровня доступа пользователя. В этом случае можно добавить вызов обработки из стандартного меню.
Добавляем в конфигурацию новую команду и в модуле команды прописываем текст:
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
    ПодключитьВнешнююОбработкуНаСервере();
    ОткрытьФорму("ВнешняяОбработка.StandardFindByRef.Форма");
КонецПроцедуры

&НаСервере
Процедура ПодключитьВнешнююОбработкуНаСервере()
    ВнешниеОбработки.Подключить("v8res://mngbase/StandardFindByRef.epf", "StandardFindByRef", false);
КонецПроцедуры
При выборе этой команды у пользователя запустится обработка "Поиск ссылок на объекты" из обычного меню. 
2. Подмена стандартной обработки. Допустим, по какой-то причине нас не устраивает стандартная обработка. В этом случае мы можем ее подменить любой другой. Выполняем на сервере следующий код (например в "ПриЗапуске()" конфигурации) и после этого из стандартного меню "Все функции" - "Поиск ссылок на объект" будет вызываться наша собственная внешняя либо встроенная в конфигурацию обработка. 
    ДвоичныеДанные = Новый ДвоичныеДанные("C:\ВнешняяОбработка.epf");
    АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанные); 
    ВнешниеОбработки.Подключить(АдресХранилища, "StandardFindByRef", false);

3. Изменение стандартной обработки. Стандартные обработки очень удобны, однако иногда в них не хватает какой-то мелочи. Например, нам может понадобиться добавить в обработку "Поиск ссылок на объект" фильтр для поиска только по документам. Можно, конечно, написать такую же обработку самостоятельно, а можно просто взять встроенную и немного изменить. Чтобы получить встроенную в виде отдельно файла, выполняем код:
КопироватьФайл("v8res://mngbase/StandardFindByRef.epf","C:\ВнешняяОбработка.epf");
Теперь у нас есть стандартный 1С-ный файл "C:\ВнешняяОбработка.epf" с встроенной обработкой. Его можно открыть в конфигураторе и внести любые нужные изменения. В дальнейшем модифицированную обработку можно использовать просто как внешнюю либо подключить обратно вместо встроеной.
Ну и напоследок соответствие стандартных обработок внутренним адресам платформы.
1. Активные пользователи - "v8res://mngbase/StandardActiveUsers.epf";
2. Журнал регистрации - "v8res://mngbase/StandardEventLog.epf";
3. Поиск ссылок на объект - "v8res://mngbase/StandardFindByRef.epf";
4. Проведение документов - "v8res://mngbase/StandardDocumentsPosting.epf";
5. Удаление помеченных объектов - "v8res://mngbase/StandardDeleteMarkedObjects.epf";
6. Управление внешними источниками данных - "v8res://mngbase/StandardExternalDataSourcesManagement.epf";
7. Управление итогами - "v8res://mngbase/StandardTotalsManagement.epf";
8. Управление полнотекстовым поиском - "v8res://mngbase/StandardFullTextSearchManagement.epf";
9. Управление расширениями конфигурации - "v8res://mngbase/StandardExtensionsManagement.epf";
И еще одна обработочка. Не входит в стандартные, но тоже полезна для ознакомления.
10. Конструктор запросов на управляемых формах - "v8res://mngbase/QueryWizard.epf";
Не стоит забывать, что такое использование стандартных функций является недокументированным. Т.е. на текущий момент на платформах 8.2 - 8.3.6 такие варианты вызовов работают вполне корректно. Но могут перестать работать в любой момент, поэтому злоупотреблять ими не стоит. 
Также стоит учитывать, что в официальных материалах по 1С не документирована возможность простого изменения этих обработок не случайно. Встроенные обработки разрабатываются с учетом функционала текущей платформы. Т.е. они учитывают особенности работы и ограничения той платформы, в состав которой включены. В каких-то случаях, при использовании обработки от другой платформы, могут быть ошибки. Особенно в сложных режимах, например, при удалении документов, управлении итогами или восстановлении последовательностей. Так что использовать эти обработки следует аккуратно, оценивая возможные риски.

Оригинал: infostart.ru

вторник, 14 февраля 2017 г.

Сериализация XDTO (пример)

Сериализатор = Новый СериализаторXDTO(ФабрикаXDTO);
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл("C:\XDTOSample.xml");
ВалютаОбъект = Валюта.ПолучитьОбъект();
Сериализатор.ЗаписатьXML(Запись, ВалютаОбъект);
Запись.Закрыть();


//Запись
СсылкаНаЭлементСправочника = Справочники.Номенклатура.НайтиПоКоду("0000001");
// Создать сериализатор XDTO для глобальной фабрики XDTO
НовыйСериализаторXDTO = Новый СериализаторXDTO(ФабрикаXDTO);
// Создать объект записи XML и открыть файл
НоваяЗаписьXML = Новый ЗаписьXML;
НоваяЗаписьXML.ОткрытьФайл("D:/Exchange.xml");
// Сериализовать ссылку в XML
НовыйСериализаторXDTO.ЗаписатьXML(НоваяЗаписьXML,СсылкаНаЭлементСправочника, НазначениеТипаXML.Явное);


//Чтение
// Создаь сериализатор XDTO для глобальной фабрики XDTO
НовыйСериализаторXDTO = Новый СериализаторXDTO(ФабрикаXDTO);
// Прочитать данные объекта XDTO из файла XML
НовоеЧтениеXML = Новый ЧтениеXML;
НовоеЧтениеXML.ОткрытьФайл("D:/Exchange.xml");
// Сериализовать ссылку из XML
НоваяСсылкаСправочник = НовыйСериализаторXDTO.ПрочитатьXML(НовоеЧтениеXML)

четверг, 9 февраля 2017 г.

XDTO-пакеты. Неименованные типы

В продолжение к посту XDTO-пакеты, xml, xml schema несколько слов о неименованных типах.

Давайте посмотрим, что будет, если в конструкторе XDTO-пакета к свойству добавить определение типа и, в свою очередь, добавить туда еще свойств:

Как видите, свойства "Адрес" и "Телефон" сложного типа ("ОбъектXDTO"). А телефон еще и списковый тип (я задал "Максимальное количество" равное трем).



Вот XML-схема этого пакета:
< xs:schema xmlns:tns="http://www.1c.ru/demos/products"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.1c.ru/demos/products"
attributeFormDefault="unqualified" elementFormDefault="qualified">
   < xs:complexType name="Клиент">
      < xs:sequence>
         < xs:element name="Фамилия" type="xs:string"/>
         < xs:element name="Имя" type="xs:string"/>
         < xs:element name="Адрес">
            < xs:complexType>
               < xs:sequence>
                  < xs:element name="Город" type="xs:string"/>
                  < xs:element name="Улица" type="xs:string"/>
                  < xs:element name="Дом" type="xs:int"/>
               < /xs:sequence>
            < /xs:complexType>
         < /xs:element>
         < xs:element name="Телефон" maxOccurs="3">
            < xs:complexType>
               < xs:sequence>
                  < xs:element name="КодГорода" type="xs:string"/>
                  < xs:element name="Номер" type="xs:string"/>
                  < xs:element name="Добавочный" type="xs:string"/>
               < /xs:sequence>
            < /xs:complexType>
         < /xs:element>
      < /xs:sequence>
   < /xs:complexType>
< /xs:schema>
Вот код, который создает объект этого типа:
    клиентТип = ФабрикаXDTO.Тип("http://www.1c.ru/demos/products", "Клиент");
    клиент = ФабрикаXDTO.Создать(клиентТип);

При создании объекта типа "Клиент" мы получим следующую картину:

Заполнить реквизиты "Фамилия" и "Имя" несложно:
    клиент.Фамилия = "Нуралиев";
    клиент.Имя = "Борис";
Телефоны рассмотрим немного позже, а вот как заполнить реквизит "Адрес"? По логике, это нужно сделать как в примере с номенклатурой и единицами измерения из предыдущей статьи. Создать "ОбъектXDTO" с типом таким же, как у свойства "Адрес". Но у этого типа нет самостоятельного имени, а значит, вызвать "ФабрикаXDTO.Тип(...)", чтобы получить этот самый тип, не получится. Но это не значит, что самого типа нет. Просто он содержится в типе "клиентТип". Давайте посмотрим на него более внимательно:

Как видите, имени у типа нет, но сам объект "ТипОбъектаXDTO" существует. Значит, адрес мы можем заполнить вот таким кодом:
    клиент.Адрес = ФабрикаXDTO.Создать(клиентТип.Свойства.Получить("Адрес").Тип);
    клиент.Адрес.Город = "Москва";
    клиент.Адрес.Улица = "Селезневская";
    клиент.Адрес.Дом = 21;
Теперь и с телефонами ситуация проясняется. Свойство "Телефон" имеет тип "СписокXDTO", а синтакс-помощник говорит, что у этого типа есть метод "Добавить", которому передается "ОбъектXDTO". Вот код, который добавляет телефоны:
    телефонТип = клиентТип.Свойства.Получить("Телефон").Тип;

    нТелефон = ФабрикаXDTO.Создать(телефонТип);
    нТелефон.КодГорода = "495";
    нТелефон.Номер = "737-92-57";
    нТелефон.Добавочный = "*0";
    клиент.Телефон.Добавить(нТелефон);

    нТелефон = ФабрикаXDTO.Создать(телефонТип);
    нТелефон.КодГорода = "495";
    нТелефон.Номер = "681-44-07";
    нТелефон.Добавочный = "*0";
    клиент.Телефон.Добавить(нТелефон);
В итоге я получил вот такой XML:
< ?xml version="1.0" encoding="UTF-8" ?> 
< Клиент xmlns="http://www.1c.ru/demos/products"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  < Фамилия>Нуралиев< /Фамилия> 
  < Имя>Борис< /Имя> 
  < Адрес>
    < Город>Москва< /Город> 
    < Улица>Селезневская< /Улица> 
    < Дом>21< /Дом> 
  < /Адрес>
  < Телефон>
    < КодГорода>495< /КодГорода> 
    < Номер>737-92-57< /Номер> 
    < Добавочный>*0< /Добавочный> 
  < /Телефон>
  < Телефон>
    < КодГорода>495< /КодГорода> 
    < Номер>681-44-07< /Номер> 
    < Добавочный>*0< /Добавочный> 
  < /Телефон>
< /Клиент>
Напоследок хочу подарить вам небольшую рекурсивную процедуру, которая заполняет все свойства вот таких неименованных типов, кроме списковых:
// Заполняет все свойства объектов, которые в качестве типа имеют неименованый тип "ОбъектXDTO"
Процедура ЗаполнитьСвойстваОбъектаXDTO(ОбъектXDTO, тФабрикаXDTO)
    ТипОбъектаXDTO = ОбъектXDTO.Тип();
    Для каждого СвойствоXDTO Из ТипОбъектаXDTO.Свойства Цикл
        флТипНеИменованый = ПустаяСтрока(СвойствоXDTO.Тип.Имя);
        флСвойствоНеСписковое = (СвойствоXDTO.НижняяГраница=1) и (СвойствоXDTO.ВерхняяГраница=1);
        Если флТипНеИменованый и флСвойствоНеСписковое Тогда
            тЗначениеСвойства = тФабрикаXDTO.Создать(СвойствоXDTO.Тип);
            Если Тип(тЗначениеСвойства) = Тип("ОбъектXDTO") Тогда
                ЗаполнитьСвойстваОбъектаXDTO(тЗначениеСвойства, тФабрикаXDTO);
            КонецЕсли;
            ОбъектXDTO.Установить(СвойствоXDTO,тЗначениеСвойства);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры // ЗаполнитьСвойстваОбъектаXDTO
Естественно, вы можете доработать ее по своему вкусу.

Оригинал: http://blog.zfilin.org.ua

XDTO-пакеты, xml, xml schema

С чего начинается?..

С чего начинаются XDTO-пакеты для неискушенного разработчика? Для меня они начались с вопроса: "А что это еще за хренотень в дереве метаданных?" И еще я знал, что это что-то про xml. Но мы начнем не с этого. А с объекта ФабрикаXDTO. Как можно догадаться из названия, это фабрика объектов (XDTO расшифровывается как XML Data Transfer Objects).
Небольшое лирическое отступление. Лучше понять, что такое "фабрика объектов", можно из замечательной книги "Приемы объектно-ориентированного проектирования. Паттерны проектирования" в частности, в разделе о шаблоне "Абстрактная фабрика", или "Фабричный метод". Книга, хочу заметить, действительно стоящая, но мозголомная, скорее формата "справочник", а не "учебник". Вдобавок все, что там написано, сложно применимо к 1С. Когда-нибудь я разозлюсь и напишу здоровенную статью о шаблонах (привет, kote!), а то досадно, что некоторые 1С-программистов даже считать не собираются. Инструмент не должен стоять на пути человека к вершинам профессионализма. Но пока не об этом.
Итак, говоря простым языком, фабрика объектов - это некое "устройство", умеющее принять на входе описание объекта и сгенерировать по этому описанию объект определенного типа, "пригодный к употреблению". Или несколько. То есть это в прямом смысле фабрика: загрузили "чертеж", и она пошла штамповать "продукцию" по "чертежу" (для дотошных: "сырье" в этом случае ваше процессорное время, электричество и т.д.).
Тут я просто вынужден послать вас ознакомиться с хорошей статьёй о простых типах в XDTO с диска ИТС. Если бы это было целесообразно, я бы всю ее скопипастил сюда, но зачем? И все же один пример я оттуда возьму. Для наглядности.
Вот так в статье описывается работа с объектом "Структура":
структурныйТип = ФабрикаXDTO.Тип("http://www.1c.ru/demos/products", "Номенклатура"); 
номенклатура = ФабрикаXDTO.Создать(структурныйТип); 
номенклатура.Наименование = "Ботинки женские"; 
номенклатура.ЗакупочнаяЦена = 1000; 
Для этого примера я бы нарисовал такую диаграмму:
Обратите внимание, что объект "структурныйТип" (т.н. "чертеж") тоже был создан фабрикой, на основании "загадочных" строчек. Рассмотрим, что же это за строчки. Про метод "Тип" объекта "ФабрикаXDTO" синтакс-помощник пишет:
Синтаксис:
Тип(<  URIПространстваИмен>, <  Имя>) 

Возвращаемое значение:
Тип: ТипЗначенияXDTO; ТипОбъектаXDTO; Неопределено. 

Описание:
Получение типа XDTO.
Не слишком информативно. Тем не менее понятно, что на основании какого-то пространства имен и имени типа метод "Тип" создает нам необходимый "чертёж". Про пространства имен можно почитать, например, в статье "Коротко о пространствах имен (XML Namespaces)", или терзайте жужл запросом "xmlns". Вкратце же скажу, что это некая область, в которой вы можете определить свои xml-теги, и они будут означать именно то, что вы в них закладывали при определении. Например, тег < table> в пространстве имен, определяющем HTML-документ, означает описание таблицы, а в вашем собственном он может означать, например, блок описания стола. Чтобы их не путать и нужны пространства имен.
Тут есть очень важный момент, который сначала вводит в заблуждение. Название пространства имен напоминает адрес страницы в интернете, и сразу же хочется посмотреть, что там такое по этому адресу. Так вот. Технически название может быть любым, но разработчики договорились, что все будут использовать в качестве названия пространства имен URL, по которому в интернете находится страница с описанием этого пространства имен, понятным человеку. К тому же так обеспечивается уникальность названий пространств имен, поскольку в интернете не может быть двух страниц с одинаковым адресом. И "ФабрикаXDTO" при генерации типа XDTO, конечно же, не лезет в интернет ни за какими данными. К сожалению, не все соблюдают правило о публикации человеческих описаний (сволочи!), и уж тем более нехорошо использовать адреса на чужих доменах (как в примере). Мало ли какую информацию фирма 1С воткнет со временем на страницу http://www.1c.ru/demos/products. Это может вводить в заблуждение, поэтому в 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-схему прислать никто не удосужился, вы можете воспользоваться замечательным инструментом xsd.exe из .NET Framework. (У себя я нашел его в папке "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\".) Пользоваться им очень просто: даете ему на вход xml, на выходе получаете xsd. Вообще-то этот xsd не всегда (или вообще никогда?) является файлом сразу же "готовым к употреблению" в 1С, но все равно это существенная помощь в создании XML-схемы.

Оригинал: infostart.ru