Как оптимально прочитать и обновить конкретное поле в XML-файле?

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

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

Способ 1: Потоковое чтение и запись (самый сбалансированный метод)

Наиболее эффективным способом для файлов среднего и большого размера в 1С является использование пары объектов ЧтениеXML и ЗаписьXML. Ключевая особенность здесь заключается в методе ЗаписатьТекущий, который позволяет копировать узлы из источника в приемник «как есть», за исключением тех моментов, когда нам нужно подменить значение.

Рассмотрим алгоритм реализации этого метода. Мы будем последовательно читать файл, и если имя текущего элемента совпадает с тем, которое нам нужно обновить, мы запишем свое значение. В противном случае — просто перенесем данные из чтения в запись.


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

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

// Структура с новыми значениями (Ключ - имя тега, Значение - новый GUID)
НовыеДанные = Новый Структура("ИдентификаторОбъекта", "550e8400-e29b-41d4-a716-446655440000");

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

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

Преимущества этого подхода:

  1. Минимальное потребление памяти: файл не загружается целиком, данные передаются через буфер.
  2. Сохранение структуры: все пространства имен, комментарии и атрибуты (при правильной обработке) остаются на месте.
  3. Высокая скорость работы даже на файлах объемом в сотни мегабайт.

Способ 2: Использование Фабрики XDTO

Если XML-файл соответствует определенной схеме (XSD), то удобно использовать механизм XDTO. Этот метод позволяет работать с XML как с объектной моделью 1С.

Проанализируем процесс: мы читаем файл в объект XDTO, меняем свойство объекта и записываем его обратно. Однако, стоит помнить, что XDTO требователен к памяти, так как строит дерево объектов.


// Читаем XML в объект XDTO
МойОбъект = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);

// Прямое изменение значения
МойОбъект.Идентификатор = "Новый-GUID-12345";

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

Этот способ хорош тем, что 1С сама следит за типами данных и пространствами имен. Но будьте осторожны: если файл содержит «кастомные» пространства имен, не описанные в пакетах XDTO, они могут быть потеряны или искажены при перезаписи.

Способ 3: Текстовая замена (быстрый, но опасный метод)

Иногда, когда структура XML максимально проста, а файл огромен, программисты прибегают к использованию функций работы со строками. Например, замена через СтрЗаменить или использование регулярных выражений.

Рассмотрим ситуацию: если нам нужно заменить уникальную метку-заглушку или значение, которое гарантированно не встречается в других тегах. Мы можем прочитать файл как текст, выполнить замену и сохранить.


Текст = Новый ЧтениеТекста(ПутьКФайлу);
Содержимое = Текст.Прочитать();
Текст.Закрыть();

// Пример простой замены
НовоеСодержимое = СтрЗаменить(Содержимое, "СтарыйИД", "НовыйИД");

Запись = Новый ЗаписьТекста(ПутьКФайлу);
Запись.Записать(НовоеСодержимое);
Запись.Закрыть();

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

Способ 4: Профессиональный подход — XSLT-преобразования

Для тех, кто ищет максимально «чистое» решение с точки зрения архитектуры, в 1С предусмотрен объект ПреобразованиеXSL. Это стандарт индустрии для модификации XML-документов.

Выясним, как это работает: вы создаете небольшой XSL-шаблон (файл трансформации), который говорит системе: «копируй все узлы, но для узла с именем X примени другое правило». Сама трансформация выполняется крайне быстро на уровне низкоуровневых библиотек.

Пример простейшего XSL-шаблона для замены значения:


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Идентификатор">
        <Идентификатор>Новое_Значение</Идентификатор>
    </xsl:template>
</xsl:stylesheet>

В коде 1С это будет выглядеть так:


Преобразование = Новый ПреобразованиеXSL;
Преобразование.ЗагрузитьИзСтроки(ТекстXSL); // Загружаем шаблон
Преобразование.Преобразовать(ПутьКИсходномуXML, ПутьКРезультатуXML);

Рекомендации по выбору метода

Проанализировав все варианты, мы можем сделать следующие выводы:

  1. Если файл небольшой и есть XSD-схема — используйте ФабрикаXDTO. Это наиболее современный и типовой для 1С подход.
  2. Если файл большой (от 50 Мб до нескольких Гб) — ваш выбор ЧтениеXML + ЗаписьXML с использованием ЗаписатьТекущий(). Это обеспечит стабильность системы и защиту от переполнения памяти.
  3. Если требуется сложная логика изменений (замена многих полей по разным правилам) — используйте XSLT. Это позволит отделить логику трансформации от кода 1С.
  4. Избегайте работы с XML как с обычным текстом (СтрЗаменить), так как это часто приводит к повреждению кодировок или нарушению структуры документа при появлении в данных спецсимволов.

Таким образом, комбинируя потоковые методы чтения и записи, мы можем добиться высочайшей производительности при минимальных затратах ресурсов сервера.

← На главную