Как в 1С изменить значение атрибута или элемента в XML-файле?

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

В процессе работы с интеграциями и обменами данными часто возникает задача программно отредактировать XML-файл: например, изменить значение конкретного атрибута, как `НомерВходящегоСообщения="100"`, или поменять текстовое содержимое тега. Платформа 1С предлагает несколько подходов для решения этой задачи, и выбор конкретного метода зависит от размера файла и сложности требуемых изменений. Рассмотрим основные способы с примерами кода.

Способ 1: Простая текстовая замена через `СтрЗаменить`

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

Посмотрим на пример:

Предположим, нам нужно в строке `НомерВходящегоСообщения=100` заменить `100` на `101`. Код будет выглядеть следующим образом:


// ФайлПолноеИмя - полный путь к вашему XML-файлу
// СтароеЗначение - например, "НомерВходящегоСообщения=100"
// НовоеЗначение - например, "НомерВходящегоСообщения=101"

ТекстДокумент = Новый ТекстовыйДокумент;
ТекстДокумент.Прочитать(ФайлПолноеИмя);

ТекстФайла = ТекстДокумент.ПолучитьТекст();
ТекстФайла = СтрЗаменить(ТекстФайла, СтароеЗначение, НовоеЗначение);

ТекстДокумент.УстановитьТекст(ТекстФайла);
// Указываем кодировку, чтобы не повредить файл
ТекстДокумент.Записать(ФайлПолноеИмя, КодировкаТекста.UTF8);

Важные моменты и возможные проблемы:

  1. Риск повредить структуру. Если заменяемая строка встречается в файле несколько раз в разных контекстах, вы можете случайно изменить не то, что хотели. Этот метод не анализирует структуру XML.
  2. Проблемы с кодировкой. Как было отмечено в обсуждении, после записи файла он может перестать открываться как корректный XML. Это часто связано с неверной кодировкой. При использовании метода ТекстовыйДокумент.Записать() критически важно явно указывать правильную кодировку, в которой должен быть сохранен файл (чаще всего `КодировкаТекста.UTF8`).
  3. Производительность. Этот способ не подходит для больших файлов, так как весь файл целиком загружается в оперативную память.

Вывод: Используйте этот метод для быстрых и простых замен в небольших файлах, всегда контролируя кодировку при записи.

Способ 2: Работа через объектную модель документа (DOM)

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

Для работы с DOM в 1С используются объекты:

Разберем по шагам на рабочем примере из форума. Задача — найти атрибут `НомерВходящегоСообщения` и поменять его значение на "221".


ИмяФайла = "D:\Message.XML";

// 1. Читаем файл и строим DOM-модель в памяти
ФайлЧтение = Новый ЧтениеXML;
ФайлЧтение.ОткрытьФайл(ИмяФайла);

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

// 2. Ищем нужный атрибут и меняем его значение
// Обходим узлы документа, чтобы найти нужный нам элемент
Для Каждого КорневойУзел Из ДокументDOM.ДочерниеУзлы Цикл
    Для Каждого ДочернийУзел Из КорневойУзел.ДочерниеУзлы Цикл
        // Используем Попытку, так как атрибут есть не у всех узлов
        Попытка
            Атрибут = ДочернийУзел.Атрибуты.ПолучитьИменованныйЭлемент("НомерВходящегоСообщения");
            Атрибут.ЗначениеУзла = "221";
        Исключение
            // Атрибута нет, просто пропускаем узел
        КонецПопытки;
    КонецЦикла;
КонецЦикла;

// 3. Записываем измененную DOM-модель обратно в файл
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ИмяФайла, "UTF-8"); // Явно указываем кодировку

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

ЗаписьXML.Закрыть();

Этот метод гораздо надежнее, так как вы работаете со структурой документа. Вместо перебора узлов в цикле можно использовать и более продвинутые методы поиска, например, `ПолучитьЭлементыПоИмени()`, если вы точно знаете имя тега.

Недостаток: Как и в первом случае, весь документ загружается в память. Для файлов размером в сотни мегабайт или гигабайты это может привести к нехватке памяти и низкой производительности.

Способ 3: Потоковая (последовательная) обработка для больших файлов

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

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

Рассмотрим пример, где нужно найти определенные узлы (`ПередВыгрузкойОбъекта`, `ПослеЗагрузкиПравилОбмена`) и заменить их текстовое содержимое.


ФайлИсточник = "D:\rules_old.xml";
ФайлПриемник = "D:\rules_new.xml";

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

// Флаг, показывающий, что мы находимся внутри нужного тега
ЭтоНужныйУзел = Ложь;

// Открываем файлы на чтение и запись
ХМЛЧтение = Новый ЧтениеXML;
ХМЛЧтение.ОткрытьФайл(ФайлИсточник);

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

// Читаем исходный файл узел за узлом
Пока ХМЛЧтение.Прочитать() Цикл

    Если ХМЛЧтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        
        // Проверяем, не тот ли это узел, который мы ищем
        Если СписокУзловДляЗамены.НайтиПоЗначению(ХМЛЧтение.Имя) <> Неопределено Тогда
            ЭтоНужныйУзел = Истина;
        КонецЕсли;
        
        // Копируем текущий узел (начало элемента) в новый файл
        ХМЛЗапись.ЗаписатьТекущий(ХМЛЧтение);

    ИначеЕсли ХМЛЧтение.ТипУзла = ТипУзлаXML.Текст И ЭтоНужныйУзел Тогда
        
        // Мы внутри нужного тега. Вместо копирования старого текста, пишем новый.
        ХМЛЗапись.ЗаписатьТекст("// Это новый текст для тега");

    ИначеЕсли ХМЛЧтение.ТипУзла = ТипУзлаXML.КонецЭлемента И ЭтоНужныйУзел Тогда
        
        // Мы вышли из тега, сбрасываем флаг
        ЭтоНужныйУзел = Ложь;
        // Копируем текущий узел (конец элемента) в новый файл
        ХМЛЗапись.ЗаписатьТекущий(ХМЛЧтение);

    Иначе
        // Все остальные узлы (атрибуты, комментарии и т.д.) просто копируем как есть
        ХМЛЗапись.ЗаписатьТекущий(ХМЛЧтение);
    КонецЕсли;

КонецЦикла;

// Закрываем файлы
ХМЛЧтение.Закрыть();
ХМЛЗапись.Закрыть();

Вывод: Этот подход самый сложный в реализации, но он является единственным рабочим решением для очень больших файлов, так как потребление памяти минимально.

Подведем итог:

← На главную