При работе с технологией XDTO в 1С:Предприятии 8.3 разработчики часто сталкиваются с неочевидными проблемами при выгрузке данных в формат XML. Одной из таких проблем является частичная потеря реквизитов, особенно тех, которые представлены сложными типами, а также некорректное формирование пространств имен (xmlns) в итоговом XML-файле. Мы рассмотрим, почему это происходит и как правильно настроить процесс выгрузки, чтобы избежать подобных ошибок.
Представим ситуацию, когда мы имеем 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, что явно указывает на проблему.
Ключевая проблема часто кроется в том, как мы используем метод ФабрикаXDTO.ЗаписатьXML() и как XSD-схема определяет пространства имен. Давайте рассмотрим это подробнее:
targetNamespace и elementFormDefault в XSD:
В XSD-схеме атрибут targetNamespace определяет пространство имен для элементов и атрибутов, объявленных в этой схеме. Атрибут elementFormDefault в корневом элементе схемы (<xs:schema>) указывает, должны ли локально объявленные элементы быть явно квалифицированы пространством имен схемы в итоговом XML-документе.
elementFormDefault="qualified": все локально объявленные элементы (то есть элементы, определенные внутри других элементов или сложных типов) должны быть явно квалифицированы пространством имен схемы (например, через префикс).elementFormDefault="unqualified" (или отсутствует, так как это значение по умолчанию для XSD 1.0): локальные элементы не будут иметь префикса пространства имен.Если в нашей XSD-схеме установлено elementFormDefault="qualified", а XDTO-объект записывается таким образом, что его элементы не квалифицируются этим пространством имен, это может привести к тому, что 1С XDTO либо не сможет правильно сопоставить поля, либо выгрузит их в "нулевом" пространстве имен (xmlns="").
Фабрика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="[неймСпейс]"), что и порождает проблему.
Потеря сложных типов, таких как department, может также указывать на то, что XDTO-объект был построен не полностью в соответствии со схемой, или же схема XSD содержит конструкции, которые 1С XDTO обрабатывает с особенностями. Если XSD-схема была импортирована в XDTO-пакет, убедитесь, что все элементы и их типы были правильно распознаны и сохранены в метаданных XDTO-пакета. Важно, чтобы каждый XDTO-объект, который мы передаем для записи, был полностью и корректно заполнен всеми необходимыми реквизитами, включая те, что являются сложными типами. Каждый объект должен быть создан на основе соответствующего типа из фабрики XDTO, и все его свойства должны быть заполнены значениями, соответствующими их типам по схеме.
Для решения проблемы с некорректным формированием xmlns и потенциальной потерей данных, нам необходимо скорректировать вызов метода ФабрикаXDTO.ЗаписатьXML(). Суть заключается в том, чтобы позволить фабрике XDTO самой определить правильное пространство имен для корневого элемента, если оно уже известно из загруженного XSD-пакета.
Мы выяснили, что четвертый параметр метода ЗаписатьXML(), отвечающий за URIПространстваИмен, часто является источником проблем. Если XDTO-объект (например, СписокТоваров) был корректно создан на основе типа из XDTO-пакета, то этот объект уже "знает" свое пространство имен. Повторная передача его в качестве параметра может вызвать конфликт. Поэтому, в большинстве случаев, этот параметр следует либо опустить, либо передать ему значение Неопределено.
Рассмотрим пример правильного вызова:
// Исходный код с ошибкой:
// ВыгрузкаФабрикаXDTO.ЗаписатьXML(ФайлXML, СписокТоваров,,[неймСпейс]);
// Корректный вариант 1: Опустить параметр URIПространстваИмен
ВыгрузкаФабрикаXDTO.ЗаписатьXML(ФайлXML, СписокТоваров);
// Корректный вариант 2: Передать Неопределено в качестве параметра URIПространстваИмен
// (если нужно явно указать другие параметры, например, ЛокальноеИмя, но не URIПространстваИмен)
ВыгрузкаФабрикаXDTO.ЗаписатьXML(ФайлXML, СписокТоваров, Неопределено, Неопределено);
Когда мы опускаем четвертый параметр или передаем Неопределено, XDTO сам использует информацию о пространстве имен, заложенную в тип объекта СписокТоваров при его создании из XDTO-пакета. Это позволяет избежать двойных объявлений xmlns и корректно квалифицировать элементы.
Если после исправления проблемы с 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="qualified" в XSD-схеме накладывает определенные требования на квалификацию элементов. Если вы обнаружили, что именно этот атрибут стал причиной некорректного формирования xmlns:d2p1, это означает, что внутренняя логика XDTO в 1С при его наличии ожидает, что элементы будут явно квалифицированы, но ваша попытка явно указать [неймСпейс] в ЗаписатьXML(), возможно, шла вразрез с тем, как XDTO уже интерпретировал схему. При правильном импорте XSD в XDTO-пакет, фабрика XDTO должна сама корректно обрабатывать elementFormDefault и targetNamespace. Избыточные параметры в ЗаписатьXML() только мешают этому процессу.
Целевое пространство имен (targetNamespace) обеспечивает уникальность типов и элементов. Без его корректного определения и использования XDTO может "терять" типы или интерпретировать их как anyType, что приводит к потере структуры и данных. Поэтому всегда проверяйте, что ваш XSD корректен и XDTO-пакет был создан без ошибок.
Проблемы с сохранением реквизитов и некорректным формированием пространств имен при выгрузке XDTO-объектов в XML в 1С часто сводятся к двум основным моментам:
ФабрикаXDTO.ЗаписатьXML(), а именно передача избыточного четвертого параметра <URIПространстваИмен>, когда XDTO-объект уже содержит необходимую информацию о своем пространстве имен.Всегда внимательно читайте документацию к методам XDTO, убеждайтесь в корректности вашей XSD-схемы и правильности построения XDTO-объектов в коде 1С. Позвольте фабрике XDTO максимально самостоятельно справляться с обработкой пространств имен, доверяя ей ту информацию, которую она получила из импортированных XSD-схем.