Как добавить новый элемент со вложенными тегами в XML файл через Фабрику XDTO?

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

Работа с XML-файлами в 1С, особенно когда речь идет о модификации структур сложных форматов (таких как Microsoft OpenXML, используемый в Excel), часто ставит перед разработчиком непростую задачу, сопоставимую по сложности с тем, как реализуется выгрузка и загрузка движений документа через XML. Использование ФабрикаXDTO является наиболее элегантным и современным способом манипуляции данными, однако оно требует строгого соблюдения типизации. В этой статье мы разберем, как правильно добавить новый элемент в существующую структуру XML, избежав типичных ошибок вроде "Несоответствие типов", и проанализируем альтернативные способы решения задачи.

Анализ проблемы типизации в XDTO

Рассмотрим ситуацию: нам необходимо в файл styles.xml добавить описание нового шрифта в теге <font>, который содержит вложенные элементы <u />, <sz val="8" /> и другие. Основная ошибка при работе с ФабрикаXDTO без предварительно загруженной XSD-схемы (в подготовке которой может помочь конвертация схемы XSD в модель XDTO) заключается в том, что 1С строит модель типов "на лету" во время выполнения функции ПрочитатьXML. В этом случае программист часто пытается создать вложенный элемент, используя тип родителя или произвольный тип, что приводит к исключению.

Проанализируем пример некорректного кода:


AnyType = СписокFonts[0].Тип();
НовыйЭлементFont = ФабрикаXDTO.Создать(AnyType);
// Попытка добавить вложенный элемент u, используя тот же тип, что и у Font
НовыйЭлементU = ФабрикаXDTO.Создать(AnyType); 
НовыйЭлементFont.Последовательность().Добавить(НовыйЭлементU); // Ошибка: Несоответствие типов

Причина ошибки в том, что тип объекта font и тип объекта u (подчеркивание) — это разные типы в модели XDTO. Даже если они кажутся простыми, фабрика ожидает строгого соответствия описанию свойства.

Правильный способ создания вложенных элементов

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

  1. Прочитать XML-файл в объект styleSheet.
  2. Найти список fonts и получить доступ к коллекции font.
  3. Определить тип самого элемента font (для добавления в список).
  4. Важный шаг: Чтобы создать вложенный элемент (например, sz), нужно получить тип этого свойства из метаданных объекта font.

Разберем реализацию этого алгоритма на языке 1С:


// 1. Получаем тип элемента font из списка существующих
ТипЭлементаFont = styleSheet.fonts.font[0].Тип();
НовыйFont = ФабрикаXDTO.Создать(ТипЭлементаFont);

// 2. Чтобы создать вложенный элемент sz (размер шрифта), 
// узнаем тип свойства "sz" у объекта НовыйFont
СвойствоSZ = НовыйFont.Свойства().Получить("sz");
ТипЭлементаSZ = СвойствоSZ.Тип;

// 3. Создаем объект нужного типа и устанавливаем значение атрибута
НовыйЭлементSZ = ФабрикаXDTO.Создать(ТипЭлементаSZ);
НовыйЭлементSZ.val = "8";

// 4. Присваиваем созданный объект свойству родителя
НовыйFont.sz = НовыйЭлементSZ;

// Аналогично для других тегов
СвойствоName = НовыйFont.Свойства().Получить("name");
НовыйЭлементName = ФабрикаXDTO.Создать(СвойствоName.Тип);
НовыйЭлементName.val = "Arial";
НовыйFont.name = НовыйЭлементName;

// Добавляем готовый шрифт в общий список
styleSheet.fonts.font.Добавить(НовыйFont);

Работа с пустыми тегами и последовательностями

В формате OpenXML часто встречаются теги без атрибутов и значений, такие как <u /> (подчеркивание). В XDTO работа с ними может быть неочевидной. Если свойство определено в схеме как объектный тип, достаточно просто создать экземпляр этого типа и присвоить его свойству родителя. Рассмотрим подробнее работу с Последовательность().

Метод Последовательность() используется в 1С для сохранения строгого порядка следования элементов в XML, если это требуется схемой (индикатор xs:sequence). Если вы работаете с динамически созданными типами, порядок важен для валидности файла Excel. Добавление через последовательность выглядит так:


// Создаем элемент u (подчеркивание)
ТипU = НовыйFont.Свойства().Получить("u").Тип;
НовыйЭлементU = ФабрикаXDTO.Создать(ТипU);

// Если объект поддерживает последовательность, добавляем элемент в неё
Если НовыйFont.Последовательность() <> Неопределено Тогда
    НовыйFont.Последовательность().Добавить(СвойствоU, НовыйЭлементU);
Иначе
    НовыйFont.u = НовыйЭлементU;
КонецЕсли;

Важный нюанс: При вызове метода Добавить() в последовательность, первым параметром лучше передавать объект свойства СвойствоXDTO, а вторым — само значение. Это гарантирует, что 1С правильно сопоставит объект с тегом в XML.

Использование пространств имен (Namespaces)

При работе с файлами Excel крайне важно учитывать URI пространств имен. Если создать объект в "пустом" пространстве имен, Excel может не распознать ваш файл после сохранения. Проанализируем, как передать URI:


URI_Main = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
// При создании объекта можно явно указывать пространство имен, если тип ищется по имени
ТипFont = ФабрикаXDTO.Тип(URI_Main, "CT_Font");
НовыйFont = ФабрикаXDTO.Создать(ТипFont);

Однако при динамическом чтении (как в нашем примере) фабрика уже знает пространство имен, так как оно было считано из заголовка файла. Главное — убедиться, что при записи методом ЗаписатьXML вы указываете корректный префикс и URI.

Альтернатива: Построитель DOM

Если структура XML слишком изменчива или вы не хотите глубоко погружаться в типизацию XDTO, рассмотрим использование ПостроительDOM. Этот метод позволяет работать с XML как с деревом узлов, что зачастую проще для "точечных" изменений.


// Пример работы через DOM
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);
Построитель = Новый ПостроительDOM;
ДокументDOM = Построитель.Прочитать(Чтение);

// Создаем новый узел font
НовыйУзелFont = ДокументDOM.СоздатьЭлемент("font");

// Создаем вложенный узел sz с атрибутом
УзелSZ = ДокументDOM.СоздатьЭлемент("sz");
УзелSZ.УстановитьАтрибут("val", "8");
НовыйУзелFont.ДобавитьДочерний(УзелSZ);

// Находим родительский узел fonts и добавляем наш новый шрифт
СписокFonts = ДокументDOM.ПолучитьЭлементыПоИмени("fonts");
Если СписокFonts.Количество() > 0 Тогда
    СписокFonts[0].ДобавитьДочерний(НовыйУзелFont);
КонецЕсли;

// Записываем обратно
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ПутьКФайлуНов);
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, Запись);
Запись.Закрыть();

Преимущество DOM в том, что нам не нужно знать типы данных — мы просто оперируем строковыми именами тегов и атрибутов. Это делает код более универсальным при работе с разными версиями форматов файлов.

Итоги и рекомендации

Мы проанализировали два основных подхода к редактированию XML в 1С. Выясним, какой из них выбрать:

  1. Фабрика XDTO идеальна, когда у вас есть готовая XSD-схема или вы осуществляете перенос данных с использованием XDTO между конфигурациями. Она обеспечивает строгий контроль данных, но требует аккуратного обращения с типами свойств.
  2. Построитель DOM лучше подходит для быстрой модификации файлов со сложной или неизвестной структурой (как файлы Office), либо когда требуется выгрузка и загрузка данных XML с дополнительными опциями отбора.

Помните, что при использовании XDTO ключевым моментом является получение типа через Свойства().Получить("ИмяСвойства").Тип, а не попытка подставить произвольный тип. Это гарантирует отсутствие ошибок и валидность результирующего XML-документа.

← На главную