Как дополнить существующий XML-файл новыми узлами в 1С?

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

При интеграции систем или выгрузке отчетности часто возникает необходимость внедрить дополнительные данные в уже сформированный XML-документ. Разработчики сталкиваются с дилеммой: обязательно ли полностью считывать файл, десериализовать его в структуры 1С (соответствия, структуры, таблицы значений), дополнять своими данными и затем заново сериализовать в XML, либо существуют более лаконичные и производительные способы?

Разберем специфику работы с форматом XML и проанализируем основные архитектурные варианты решения этой задачи средствами платформы 1С:Предприятие.

Особенности структуры XML и ограничения прямого добавления

В отличие от обычных текстовых логов или CSV-файлов, к XML-документу нельзя применить стандартный файловый режим дозаписи в конец (append). Это обусловлено строгими требованиями спецификации формата:

  1. Наличие единого корневого элемента: корректный XML-документ всегда оборачивается в единственный корневой узел. В конце файла неизменно находится закрывающий тег этого узла. Любая попытка просто дописать строки в конец файла нарушит структуру и сделает документ невалидным.
  2. Пространства имен (Namespaces): новые узлы должны наследовать или явно объявлять URI пространства имен родительской ветки, иначе последующая проверка по XSD-схеме завершится ошибкой.
  3. Кодировки и BOM: перезапись частей файла строковыми методами может повредить исходную кодировку или заголовок порядка байтов (BOM), что вызовет сбой парсинга на стороне внешней системы.

Следовательно, задача всегда сводится к изменению структуры документа с его последующей полной перезаписью. Рассмотрим два основных способа выполнения этой операции в платформе 1С.

Способ 1. Использование объектной модели DOM

Для файлов небольшого и среднего объема (до нескольких десятков мегабайт) наиболее удобным и наглядным решением является работа с объектной моделью документа — DOM (Document Object Model). Платформа предоставляет для этого объекты ПостроительDOM, ДокументDOM и ЗаписьDOM.

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

Разберем по шагам алгоритм работы с DOM:

  1. Открываем исходный файл через ЧтениеXML.
  2. С помощью объекта ПостроительDOM считываем поток во внутреннее дерево ДокументDOM.
  3. Закрываем входящий поток чтения, чтобы освободить файл на диске.
  4. Находим целевой узел, в который требуется встроить данные.
  5. Создаем новые элементы через метод СоздатьЭлемент() и текстовые узлы через СоздатьТекстовыйУзел().
  6. Вставляем их в целевой узел с помощью методов ДобавитьДочерний() или ВставитьПеред().
  7. Инициализируем ЗаписьXML и сохраняем измененное дерево посредством объекта ЗаписьDOM.

Посмотрим на практический пример реализации:


ПутьКФайлу = "C:\Exchange\data.xml";

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

Построитель = Новый ПостроительDOM;
Документ = Построитель.Прочитать(Чтение);
Чтение.Закрыть();

// Получаем корневой узел или ищем нужную ветку
КорневойУзел = Документ.ЭлементДокумента;

// Создаем новый узел и текстовое значение
НовыйЭлемент = Документ.СоздатьЭлемент("CustomData");
НовыйЭлемент.УстановитьАтрибут("id", "1001");

ТекстовоеЗначение = Документ.СоздатьТекстовыйУзел("Дополнительные сведения");
НовыйЭлемент.ДобавитьДочерний(ТекстовоеЗначение);

// Прикрепляем элемент в структуру дерева
КорневойУзел.ДобавитьДочерний(НовыйЭлемент);

// Сохраняем обновленный документ обратно в файл
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ПутьКФайлу);

ЗаписьDOMДерева = Новый ЗаписьDOM;
ЗаписьDOMДерева.Записать(Документ, Запись);
Запись.Закрыть();

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

Способ 2. Потоковая модификация через ЧтениеXML и ЗаписьXML

Если файл имеет большой объем или процесс обработки критичен к потреблению памяти, DOM-модель не подходит. В этом случае правильнее применить потоковое чтение и запись с одновременным копированием элементов во временный файл.

Рассмотрим подробнее механизм работы: мы последовательно читаем исходный файл с помощью ЧтениеXML, передаем считываемые узлы в целевой файл через ЗаписьXML.ЗаписатьТекущий(), а при попадании на требуемую позицию временно перехватываем поток и выводим собственные теги.

Разберем по шагам реализацию потокового добавления:

  1. Открываем исходный документ объектом ЧтениеXML.
  2. Создаем новый временный файл через ЗаписьXML.
  3. В цикле обходим узлы метода Прочитать().
  4. Проверяем, не дошли ли мы до места вставки (например, перед закрывающим тегом определенного блока).
  5. Если условие достигнуто, вызываем методы ЗаписатьНачалоЭлемента(), ЗаписатьТекст() и ЗаписатьКонецЭлемента().
  6. В остальных случаях просто вызываем ЗаписьXML.ЗаписатьТекущий(ЧтениеXML), что обеспечивает максимальную скорость копирования без ручного разбора атрибутов и текстов.
  7. По окончании закрываем оба потока и заменяем исходный файл временным через ПереместитьФайл().

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


ПутьИсходный = "C:\Exchange\large_data.xml";
ПутьВременный = "C:\Exchange\large_data_temp.xml";

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьИсходный);

Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ПутьВременный, "UTF-8");

Пока Чтение.Прочитать() Цикл
    // Ловим момент перед закрытием корневого элемента
    Если Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента И Чтение.Имя = "Root" Тогда
        // Вставляем свои узлы
        Запись.ЗаписатьНачалоЭлемента("AppendedNode");
        Запись.ЗаписатьАтрибут("status", "Active");
        Запись.ЗаписатьТекст("Потоковая запись значения");
        Запись.ЗаписатьКонецЭлемента();
    КонецЕсли;
    
    // Переносим текущий узел в результирующий файл
    Запись.ЗаписатьТекущий(Чтение);
КонецЦикла;

Чтение.Закрыть();
Запись.Закрыть();

УдалитьФайлы(ПутьИсходный);
ПереместитьФайл(ПутьВременный, ПутьИсходный);

Способ 3. Декларативная вставка через XSLT-преобразование

Еще один альтернативный метод — использование платформенного объекта ПреобразованиеXSL. Он удобен в случаях, когда XML-файл стандартизирован, а логику модификации хочется вынести из программного кода в отдельный декларативный шаблон (identity transform).

В шаблоне XSL описывается правило копирования всех имеющихся тегов как есть, а для определенного пути XPath задается внедрение нового блока. Метод ПреобразованиеXSL.Преобразовать() принимает исходный и результирующий файлы, производя замену без ручного перебора структуры в коде 1С.

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

Выбор оптимального инструмента зависит от конкретной задачи:

Для небольших XML-документов (файлы настроек, небольшие пакеты обмена) идеальным выбором является объектная модель DOM, так как она предоставляет удобную навигацию по узлам и минимизирует количество кода.

Для объемных выгрузок и регулярных фоновых обменов следует использовать потоковую связку ЧтениеXML и ЗаписьXML с вызовом метода ЗаписатьТекущий(), что гарантирует стабильность работы системы без перегрузки оперативной памяти.

← На главную