При интеграции 1С со сторонними информационными системами разработчики часто сталкиваются с жесткими требованиями к структуре XML-документов. Распространенной задачей является вывод данных в виде отдельных вложенных элементов (тегов) вместо записи атрибутов внутри одного тега. Например, вместо компактного атрибута <VERSION CREATEDATE="14.12.2018"/> принимающая сторона может требовать развернутую структуру с отдельным подчиненным элементом: <CREATEDATE>04.12.2018</CREATEDATE>.
В этой статье мы подробно разберем, как решить данную задачу с помощью встроенного в платформу 1С:Предприятие объекта ЗаписьXML, а также рассмотрим более надежные и современные альтернативы: встроенную XML-сериализацию, технологию XDTO и объектную модель DOM.
Основная ошибка при решении этой задачи заключается в использовании метода ЗаписатьАтрибут(). Этот метод добавляет свойство внутрь открытого тега. Чтобы получить полноценный элемент со значением внутри, нам необходимо открыть элемент, записать в него строковое значение и закрыть элемент. Для записи текстового контента между тегами используется метод ЗаписатьТекст().
Проанализируем простейший пример, который решает поставленную задачу:
// Инициализируем объект записи
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\export.xml", "UTF-8");
// Открываем корневой или родительский элемент
ЗаписьXML.ЗаписатьНачалоЭлемента("VERSION");
// Открываем подчиненный элемент для даты
ЗаписьXML.ЗаписатьНачалоЭлемента("CREATEDATE");
// Записываем строковое значение даты в нужном формате
ЗаписьXML.ЗаписатьТекст(Формат(ТекущаяДата(), "ДФ=dd.MM.yyyy"));
// Закрываем подчиненный элемент
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закроет </CREATEDATE>
// Закрываем родительский элемент
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закроет </VERSION>
// Завершаем работу с файлом
ЗаписьXML.Закрыть();
В результате выполнения этого кода мы получим корректную структуру XML:
<VERSION>
<CREATEDATE>14.12.2018</CREATEDATE>
</VERSION>
Использование функции Формат() с явным указанием маски ДФ=dd.MM.yyyy оправдано только в том случае, если принимающая программа не умеет работать со стандартными форматами XML. В международной практике обмена данными общепринятым стандартом для дат является формат ISO 8601 (например, YYYY-MM-DD или YYYY-MM-DDThh:mm:ss).
В платформе 1С реализован глобальный метод XMLСтрока(). Он автоматически преобразует переданное значение (дату, число, булево) в канонический строковый вид, соответствующий спецификации W3C XML Schema. Это позволяет избежать ручного написания шаблонов форматирования и гарантирует корректное чтение данных любыми внешними парсерами.
Выясним, как изменится наш код при использовании встроенной сериализации:
ЗаписьXML.ЗаписатьНачалоЭлемента("CREATEDATE");
// Функция автоматически преобразует дату в стандартный формат (например, 2018-12-14T00:00:00)
ЗаписьXML.ЗаписатьТекст(XMLСтрока(ТекущаяДата()));
ЗаписьXML.ЗаписатьКонецЭлемента();
Если требуется записать только дату без времени, то для этого также отлично подойдет глобальный метод ЗаписатьXML(). Платформа сама определит тип данных и запишет значение в поток:
ЗаписьXML.ЗаписатьНачалоЭлемента("CREATEDATE");
ЗаписатьXML(ЗаписьXML, НачалоДня(ТекущаяДата()));
ЗаписьXML.ЗаписатьКонецЭлемента();
При ручном вызове методов ЗаписатьНачалоЭлемента() и ЗаписатьКонецЭлемента() в больших файлах легко допустить ошибку в иерархии тегов (например, забыть закрыть один из элементов). Чтобы абстрагироваться от последовательной записи и работать с XML-документом как с деревом объектов в оперативной памяти, рассмотрим использование модели DOM.
Этот подход позволяет сначала полностью выстроить логическую структуру документа, связать элементы друг с другом и лишь затем выгрузить результат в файл:
// Создаем основу DOM-документа
ДокументDOM = Новый ДокументDOM;
// Создаем элементы документа
ЭлементVersion = ДокументDOM.СоздатьЭлемент("VERSION");
ЭлементCreateDate = ДокументDOM.СоздатьЭлемент("CREATEDATE");
// Наполняем элемент даты текстовым содержимым
ЭлементCreateDate.ТекстовоеСодержимое = XMLСтрока(ТекущаяДата());
// Выстраиваем иерархию (вкладываем элементы)
ЭлементVersion.ДобавитьДочерний(ЭлементCreateDate);
ДокументDOM.ДобавитьДочерний(ЭлементVersion);
// Записываем готовый документ в файл через ЗаписатьDOM
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\export_dom.xml", "UTF-8");
ЗаписатьDOM = Новый ЗаписатьDOM;
ЗаписатьDOM.Записать(ДокументDOM, ЗаписьXML);
ЗаписьXML.Закрыть();
Наиболее современным, надежным и гибким способом работы с XML в 1С является использование механизма XDTO. Если у вас есть готовая схема XML (файл .xsd), предоставленная интегратором, вы можете импортировать её в конфигурацию в качестве Пакета XDTO.
Использование XDTO дает программисту следующие важные преимущества:
xs:date, система автоматически обрежет время и запишет дату в стандартном формате YYYY-MM-DD.Рассмотрим пример создания и выгрузки объекта данных через фабрику XDTO:
// Предположим, у нас в конфигурации определен пакет XDTO с типом "VersionType"
// Получаем тип из фабрики XDTO
ТипXDTO = ФабрикаXDTO.Тип("http://www.your-integration-schema.ru", "VersionType");
// Создаем экземпляр объекта XDTO по выбранному типу
ОбъектVersion = ФабрикаXDTO.Создать(ТипXDTO);
// Заполняем дату (платформа сама преобразует дату 1С в формат XML при записи)
ОбъектVersion.CREATEDATE = ТекущаяДата();
// Записываем готовый объект в XML
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\export_xdto.xml", "UTF-8");
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ОбъектVersion);
ЗаписьXML.Закрыть();
Использование фабрики XDTO полностью избавляет разработчика от необходимости вручную прописывать теги и следить за открытием/закрытием узлов структуры, сводя к минимуму вероятность возникновения синтаксических ошибок в результирующем файле.