В процессе работы с интеграциями и обменами данными часто возникает задача программно отредактировать XML-файл: например, изменить значение конкретного атрибута, как `НомерВходящегоСообщения="100"`, или поменять текстовое содержимое тега. Платформа 1С предлагает несколько подходов для решения этой задачи, и выбор конкретного метода зависит от размера файла и сложности требуемых изменений. Рассмотрим основные способы с примерами кода.
Этот метод является самым простым и быстрым для небольших файлов. Его суть заключается в том, чтобы прочитать весь XML-файл как обычный текст, выполнить замену нужной подстроки и записать измененный текст обратно в файл.
Посмотрим на пример:
Предположим, нам нужно в строке `НомерВходящегоСообщения=100` заменить `100` на `101`. Код будет выглядеть следующим образом:
// ФайлПолноеИмя - полный путь к вашему XML-файлу
// СтароеЗначение - например, "НомерВходящегоСообщения=100"
// НовоеЗначение - например, "НомерВходящегоСообщения=101"
ТекстДокумент = Новый ТекстовыйДокумент;
ТекстДокумент.Прочитать(ФайлПолноеИмя);
ТекстФайла = ТекстДокумент.ПолучитьТекст();
ТекстФайла = СтрЗаменить(ТекстФайла, СтароеЗначение, НовоеЗначение);
ТекстДокумент.УстановитьТекст(ТекстФайла);
// Указываем кодировку, чтобы не повредить файл
ТекстДокумент.Записать(ФайлПолноеИмя, КодировкаТекста.UTF8);
Важные моменты и возможные проблемы:
ТекстовыйДокумент.Записать() критически важно явно указывать правильную кодировку, в которой должен быть сохранен файл (чаще всего `КодировкаТекста.UTF8`).Вывод: Используйте этот метод для быстрых и простых замен в небольших файлах, всегда контролируя кодировку при записи.
Это более надежный и правильный способ работы с XML. Файл загружается в память в виде древовидной структуры объектов (узлов, элементов, атрибутов). Это позволяет точно находить нужный элемент или атрибут и изменять его значение, не затрагивая остальную структуру документа. Для визуального просмотра дерева элементов и ручного изменения данных можно использовать универсальную обработку для чтения и редактирования XML-файлов.
Для работы с DOM в 1С используются объекты:
ЧтениеXML: для первоначального чтения файла.ПостроительDOM: для преобразования потока XML в объектную модель (дерево).ДокументDOM: сам объект, представляющий XML-документ в памяти.ЗаписьXML: для подготовки к записи в файл.ЗаписьDOM: для записи измененной DOM-модели в файл.Разберем по шагам на рабочем примере из форума. Задача — найти атрибут `НомерВходящегоСообщения` и поменять его значение на "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.Закрыть();
Этот метод гораздо надежнее, так как вы работаете со структурой документа. Вместо перебора узлов в цикле можно использовать и более продвинутые методы поиска, например, `ПолучитьЭлементыПоИмени()`, если вы точно знаете имя тега.
Недостаток: Как и в первом случае, весь документ загружается в память. Для файлов размером в сотни мегабайт или гигабайты это может привести к нехватке памяти и низкой производительности.
Это самый производительный и наименее ресурсоемкий способ для обработки очень больших XML-файлов. Суть в том, что мы одновременно читаем исходный файл и пишем новый (или тот же самый), обрабатывая документ узел за узлом, не загружая его целиком в память. Для реализации такого подхода на практике подойдёт внешняя обработка для автоматической замены данных в XML-файле.
Мы последовательно читаем узел из исходного файла, анализируем его, и если это не тот узел, который нам нужно изменить, то просто копируем его в выходной файл. Если же мы находим нужный узел, мы записываем в выходной файл его измененную версию.
Рассмотрим пример, где нужно найти определенные узлы (`ПередВыгрузкойОбъекта`, `ПослеЗагрузкиПравилОбмена`) и заменить их текстовое содержимое.
ФайлИсточник = "D:\rules_old.xml";
ФайлПриемник = "D:\rules_new.xml";
СписокУзловДляЗамены = Новый СписокЗначений;
СписокУзловДляЗамены.Добавить("ПередВыгрузкойОбъекта");
СписокУзловДляЗамены.Добавить("ПослеЗагрузкиПравилОбмена");
// Флаг, показывающий, что мы находимся внутри нужного тега
ЭтоНужныйУзел = Ложь;
// Открываем файлы на чтение и запись
ХМЛЧтение = Новый ЧтениеXML;
ХМЛЧтение.ОткрытьФайл(ФайлИсточник);
ХМЛЗапись = Новый ЗаписьXML;
ХМЛЗапись.ОткрытьФайл(ФайлПриемник, "UTF-8");
// Читаем исходный файл узел за узлом
Пока ХМЛЧтение.Прочитать() Цикл
Если ХМЛЧтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Проверяем, не тот ли это узел, который мы ищем
Если СписокУзловДляЗамены.НайтиПоЗначению(ХМЛЧтение.Имя) <> Неопределено Тогда
ЭтоНужныйУзел = Истина;
КонецЕсли;
// Копируем текущий узел (начало элемента) в новый файл
ХМЛЗапись.ЗаписатьТекущий(ХМЛЧтение);
ИначеЕсли ХМЛЧтение.ТипУзла = ТипУзлаXML.Текст И ЭтоНужныйУзел Тогда
// Мы внутри нужного тега. Вместо копирования старого текста, пишем новый.
ХМЛЗапись.ЗаписатьТекст("// Это новый текст для тега");
ИначеЕсли ХМЛЧтение.ТипУзла = ТипУзлаXML.КонецЭлемента И ЭтоНужныйУзел Тогда
// Мы вышли из тега, сбрасываем флаг
ЭтоНужныйУзел = Ложь;
// Копируем текущий узел (конец элемента) в новый файл
ХМЛЗапись.ЗаписатьТекущий(ХМЛЧтение);
Иначе
// Все остальные узлы (атрибуты, комментарии и т.д.) просто копируем как есть
ХМЛЗапись.ЗаписатьТекущий(ХМЛЧтение);
КонецЕсли;
КонецЦикла;
// Закрываем файлы
ХМЛЧтение.Закрыть();
ХМЛЗапись.Закрыть();
Вывод: Этот подход самый сложный в реализации, но он является единственным рабочим решением для очень больших файлов, так как потребление памяти минимально.
Подведем итог: