При работе с интеграциями часто возникает задача: получить XML-файл, найти в нем определенный узел (например, идентификатор объекта) и заменить его значение на актуальное, сохранив при этом структуру остального документа в неизменном виде. Сложность заключается в том, что XML-файлы могут быть очень большими, и полная десериализация в объекты 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.Закрыть();
Преимущества этого подхода:
Если XML-файл соответствует определенной схеме (XSD), то удобно использовать механизм XDTO. Этот метод позволяет работать с XML как с объектной моделью 1С.
Проанализируем процесс: мы читаем файл в объект XDTO, меняем свойство объекта и записываем его обратно. Однако, стоит помнить, что XDTO требователен к памяти, так как строит дерево объектов.
// Читаем XML в объект XDTO
МойОбъект = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
// Прямое изменение значения
МойОбъект.Идентификатор = "Новый-GUID-12345";
// Запись обратно
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлу);
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, МойОбъект);
ЗаписьXML.Закрыть();
Этот способ хорош тем, что 1С сама следит за типами данных и пространствами имен. Но будьте осторожны: если файл содержит «кастомные» пространства имен, не описанные в пакетах XDTO, они могут быть потеряны или искажены при перезаписи.
Иногда, когда структура XML максимально проста, а файл огромен, программисты прибегают к использованию функций работы со строками. Например, замена через СтрЗаменить или использование регулярных выражений.
Рассмотрим ситуацию: если нам нужно заменить уникальную метку-заглушку или значение, которое гарантированно не встречается в других тегах. Мы можем прочитать файл как текст, выполнить замену и сохранить.
Текст = Новый ЧтениеТекста(ПутьКФайлу);
Содержимое = Текст.Прочитать();
Текст.Закрыть();
// Пример простой замены
НовоеСодержимое = СтрЗаменить(Содержимое, "СтарыйИД", "НовыйИД");
Запись = Новый ЗаписьТекста(ПутьКФайлу);
Запись.Записать(НовоеСодержимое);
Запись.Закрыть();
Важное предупреждение: этот метод крайне не рекомендуется для промышленного использования, если вы не контролируете формат файла на 100%. Вы можете случайно заменить данные внутри CDATA, атрибутов или комментариев, что приведет к невалидности XML или логическим ошибкам в данных.
Для тех, кто ищет максимально «чистое» решение с точки зрения архитектуры, в 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);
Проанализировав все варианты, мы можем сделать следующие выводы:
ФабрикаXDTO. Это наиболее современный и типовой для 1С подход.ЧтениеXML + ЗаписьXML с использованием ЗаписатьТекущий(). Это обеспечит стабильность системы и защиту от переполнения памяти.XSLT. Это позволит отделить логику трансформации от кода 1С.СтрЗаменить), так как это часто приводит к повреждению кодировок или нарушению структуры документа при появлении в данных спецсимволов.Таким образом, комбинируя потоковые методы чтения и записи, мы можем добиться высочайшей производительности при минимальных затратах ресурсов сервера.