среда, 16 ноября 2011 г.

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
Естественно, вы можете доработать ее по своему вкусу.

На сегодня на этом все, а вам я желаю хорошего дня и хорошего кода.

37 комментариев:

  1. Столкнулся с такой проблемой: если у типа элемента схемы с типом определенным в самой схеме не указать префикс "tns:" то у созданного объекта XDTO отсутствуют свойства.
    Пример:

    ОтветитьУдалить
  2. Этот комментарий был удален автором.

    ОтветитьУдалить
  3. Этот комментарий был удален автором.

    ОтветитьУдалить
  4. xs:element name="АдрОрг" type="tns:АдрТип"
    xs:complexType name="АдрТип"

    ОтветитьУдалить
  5. Любопытно. Обязательно указывать префикс? Теперь понятно почему у меня не получались такие вещи.

    ОтветитьУдалить
  6. Здравсвуйте!

    Ваша статья очень помогла, спасибо!

    Только вот Ваш пример:
    телефонТип = клиентТип.Свойства.Получить("Телефон").Тип;

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

    У меня не сработал, пришлось в СписокXDTO добавлять элементы:
    НовТелефон = Фабрика.Создать(телефонТип);
    НовТелефон.phone.Добавить("79261111111");
    Сообщение.phones = НовТелефон;

    Т.е. проведем аналогию:
    У Вас: НовТелефон.phone = "7921111111";
    У Меня: НовТелефон.phone.Добавить("79261111111");

    Еще раз спасибо!

    ОтветитьУдалить
  7. В моем примере списочным типом является поле "клиент.Телефон".
    Такое ощущение, что у вас список это не "клиент.Телефон", а "клиент.Телефон.Номер" или, говоря языком вашего примера, "НовТелефон.phone" это список.

    Хотя, возможно что-то поменялось с релизом платформы. Не могли бы вы сообщить номер релиза платформы и прислать cf-файл?

    ОтветитьУдалить
  8. Спасибо большое автору, статья очень помогла разобраться. Грамотно написано и ничего лишнего.

    ОтветитьУдалить
  9. Огромное спасибо, несколько дней логову ломал, а тут все отлично написано

    ОтветитьУдалить
  10. Два вопроса:
    1. Что за окно на скриншотах "Выражение". Как его отыкрыть?

    2. Как настроить xdto так, чтобы можно было в объекте сохранять неограниченное число сделющих узлов:
    <param name="paramName">paramValue</param>
    или
    <paramName>paramValue</paramName>

    т.е. какие сущности в дереве xdto создать и какие им назначить свойства?

    ОтветитьУдалить
  11. "Выражение" это отладка. Делаете точку останова и жмете Shift+F9.

    По неограниченному количеству узлов - это списки. Посмотрите как создаются телефоны в примере, так же ваши списки.

    ОтветитьУдалить
  12. Это механизм при Записи в XML. А как работать с неименованными типа при чтении из файла XML?

    ОтветитьУдалить
  13. При чтении работать точно так же. Загружаете XML и смотрите отладчиком (или как вам нужно) на тип в XDTO.

    ОтветитьУдалить
  14. Огромное спасибо) очень помог)

    ОтветитьУдалить
  15. Этот комментарий был удален автором.

    ОтветитьУдалить




  16. s:complexType mixed="true"
    s:sequence
    s:any/
    /s:sequence
    /s:complexType
    /s:element


    А как быть в такой ситуации, не понимаю, что записывать в any

    ОтветитьУдалить
  17. Этот комментарий был удален автором.

    ОтветитьУдалить
  18. подскажи пожалуйста. не могу победить так называемый __content

    нужно считать строку типа

    header guid_station="пример1">Значение1 /header

    делаю схему

    xs:complexType name="header"
    xs:simpleContent
    xs:extension base="xs:string"
    xs:attribute name="version_xmlfile" type="xs:string" use="required"/
    /xs:extension
    /xs:simpleContent
    /xs:complexType

    при создании xml все происходит отлично. в цикле он видит __content как элемент массива
    СтрокаHEAD.guid_station = "Зн1";
    СтрокаHEAD.__content = "Зн2";

    а вот при считывании xml - отказывается его видеть. что не так делаю?

    ОтветитьУдалить
  19. Недавно сталкивался с похожими трудностями, залейте пожалуйста xml, который вы пытаетесь читать на http://pastebin.ru/
    А-то тут в сообщениях сложно понять.

    ОтветитьУдалить
  20. с этой фигней разобрался вроде. в чем был прикол. при вызове
    ОбXDTO = ФабрикаXDTO.ПрочитатьXML(МойXML, ФабрикаXDTO.Тип("http://www.obzhora.test.ua", "data"));
    обязательно нужно указывать главный тег - data у меня к тому же в файле xml у него должно стоять пространство имен

    иначе не срабатывает. однако теперь я начал тестировать на рабочем примере и начали вылазить другие интересные вещи. так теперь если какого-то свойства или тега не хватает - он вылетает в ошибку. можно ли где-то указать ему какие свойства не обязательно загружать?

    ОтветитьУдалить
  21. Этот комментарий был удален автором.

    ОтветитьУдалить
  22. с этой фигней разобрался вроде. в чем был прикол. при вызове
    ОбXDTO = ФабрикаXDTO.ПрочитатьXML(МойXML, ФабрикаXDTO.Тип("http://www.obzhora.test.ua", "data"));
    обязательно нужно указывать главный тег - data у меня к тому же в файле xml у него должно стоять пространство имен
    data xmlns="http://www.obzhora.test.ua" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    иначе не срабатывает. однако теперь я начал тестировать на рабочем примере и начали вылазить другие интересные вещи. так теперь если какого-то свойства или тега не хватает - он вылетает в ошибку. можно ли где-то указать ему какие свойства не обязательно загружать?

    ОтветитьУдалить
  23. все - вопрос снят) извини за беспокойство - я поболтал тут сам с собой)
    все необязательные реквизиты ставим minOccurs="0" и все теги где встречаются атрибуты делаем через __content и все хорошо)
    надеюсь кому-то пригодится

    ОтветитьУдалить
  24. Хорошо, когда сам спросил и сам себе ответил.
    Спасибо, что описали решение, думаю, может пригодится уважаемым читателям.
    Про пространства имен, я бы рекомендовал ознакомится с публикацией, посвященной XPath - http://infostart.ru/public/280340/
    Там хорошо разбирается тема пространств имен и упоминаются некоторые неприятные особенности.

    ОтветитьУдалить
  25. за XPath спасибо большое - очень позновательно.
    тут еще выскочил вот какой прикол. у меня ругается если теги расставлены не в том порядке, в схеме вот так
    xs:element name="INVOICEPARTNER" type="tns:gln" minOccurs="0"/
    xs:element name="SENDER" type="tns:gln"/
    xs:element name="RECIPIENT" type="tns:gln"/
    xs:element name="EDIINTERCHANGEID" type="tns:edi-interchange-id" minOccurs="1"/

    а в файле

    RECIPIENT>98635277286329863527728632</SENDER
    можно ли как-то это обойти?

    ОтветитьУдалить
  26. Если я правильно понял, то речь о нарушении порядка закрытия тэгов. Вроде:
    (тэг1)(тэг2)что-то(/тэг1)(/тэг2)

    Это основа основ декларации XML. Такой порядок будет не валидным в любой схеме. Обойти - разбор xml вручную, как текста, при помощи strpos (Найти).
    Если и есть какой-то "трюк" на эту тему, то я его не знаю и не рекомендую. Требуйте соблюдения стандартов, они писались не просто так.

    ОтветитьУдалить
  27. Нет нет. как всегда в сообщении часть данных потерялась.
    Я имел ввиду что построение тегов в схеме такого плана
    ГлавТег
    Тег1
    Тег2
    Тег3

    а в xml файлике может прийти чтото вроде такого
    ГлавТег
    Тег2
    Тег3
    Тег1

    то есть файл корректный с точки зрения XML и данные там все вроде как есть. но если у меня Тег1 - обязательный, а он сразу его не находит - выбрасывает в ошибку.
    надеюсь в этот раз понятней описал проблему.

    причем забавный нюанс. если я считываю XML вот так:
    ОбXDTO = ФабрикаXDTO.ПрочитатьXML(МойXML, ФабрикаXDTO.Тип("http://www.моясхема.ua", ГлавТег));
    то он все читает, но только если схема составлена идеально - соблюден порядок, прописаны какие теги необязательны и т.д.
    а если в Типе Фабрики Указываем имя от "балды" то читает все отлично, даже если теги местами переставить, однако не видит __content
    ОбXDTO = ФабрикаXDTO.ПрочитатьXML(МойXML, ФабрикаXDTO.Тип("http://www.моясхема.ua", "какая то херня"));

    ОтветитьУдалить
  28. Для произвольного порядка элементов в типе вместо xs:sequence используйте xs:all

    ОтветитьУдалить
  29. А каким образом Сделать так:
    < Телефоны>
    < Телефон>
    < КодГорода>495< /КодГорода>
    < Номер>737-92-57< /Номер>
    < Добавочный>*0< /Добавочный>
    < /Телефон>
    < Телефон>
    < КодГорода>495< /КодГорода>
    < Номер>681-44-07< /Номер>
    < Добавочный>*0< /Добавочный>
    < /Телефон>
    < /Телефоны>

    ОтветитьУдалить
  30. Вопрос в подходящей для вашего случая схеме. В схеме сделайте тип "Телефоны" списочным (максимальное количество элементов -1) и все получится.

    ОтветитьУдалить
  31. То есть надо сделать тип "Телефоны", в нем разместить "Телефон"? А как мне потом их оттуда доставать? Я вчера голову сломал - так и не понял как это делатся.

    ОтветитьУдалить
  32. Этот комментарий был удален автором.

    ОтветитьУдалить
  33. Не совсем понял, как и что добавить в схему....

    ОтветитьУдалить
  34. Я добавляю в схему "телефоны", создаю там "определение типа", потом "телефон", в котором тоже "определение типа", а дальше реквизиты нужные. Не могу сообразить, как это все великолепие собрать в xml.

    ЗЫ Если возможно, огромная просьба - можно по скайпу пообщаться? Мой скайп daniil_ivanoff

    ОтветитьУдалить
  35. Огромное спасибо за статью!!! Все просто и понятно

    ОтветитьУдалить
  36. Ребята, спасибо. Помогло. Здоровья вам.

    ОтветитьУдалить
  37. Приятно знать, что статья написанная так давно до сих пор кому-то помогает.
    А, пожалуйста!

    ОтветитьУдалить

Примечание. Отправлять комментарии могут только участники этого блога.