Как установить значение "Неопределено" для реквизита объекта XDTO в 1С, если схема не позволяет?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Бухгалтерский учет Торговля и дистрибуция
← К списку

При работе с механизмом XDTO (XML Data Transfer Objects) в 1С мы часто сталкиваемся с задачами интеграции и обмена данными с внешними системами. XDTO позволяет нам удобно работать с XML-данными в объектно-ориентированном стиле. Однако, иногда возникает задача установить значение Неопределено для определенного реквизита объекта XDTO, и здесь мы можем столкнуться с неожиданными сложностями.

Основная причина таких сложностей кроется в XML-схеме (XSD), по которой создан XDTO-пакет. Схема определяет строгие ограничения (фасеты) на типы данных, формат и обязательность полей. Если мы попытаемся присвоить Неопределено обязательному полю или полю с жестким ограничением типа, система, как правило, выдаст ошибку, поскольку такое значение будет противоречить правилам схемы.

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

Решение 1: Создание нового объекта XDTO и замещение существующего

Один из наиболее надежных и часто применяемых подходов заключается в том, чтобы не пытаться изменить существующий объект, а создать совершенно новый объект XDTO нужного типа, заполнить его только необходимыми значениями и затем заменить им старый объект. Этот метод позволяет обойти ограничения на изменение уже существующих объектов, сформированных по строгим схемам.

Принцип работы

  1. Мы создаем новый экземпляр объекта XDTO того же типа, что и реквизит, который хотим изменить.
  2. Заполняем этот новый объект только теми реквизитами, которые должны иметь конкретные значения. Реквизиты, которые должны быть "пустыми" или Неопределено, мы просто не трогаем, и они примут значения по умолчанию (или останутся незаполненными, если схема это позволяет).
  3. Присваиваем этот новый, корректно заполненный объект вместо старого.

Рассмотрим пример из практики, когда требовалось изменить адресные данные в объекте XDTO, который был частью более крупной структуры. Прямое изменение реквизитов существующего объекта ExtendedOrganizationInfo.Address не работало, так как объект Address был создан по строгой схеме.

Пример реализации

В данном случае, для создания нового объекта использовалась вспомогательная функция НовыйProtoОбъектXDTO, которая является частью библиотеки КонтурДиадокГенерацияXML. Это типичный пример обертки над стандартным механизмом ФабрикаXDTO.Создать(), который мы можем использовать в общем случае.

Давайте разберем по шагам, как это было реализовано:

  1. Сначала нам нужно получить доступ к модулю, который содержит вспомогательные функции для генерации XDTO-объектов. В данном примере это делается через временное хранилище.
  2. 
    Ядро = ПолучитьИзВременногоХранилища(ОсновнойМодуль.ОбщийКонтекстКлиентСервер.АдресОбработкиЯдра);
    ГенерацияXML = Ядро.ОбработкаОбъект.Модуль_ГенерацияXML(Ядро);
    

    Здесь Ядро и ГенерацияXML являются объектами, предоставляющими доступ к необходимым функциям.

  3. Затем мы создаем новый "прото-объект" XDTO нужного типа. В нашем случае это тип AddressInfo.
  4. 
    НовыйОбъектXDTO = ГенерацияXML.НовыйProtoОбъектXDTO("AddressInfo", Ложь);
    

    Функция НовыйProtoОбъектXDTO создает объект XDTO, который изначально имеет значения по умолчанию для всех своих реквизитов. Если реквизит может быть пустым, он будет пустым.

  5. Теперь мы заполняем только те поля нового объекта, которые должны иметь конкретные значения. Остальные поля, которые должны быть "неопределенными" или пустыми, мы просто не трогаем.
  6. 
    УстановитьЗначениеXDTO(НовыйОбъектXDTO, "IsForeign"    , Истина);
    УстановитьЗначениеXDTO(НовыйОбъектXDTO, "CountryCode"  , "643");
    УстановитьЗначениеXDTO(НовыйОбъектXDTO, "AddressText"  , НовыйАдрес);
    

    Функция УстановитьЗначениеXDTO (или аналогичная) используется для присвоения значений реквизитам объекта XDTO. Мы видим, что заполняем только IsForeign, CountryCode и AddressText. Если, например, в AddressInfo есть другие реквизиты, которые не были заполнены, они останутся в своем исходном состоянии (например, Неопределено или значение по умолчанию, если оно задано в схеме).

  7. Наконец, мы присваиваем этот новый, корректно заполненный объект XDTO в качестве значения реквизита родительского объекта.
  8. 
    ExtendedOrganizationInfo.Address = НовыйОбъектXDTO;
    

    Таким образом, мы эффективно "обновили" адресные данные, избежав прямых манипуляций с существующим объектом, которые могли бы нарушить ограничения схемы.

    Этот подход является наиболее рекомендуемым, так как он соответствует объектно-ориентированной парадигме и обходит сложности, связанные с изменением уже сформированных по строгим правилам объектов.

    Решение 2: Работа с XML без указания схемы при десериализации

    Второй подход, который может быть полезен в определенных сценариях, связан с более низкоуровневой работой с XML-представлением объекта XDTO. Этот метод позволяет нам временно "отключить" проверку схемы, чтобы модифицировать данные.

    Принцип работы

    1. Сериализуем наш объект XDTO в XML-файл или строку.
    2. Десериализуем полученный XML обратно в объект XDTO, но при этом не указываем схему. Это позволяет нам получить объект, который не связан со строгими правилами XSD.
    3. В этом "свободном" объекте мы можем "зачистить" или изменить нужные поля, присвоив им, по сути, Неопределено или пустые значения.
    4. Затем мы сериализуем модифицированный объект обратно в XML, а затем десериализуем его уже с указанием исходной схемы, если это необходимо для дальнейшей работы.

    Важный нюанс: при таком подходе следует быть особенно внимательными. Как отмечают опытные разработчики, при сохранении и последующем чтении XML без схемы, некоторые элементы могут измениться. Например, если в схеме был список с одной строкой, он может быть сохранен не как список, а как какой-то одинарный тип. Это может привести к нежелательным побочным эффектам, поэтому используйте этот метод с осторожностью и обязательно проводите тщательное тестирование.

    Пример концепции

    Давайте посмотрим на общую идею без конкретного кода, так как это более сложный и менее универсальный путь:

    
    // 1. Сериализуем исходный объект XDTO в XML-строку
    СтрокаXML = ФабрикаXDTO.ЗаписатьXML(ИсходныйОбъектXDTO);
    
    // 2. Создаем временную фабрику XDTO без привязки к схеме (или используем глобальную без загруженных схем)
    // Или просто читаем XML без указания типа
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(СтрокаXML);
    
    // 3. Читаем XML, получая объект, который не привязан к строгой схеме
    // Это может быть объект типа "ПроизвольныйОбъектXDTO" или подобный,
    // который позволяет более свободно манипулировать данными.
    ОбъектXDTOБезСхемы = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
    
    // 4. Модифицируем необходимые поля в ОбъектXDTOБезСхемы
    // Например, удаляем элемент или присваиваем ему пустую строку,
    // если это соответствует желаемому "Неопределено"
    // ОбъектXDTOБезСхемы.РеквизитДляОчистки = ""; // Или удаляем элемент, если это возможно через методы XDTO
    
    // 5. Сериализуем модифицированный объект обратно в XML-строку
    МодифицированнаяСтрокаXML = ФабрикаXDTO.ЗаписатьXML(ОбъектXDTOБезСхемы);
    
    // 6. Если необходимо получить объект, соответствующий исходной схеме,
    // десериализуем его снова, но уже с указанием схемы.
    // ОбъектXDTOСноваПоСхеме = ФабрикаXDTO.ПрочитатьXML(МодифицированнаяСтрокаXML, ИмяТипаПоСхеме);
    

    Этот метод требует глубокого понимания структуры XML и потенциальных изменений при сериализации/десериализации без схемы. Рекомендуем использовать его только в крайних случаях, когда первый подход не применим.

    Дополнительные советы и нюансы при работе с XDTO

    Давайте проанализируем некоторые важные аспекты работы с XDTO, которые помогут нам лучше понять проблему и ее решения.

    1. Свойство ВозможноПустое (nillable) в XSD

      В XML-схеме существует атрибут xsd:nillable. Если для свойства установлено xsd:nillable="true", это означает, что элемент может быть представлен в XML как <elem xsi:nil="true"/>. В 1С это соответствует свойству ВозможноПустое для объекта СвойствоXDTO. Если мы хотим явно указать отсутствие значения, это может быть одним из способов. Однако, это не то же самое, что присвоить Неопределено в 1С, и требует поддержки со стороны схемы и внешних систем.

    2. Проверка наличия свойств без использования Попытка

      Для того чтобы проверить, заполнено ли свойство XDTO или существует ли оно, не прибегая к конструкции Попытка-Исключение, мы можем использовать метод Свойства().Получить("ИмяРеквизита") объекта XDTO. Если метод возвращает Неопределено, это означает, что такого свойства нет или оно не заполнено.

      
      СвойствоXDTO = ОбъектXDTO.Свойства().Получить("ИмяРеквизита");
      Если СвойствоXDTO = Неопределено Тогда
          // Свойства нет или оно не заполнено
          Сообщить("Свойство 'ИмяРеквизита' отсутствует или не заполнено.");
      Иначе
          // Свойство существует и содержит значение
          Значение = ОбъектXDTO.ПолучитьЗначение(СвойствоXDTO);
          Сообщить("Значение свойства 'ИмяРеквизита': " + Значение);
      КонецЕсли;
      
    3. Сложности с сериализацией/десериализацией null

      Существуют известные сложности при сериализации и десериализации "null" значений через механизм XDTO. Для передачи null в веб-сервисах может использоваться специальный тип Null из пространства имен http://v8.1c.ru/8.1/data/core. Однако, его совмещение с другими примитивными типами может потребовать дополнительной обработки и внимательности.

    Мы рассмотрели несколько подходов к решению проблемы установки значения Неопределено для реквизитов объекта XDTO. Наиболее универсальным и безопасным является создание нового объекта и его замещение. Второй метод, связанный с манипуляциями XML без схемы, требует большей осторожности и понимания потенциальных рисков. В любом случае, глубокое понимание XML-схемы и особенностей работы ФабрикаXDTO является ключом к успешной интеграции и обмену данными.

    ← К списку