Работа с механизмами XDTO (XML Data Transfer Objects) в 1С часто кажется более удобной, чем ручная сборка файла, особенно когда на руках есть готовая XSD-схема. Однако на практике разработчики сталкиваются с тем, что стандартная сериализация выдает XML-документ «одной строкой», а префиксы пространств имен (например, d1p1, d1p2) выглядят нечитаемо или не принимаются информационной системой контрагента. В этой статье мы подробно разберем, как получить полный контроль над структурой и оформлением XML-файла при работе с XDTO.
По умолчанию объект ЗаписьXML может формировать файл без переносов строк, что затрудняет его анализ человеком и иногда вызывает ошибки у систем-приемников, ожидающих определенную структуру. Чтобы добавить в файл красивые отступы и переносы, необходимо использовать объект ПараметрыЗаписиXML.
Проанализируем важный нюанс: свойства объекта ПараметрыЗаписиXML доступны только для чтения после создания объекта. Поэтому все настройки нужно передавать непосредственно в конструктор при инициализации. Рассмотрим правильный пример настройки:
// Определяем параметры записи
// 1. Кодировка (например, UTF-8)
// 2. Версия XML (1.0)
// 3. Истина — использовать отступы (переносы строк)
// 4. Истина — заменять ли недопустимые символы
// 5. Символы отступа (по умолчанию обычно табуляция или пробелы)
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина, Истина, " ");
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлу, ПараметрыЗаписи);
Обратите внимание, что если вы просто создадите Новый ПараметрыЗаписиXML() без аргументов, то изменить свойство Отступ позже кодом ПараметрыЗаписиXML.Отступ = Истина; не получится — система выдаст ошибку. Всегда задавайте форматирование в момент создания объекта.
Вторая частая проблема — автоматическая генерация префиксов. Когда мы вызываем метод ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ОбъектXDTO), 1С сама назначает префиксы для всех пространств имен, которые не были объявлены ранее. Часто это приводит к появлению имен типа xmlns:d1p1.
Чтобы задать свои префиксы (например, УТ для пространства имен торговых операций), мы применим комбинированный подход: запишем корневой элемент вручную, а внутреннее содержимое доверим XDTO. Рассмотрим этот алгоритм по шагам:
ЗаписьXML с настроенными параметрами.ЗаписатьНачалоЭлемента для создания корневого узла.ЗаписатьСоответствиеПространстваИмен, чтобы жестко связать нужный нам префикс с URI пространства имен.ФабрикаXDTO.ЗаписатьXML, передавая только вложенные объекты.ЗаписатьКонецЭлемента.Посмотрим на практический пример реализации:
ЗаписьXML = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина);
ЗаписьXML.ОткрытьФайл("C:\temp\document.xml", ПараметрыЗаписи);
// 1. Записываем начало корневого элемента (например, "Документ")
// Указываем локальное имя и URI пространства имен
ЗаписьXML.ЗаписатьНачалоЭлемента("Документ", "http://url.url/UT/2017-08-21");
// 2. Устанавливаем свой префикс "УТ" для этого пространства
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("УТ", "http://url.url/UT/2017-08-21");
// 3. Если нужно задать пространство имен по умолчанию (без префикса)
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("", "http://www.base-uri.com/main");
// 4. Сериализуем внутренние данные из объекта XDTO
// Предположим, у нас есть объект ДанныеXDTO, который является частью структуры
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ДанныеXDTO, , , , НазначениеТипаXDTO.Явное);
// 5. Закрываем корень
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();
Благодаря тому, что префикс УТ уже объявлен в текущем контексте записи, механизм XDTO не будет генерировать новый, а использует существующий для всех дочерних элементов этого пространства.
Часто в требованиях к файлу (особенно в государственных информационных системах) указано, что суммы должны иметь строго две цифры после запятой. В XSD это обычно описывается типом decimal с фасетом fractionDigits = 2 или паттерном. Однако в 1С тип Число при записи в XML канонизируется: незначащие нули отбрасываются (число 5.00 превращается в 5).
Выясним причину: объект XDTO при выгрузке ориентируется на базовые типы. Если в схеме указан тип decimal, 1С передает его как число, а XML-сериализатор согласно стандарту убирает лишние нули.
Существует два способа решения:
decimal на string. В этом случае в коде 1С вы будете передавать строковое значение, сформированное функцией Формат(Сумма, "ЧЦ=15; ЧДЦ=2; ЧГ=0"). Это гарантирует сохранение нулей.\d+\.\d{2}, попробуйте передавать значение в объект XDTO как строку, если модель XDTO это позволяет (иногда 1С разрешает записывать строку в поля простых типов, если не включена строгая проверка).Проанализируем пример с форматированием суммы:
// Если поле "Сумма" в XDTO-объекте ожидает строку (согласно исправленной схеме)
ОбъектXDTO.Сумма = Формат(5, "ЧЦ=15; ЧДЦ=2; ЧГ=0"); // Результат: "5.00"
Если стандартных методов ЗаписьXML недостаточно для реализации сложной логики (например, нужно вставить специфические комментарии или программно изменить узлы после их генерации), мы можем использовать Документ DOM. Этот метод позволяет «собрать» XML в памяти как дерево объектов, отредактировать его и только потом сохранить в файл.
Рассмотрим пошагово, как это работает:
ДокументDOM.ФабрикаXDTO.ЗаписатьXML, передавая в качестве первого параметра объект ЗаписьDOM.ВыбратьУзлы или ПолучитьЭлементыПоИмени и изменить их атрибуты или текстовое содержимое.ДокументDOM в файл с помощью объекта ЗаписьDOM и настроенного ЗаписьXML (для соблюдения отступов).Этот метод более ресурсоемок, но он дает 100% гарантию того, что финальный XML будет соответствовать самым жестким требованиям принимающей стороны.
Подводя итог, отметим: для большинства задач достаточно правильно инициализировать ПараметрыЗаписиXML и использовать ручное объявление корневого элемента для контроля префиксов. Это сохраняет производительность XDTO и при этом делает результат работы профессиональным и соответствующим стандартам обмена данными.