Почему XDTO не сохраняет реквизиты и некорректно формирует пространства имен при выгрузке XML в 1С?

Программист 1С v8.3 (Управляемые формы)
← На главную

При работе с технологией XDTO в 1С:Предприятии 8.3 разработчики часто сталкиваются с неочевидными проблемами при выгрузке данных в формат XML. Одной из таких проблем является частичная потеря реквизитов, особенно тех, которые представлены сложными типами, а также некорректное формирование пространств имен (xmlns) в итоговом XML-файле. Мы рассмотрим, почему это происходит и как правильно настроить процесс выгрузки, чтобы избежать подобных ошибок.

Анализируем проблему: потеря реквизитов и некорректные xmlns

Представим ситуацию, когда мы имеем XSD-схему, описывающую структуру XML-документа. Мы загружаем эту схему в конфигурацию 1С, создаем соответствующие XDTO-объекты, заполняем их данными, и в отладчике все выглядит идеально: все поля присутствуют, значения корректны. Однако при попытке записать этот XDTO-объект в XML-файл обнаруживается, что часть данных, особенно те, что соответствуют сложным типам (например, вложенные структуры), теряется. Дополнительно, вместо ожидаемого поведения с пространством имен, в XML-файле появляются странные конструкции, такие как xmlns="" xmlns:d2p1="[неймСпейс]", что указывает на проблемы с обработкой targetNamespace.

Давайте разберем типичный пример, с которым сталкиваются разработчики. Исходная XSD-схема может содержать следующую структуру:


<!-- Часть XSD-схемы -->
<xs:element name="goods-catalog">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="bar-code" minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="price-entry" minOccurs="0" maxOccurs="unbounded">
                            <xs:complexType>
                                <xs:sequence>
                                    <xs:element name="department" type="xs:string" minOccurs="0"/>
                                    <xs:element name="value" type="xs:decimal"/>
                                    <!-- другие элементы -->
                                </xs:sequence>
                            </xs:complexType>
                        </xs:element>
                        <!-- другие элементы bar-code -->
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>

При этом, несмотря на то что в отладчике мы видим заполненные поля department внутри price-entry, в итоговом XML-файле этих полей может не оказаться, или они будут представлены некорректно. Получаемый XML-вывод может выглядеть примерно так:


<bar-code xmlns="" xmlns:d2p1="[неймСпейс]">
    <price-entry>
        <value>0.5</value>
    </price-entry>
    <!-- Здесь отсутствует элемент <department> -->
</bar-code>

Как мы видим, элемент department пропал, а с пространством имен произошли непредвиденные изменения: появился пустой xmlns="" и квалифицированный xmlns:d2p1, что явно указывает на проблему.

Причина проблемы с пространствами имен (xmlns)

Ключевая проблема часто кроется в том, как мы используем метод ФабрикаXDTO.ЗаписатьXML() и как XSD-схема определяет пространства имен. Давайте рассмотрим это подробнее:

  1. targetNamespace и elementFormDefault в XSD:

    В XSD-схеме атрибут targetNamespace определяет пространство имен для элементов и атрибутов, объявленных в этой схеме. Атрибут elementFormDefault в корневом элементе схемы (<xs:schema>) указывает, должны ли локально объявленные элементы быть явно квалифицированы пространством имен схемы в итоговом XML-документе.

    • Если elementFormDefault="qualified": все локально объявленные элементы (то есть элементы, определенные внутри других элементов или сложных типов) должны быть явно квалифицированы пространством имен схемы (например, через префикс).
    • Если elementFormDefault="unqualified" (или отсутствует, так как это значение по умолчанию для XSD 1.0): локальные элементы не будут иметь префикса пространства имен.

    Если в нашей XSD-схеме установлено elementFormDefault="qualified", а XDTO-объект записывается таким образом, что его элементы не квалифицируются этим пространством имен, это может привести к тому, что 1С XDTO либо не сможет правильно сопоставить поля, либо выгрузит их в "нулевом" пространстве имен (xmlns="").

  2. Некорректное использование ФабрикаXDTO.ЗаписатьXML():

    Метод ФабрикаXDTO.ЗаписатьXML() имеет несколько параметров. Его полный синтаксис выглядит так:

    ФабрикаXDTO.ЗаписатьXML(<ЗаписьXML>, <Элемент>, <ЛокальноеИмя>, <URIПространстваИмен>, <Форма>, <УказаниеТипа>)

    Четвертый параметр, <URIПространстваИмен>, играет здесь ключевую роль. Этот параметр позволяет явно указать URI пространства имен для записываемого элемента. Однако, если XDTO-объект, который мы передаем для записи (в нашем случае СписокТоваров), уже содержит корректную информацию о своем пространстве имен (полученную из загруженного XSD-пакета), то передача этого параметра в ЗаписатьXML может привести к конфликту или дублированию объявлений xmlns. Часто разработчики пытаются "помочь" XDTO, явно указывая пространство имен, что в итоге приводит к обратному эффекту.

    В нашем случае, в коде автора использовался вызов:

    ВыгрузкаФабрикаXDTO.ЗаписатьXML(ФайлXML, СписокТоваров,,[неймСпейс]);

    Здесь [неймСпейс] – это явно указанный URI пространства имен. При таком вызове 1С XDTO пытается записать корневой элемент bar-code (или что является корневым элементом в СписокТоваров) в указанном пространстве имен. Однако, если XDTO-пакет уже "знает" это пространство имен для своих типов, передача его снова может запутать механизм. В результате XDTO может воспринять сам элемент как находящийся в "нулевом" пространстве имен (xmlns=""), а явно указанное пространство имен добавить как новый префикс (xmlns:d2p1="[неймСпейс]"), что и порождает проблему.

  3. Неполное создание XDTO-объектов:

    Потеря сложных типов, таких как department, может также указывать на то, что XDTO-объект был построен не полностью в соответствии со схемой, или же схема XSD содержит конструкции, которые 1С XDTO обрабатывает с особенностями. Если XSD-схема была импортирована в XDTO-пакет, убедитесь, что все элементы и их типы были правильно распознаны и сохранены в метаданных XDTO-пакета. Важно, чтобы каждый XDTO-объект, который мы передаем для записи, был полностью и корректно заполнен всеми необходимыми реквизитами, включая те, что являются сложными типами. Каждый объект должен быть создан на основе соответствующего типа из фабрики XDTO, и все его свойства должны быть заполнены значениями, соответствующими их типам по схеме.

Решение проблемы: правильное использование метода ЗаписатьXML()

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

  1. Исключаем избыточный параметр пространства имен:

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

    Рассмотрим пример правильного вызова:

    
    // Исходный код с ошибкой:
    // ВыгрузкаФабрикаXDTO.ЗаписатьXML(ФайлXML, СписокТоваров,,[неймСпейс]);
            
    // Корректный вариант 1: Опустить параметр URIПространстваИмен
    ВыгрузкаФабрикаXDTO.ЗаписатьXML(ФайлXML, СписокТоваров);
            
    // Корректный вариант 2: Передать Неопределено в качестве параметра URIПространстваИмен
    // (если нужно явно указать другие параметры, например, ЛокальноеИмя, но не URIПространстваИмен)
    ВыгрузкаФабрикаXDTO.ЗаписатьXML(ФайлXML, СписокТоваров, Неопределено, Неопределено);
    

    Когда мы опускаем четвертый параметр или передаем Неопределено, XDTO сам использует информацию о пространстве имен, заложенную в тип объекта СписокТоваров при его создании из XDTO-пакета. Это позволяет избежать двойных объявлений xmlns и корректно квалифицировать элементы.

  2. Проверяем и корректируем формирование XDTO-объектов:

    Если после исправления проблемы с xmlns данные сложных типов все еще теряются, это указывает на то, что проблема может быть в самом процессе формирования XDTO-объектов. Необходимо убедиться, что:

    • Все объекты, соответствующие сложным типам (например, price-entry и department), созданы на основе соответствующих типов из ФабрикаXDTO.
    • Эти объекты правильно вложены друг в друга, то есть department является свойством объекта price-entry, а price-entry – свойством объекта bar-code, как это описано в XSD-схеме.
    • Каждое свойство объекта заполнено данными соответствующего типа.

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

    
    // Пример правильного создания вложенных объектов
            
    // Получаем тип для "bar-code"
    ТипBarCode = ВыгрузкаФабрикаXDTO.Пакеты.Получить("ИмяПакета").Получить("bar-code");
    ОбъектBarCode = ВыгрузкаФабрикаXDTO.Создать(ТипBarCode);
            
    // Получаем тип для "price-entry"
    ТипPriceEntry = ВыгрузкаФабрикаXDTO.Пакеты.Получить("ИмяПакета").Получить("price-entry");
    ОбъектPriceEntry = ВыгрузкаФабрикаXDTO.Создать(ТипPriceEntry);
    ОбъектPriceEntry.value = 0.5;
            
    // Получаем тип для "department" (если это комплексный тип, иначе это строка)
    // В нашем примере 'department' - это строка, но если бы это был сложный тип,
    // то мы бы создавали его как отдельный объект.
    // Если 'department' это xs:string, то присваиваем строку напрямую
    ОбъектPriceEntry.department = "Отдел продаж"; 
            
    // Добавляем price-entry в bar-code
    ОбъектBarCode.price-entry.Добавить(ОбъектPriceEntry);
            
    // Добавляем bar-code в СписокТоваров
    СписокТоваров.bar-code.Добавить(ОбъектBarCode);
    

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

Дополнительные аспекты: elementFormDefault и структура XSD

Важно понимать, что elementFormDefault="qualified" в XSD-схеме накладывает определенные требования на квалификацию элементов. Если вы обнаружили, что именно этот атрибут стал причиной некорректного формирования xmlns:d2p1, это означает, что внутренняя логика XDTO в 1С при его наличии ожидает, что элементы будут явно квалифицированы, но ваша попытка явно указать [неймСпейс] в ЗаписатьXML(), возможно, шла вразрез с тем, как XDTO уже интерпретировал схему. При правильном импорте XSD в XDTO-пакет, фабрика XDTO должна сама корректно обрабатывать elementFormDefault и targetNamespace. Избыточные параметры в ЗаписатьXML() только мешают этому процессу.

Целевое пространство имен (targetNamespace) обеспечивает уникальность типов и элементов. Без его корректного определения и использования XDTO может "терять" типы или интерпретировать их как anyType, что приводит к потере структуры и данных. Поэтому всегда проверяйте, что ваш XSD корректен и XDTO-пакет был создан без ошибок.

Заключение

Проблемы с сохранением реквизитов и некорректным формированием пространств имен при выгрузке XDTO-объектов в XML в 1С часто сводятся к двум основным моментам:

  1. Неправильное использование метода ФабрикаXDTO.ЗаписатьXML(), а именно передача избыточного четвертого параметра <URIПространстваИмен>, когда XDTO-объект уже содержит необходимую информацию о своем пространстве имен.
  2. Ошибки при формировании самих XDTO-объектов, когда сложные типы не создаются как отдельные XDTO-объекты, а лишь частично или некорректно заполняются.

Всегда внимательно читайте документацию к методам XDTO, убеждайтесь в корректности вашей XSD-схемы и правильности построения XDTO-объектов в коде 1С. Позвольте фабрике XDTO максимально самостоятельно справляться с обработкой пространств имен, доверяя ей ту информацию, которую она получила из импортированных XSD-схем.

← На главную