При работе с механизмом XDTO (XML Data Transfer Objects) в 1С мы часто сталкиваемся с задачами интеграции и обмена данными с внешними системами. XDTO позволяет нам удобно работать с XML-данными в объектно-ориентированном стиле. Однако, иногда возникает задача установить значение Неопределено для определенного реквизита объекта XDTO, и здесь мы можем столкнуться с неожиданными сложностями.
Основная причина таких сложностей кроется в XML-схеме (XSD), по которой создан XDTO-пакет. Схема определяет строгие ограничения (фасеты) на типы данных, формат и обязательность полей. Если мы попытаемся присвоить Неопределено обязательному полю или полю с жестким ограничением типа, система, как правило, выдаст ошибку, поскольку такое значение будет противоречить правилам схемы.
В этой статье мы подробно разберем, как обойти это ограничение и успешно установить требуемое "пустое" значение для реквизита объекта XDTO, используя различные подходы.
Один из наиболее надежных и часто применяемых подходов заключается в том, чтобы не пытаться изменить существующий объект, а создать совершенно новый объект XDTO нужного типа, заполнить его только необходимыми значениями и затем заменить им старый объект. Этот метод позволяет обойти ограничения на изменение уже существующих объектов, сформированных по строгим схемам.
Неопределено, мы просто не трогаем, и они примут значения по умолчанию (или останутся незаполненными, если схема это позволяет).Рассмотрим пример из практики, когда требовалось изменить адресные данные в объекте XDTO, который был частью более крупной структуры. Прямое изменение реквизитов существующего объекта ExtendedOrganizationInfo.Address не работало, так как объект Address был создан по строгой схеме.
В данном случае, для создания нового объекта использовалась вспомогательная функция НовыйProtoОбъектXDTO, которая является частью библиотеки КонтурДиадокГенерацияXML. Это типичный пример обертки над стандартным механизмом ФабрикаXDTO.Создать(), который мы можем использовать в общем случае.
Давайте разберем по шагам, как это было реализовано:
Ядро = ПолучитьИзВременногоХранилища(ОсновнойМодуль.ОбщийКонтекстКлиентСервер.АдресОбработкиЯдра);
ГенерацияXML = Ядро.ОбработкаОбъект.Модуль_ГенерацияXML(Ядро);
Здесь Ядро и ГенерацияXML являются объектами, предоставляющими доступ к необходимым функциям.
AddressInfo.
НовыйОбъектXDTO = ГенерацияXML.НовыйProtoОбъектXDTO("AddressInfo", Ложь);
Функция НовыйProtoОбъектXDTO создает объект XDTO, который изначально имеет значения по умолчанию для всех своих реквизитов. Если реквизит может быть пустым, он будет пустым.
УстановитьЗначениеXDTO(НовыйОбъектXDTO, "IsForeign" , Истина);
УстановитьЗначениеXDTO(НовыйОбъектXDTO, "CountryCode" , "643");
УстановитьЗначениеXDTO(НовыйОбъектXDTO, "AddressText" , НовыйАдрес);
Функция УстановитьЗначениеXDTO (или аналогичная) используется для присвоения значений реквизитам объекта XDTO. Мы видим, что заполняем только IsForeign, CountryCode и AddressText. Если, например, в AddressInfo есть другие реквизиты, которые не были заполнены, они останутся в своем исходном состоянии (например, Неопределено или значение по умолчанию, если оно задано в схеме).
ExtendedOrganizationInfo.Address = НовыйОбъектXDTO;
Таким образом, мы эффективно "обновили" адресные данные, избежав прямых манипуляций с существующим объектом, которые могли бы нарушить ограничения схемы.
Этот подход является наиболее рекомендуемым, так как он соответствует объектно-ориентированной парадигме и обходит сложности, связанные с изменением уже сформированных по строгим правилам объектов.
Второй подход, который может быть полезен в определенных сценариях, связан с более низкоуровневой работой с XML-представлением объекта XDTO. Этот метод позволяет нам временно "отключить" проверку схемы, чтобы модифицировать данные.
Неопределено или пустые значения.Важный нюанс: при таком подходе следует быть особенно внимательными. Как отмечают опытные разработчики, при сохранении и последующем чтении 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, которые помогут нам лучше понять проблему и ее решения.
ВозможноПустое (nillable) в XSD
В XML-схеме существует атрибут xsd:nillable. Если для свойства установлено xsd:nillable="true", это означает, что элемент может быть представлен в XML как <elem xsi:nil="true"/>. В 1С это соответствует свойству ВозможноПустое для объекта СвойствоXDTO. Если мы хотим явно указать отсутствие значения, это может быть одним из способов. Однако, это не то же самое, что присвоить Неопределено в 1С, и требует поддержки со стороны схемы и внешних систем.
Попытка
Для того чтобы проверить, заполнено ли свойство XDTO или существует ли оно, не прибегая к конструкции Попытка-Исключение, мы можем использовать метод Свойства().Получить("ИмяРеквизита") объекта XDTO. Если метод возвращает Неопределено, это означает, что такого свойства нет или оно не заполнено.
СвойствоXDTO = ОбъектXDTO.Свойства().Получить("ИмяРеквизита");
Если СвойствоXDTO = Неопределено Тогда
// Свойства нет или оно не заполнено
Сообщить("Свойство 'ИмяРеквизита' отсутствует или не заполнено.");
Иначе
// Свойство существует и содержит значение
Значение = ОбъектXDTO.ПолучитьЗначение(СвойствоXDTO);
Сообщить("Значение свойства 'ИмяРеквизита': " + Значение);
КонецЕсли;
null
Существуют известные сложности при сериализации и десериализации "null" значений через механизм XDTO. Для передачи null в веб-сервисах может использоваться специальный тип Null из пространства имен http://v8.1c.ru/8.1/data/core. Однако, его совмещение с другими примитивными типами может потребовать дополнительной обработки и внимательности.
Мы рассмотрели несколько подходов к решению проблемы установки значения Неопределено для реквизитов объекта XDTO. Наиболее универсальным и безопасным является создание нового объекта и его замещение. Второй метод, связанный с манипуляциями XML без схемы, требует большей осторожности и понимания потенциальных рисков. В любом случае, глубокое понимание XML-схемы и особенностей работы ФабрикаXDTO является ключом к успешной интеграции и обмену данными.