При выгрузке данных из 1С в формат XML часто возникает задача создать файл с определенной структурой. Стандартная проблема, с которой сталкиваются разработчики, — это представление данных. Использование метода ЗаписьXML.ЗаписатьАтрибут приводит к тому, что все реквизиты элемента записываются в одну строку, что не всегда соответствует требованиям принимающей системы. Разберем, как вместо этого создать иерархическую структуру, где каждый реквизит находится на новой строке в виде отдельного вложенного элемента.
Давайте сначала проясним разницу. Когда мы говорим об атрибутах, мы имеем в виду структуру вида:
<Offer NameOffer="Стол письменный" VendorCode="СП-001" Group="Мебель офисная" />
Здесь NameOffer, VendorCode и Group — это атрибуты элемента Offer. Они записываются внутри открывающего тега и располагаются в одну строку. Для их создания используется метод ЗаписатьАтрибут.
Однако часто требуется другая структура — с вложенными элементами (или дочерними узлами), которую называют "лесенкой":
<Offer>
<NameOffer>Стол письменный</NameOffer>
<VendorCode>СП-001</VendorCode>
<Group>Мебель офисная</Group>
</Offer>
Такая структура более читаема и часто является стандартом для обмена данными. Чтобы добиться такого результата, простого использования ЗаписатьАтрибут недостаточно. Необходимо явно создавать каждый вложенный элемент.
ЗаписатьНачалоЭлементаКлюч к решению — в правильном использовании методов объекта ЗаписьXML. Вместо того чтобы добавлять множество атрибутов к одному элементу, нам нужно для каждого реквизита создать свою пару открывающего и закрывающего тегов. Для этого используются методы ЗаписатьНачалоЭлемента() и ЗаписатьКонецЭлемента().
Рассмотрим два практических способа реализации.
Этот способ предполагает, что для каждого реквизита мы создаем новый элемент, а само значение помещаем в его атрибут, например, с именем "Значение".
Пример кода:
// ... внутри цикла по товарам
ЗаписьXML.ЗаписатьНачалоЭлемента("Товар");
// Реквизит "Наименование"
ЗаписьXML.ЗаписатьНачалоЭлемента("Наименование");
ЗаписьXML.ЗаписатьАтрибут("Значение", "Солянка");
ЗаписьXML.ЗаписатьКонецЭлемента; // Закрываем "Наименование"
// Реквизит "Артикул"
ЗаписьXML.ЗаписатьНачалоЭлемента("Артикул");
ЗаписьXML.ЗаписатьАтрибут("Значение", "1111111");
ЗаписьXML.ЗаписатьКонецЭлемента; // Закрываем "Артикул"
ЗаписьXML.ЗаписатьКонецЭлемента; // Закрываем "Товар"
Результат в XML-файле будет выглядеть так:
<Товар>
<Наименование Значение="Солянка" />
<Артикул Значение="1111111" />
</Товар>
Этот подход уже создает нужную вертикальную структуру, но может быть избыточным, так как добавляет дополнительный уровень вложенности через атрибут.
Это более классический и семантически верный способ. Имя реквизита становится именем тега, а его значение — текстовым содержимым этого тега. Для записи значения используется метод ЗаписатьТекст().
Пример кода:
// ... внутри цикла по товарам
ЗаписьXML.ЗаписатьНачалоЭлемента("Товар");
// Реквизит "Наименование"
ЗаписьXML.ЗаписатьНачалоЭлемента("Наименование");
ЗаписьXML.ЗаписатьТекст("Солянка");
ЗаписьXML.ЗаписатьКонецЭлемента; // Закрываем "Наименование"
// Реквизит "Артикул"
ЗаписьXML.ЗаписатьНачалоЭлемента("Артикул");
ЗаписьXML.ЗаписатьТекст("1111111");
ЗаписьXML.ЗаписатьКонецЭлемента; // Закрываем "Артикул"
ЗаписьXML.ЗаписатьКонецЭлемента; // Закрываем "Товар"
Результат в XML-файле:
<Товар>
<Наименование>Солянка</Наименование>
<Артикул>1111111</Артикул>
</Товар>
Этот вариант является предпочтительным в большинстве случаев, так как он четко разделяет имя поля (тег) и его значение (текст).
Рассмотрим полный пример кода, который решает исходную задачу. В нем используется первый из рассмотренных вариантов (вложенный элемент с атрибутом), но его легко можно адаптировать под второй вариант с помощью ЗаписатьТекст().
В этом коде производится обход табличной части Объект.КаталогНСИ и для каждой строки номенклатуры создается элемент Offer со вложенными элементами для каждого реквизита.
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.Фильтр = "XML (*.XML)|*.XML|";
Если Диалог.Выбрать() Тогда
ИмяФайла = Диалог.ПолноеИмяФайла;
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ИмяФайла);
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("Offers"); // Корневой элемент
Для Каждого ЭлементНоменклатуры Из Объект.КаталогНСИ Цикл
ЗаписьXML.ЗаписатьНачалоЭлемента("Offer"); // Элемент для одной номенклатуры
// Вложенный элемент для Наименования
ЗаписьXML.ЗаписатьНачалоЭлемента("NameOffer");
ЗаписьXML.ЗаписатьАтрибут("NameOffer", Строка(ЭлементНоменклатуры.Наименование));
ЗаписьXML.ЗаписатьКонецЭлемента();
// Вложенный элемент для Артикула
ЗаписьXML.ЗаписатьНачалоЭлемента("VendorCode");
ЗаписьXML.ЗаписатьАтрибут("VendorCode", Строка(ЭлементНоменклатуры.Артикул));
ЗаписьXML.ЗаписатьКонецЭлемента();
// Вложенный элемент для Группы
ЗаписьXML.ЗаписатьНачалоЭлемента("Group");
ЗаписьXML.ЗаписатьАтрибут("Group", Строка(ЭлементНоменклатуры.ГруппаНоменклатуры));
ЗаписьXML.ЗаписатьКонецЭлемента();
// Вложенный элемент для Характеристики
ЗаписьXML.ЗаписатьНачалоЭлемента("Characteristic");
ЗаписьXML.ЗаписатьАтрибут("Characteristic", Строка(ЭлементНоменклатуры.ХарактеристикаНом));
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрываем "Offer"
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрываем "Offers"
ЗаписьXML.Закрыть();
КонецЕсли;
Главный вывод: чтобы управлять структурой XML-файла и выводить данные "лесенкой", необходимо активно использовать связку методов ЗаписьXML.ЗаписатьНачалоЭлемента() и ЗаписьXML.ЗаписатьКонецЭлемента() для каждого реквизита, а значение помещать внутрь с помощью ЗаписьXML.ЗаписатьТекст() или как атрибут вложенного элемента.