Работа с XML — одна из наиболее частых задач при интеграции 1С с внешними системами, особенно в контексте электронного документооборота (ЭДО) и маркировки товаров «Честный Знак». Часто возникает ситуация, когда существующий XML-файл (например, УПД) нужно не просто прочитать, а модифицировать: добавить сведения о кодах маркировки, изменить идентификаторы или вставить дополнительные информационные поля. В этой статье мы подробно разберем, как правильно добавлять новые узлы и строки в XML, используя различные механизмы платформы 1С:Предприятие.
Представим ситуацию: у нас есть готовый XML-файл формата УПД. Нам необходимо выполнить три операции:
ИдФайл в заголовке документа.ИнфПолФХЖ2 с атрибутами GTIN сразу после аналогичных информационных полей.ДопСведТов, который изначально выглядит как <ДопСведТов КодТов="00-00" />, в сложную структуру с вложенными узлами НомСредИдентТов и списком КИЗ.Метод DOM (Document Object Model) удобен тем, что загружает весь XML-файл в память в виде дерева объектов. Это позволяет нам свободно перемещаться по узлам, искать элементы по имени и изменять их структуру. Рассмотрим, как реализовать наши задачи этим способом.
Шаг 1: Чтение и подготовка документа. Сначала нам нужно прочитать файл и инициализировать построитель DOM.
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяВременногоФайла);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
ЧтениеXML.Закрыть();
Шаг 2: Изменение атрибутов. Проанализируем ситуацию, когда нам нужно найти конкретный узел и обновить его атрибут. Для этого используется метод УстановитьАтрибут().
СписокЭлементовDOMФайл = ДокументDOM.ПолучитьЭлементыПоИмени("Файл");
Для Каждого ЭлементDOM Из СписокЭлементовDOMФайл Цикл
Если ЭлементDOM.ЕстьАтрибут("ИдФайл") Тогда
СтароеЗначение = ЭлементDOM.ПолучитьАтрибут("ИдФайл");
НовоеЗначение = СтрЗаменить(СтароеЗначение, "_0_0_0_0_0_00", "_0_1_0_0_0_00");
ЭлементDOM.УстановитьАтрибут("ИдФайл", НовоеЗначение);
КонецЕсли;
КонецЦикла;
Шаг 3: Добавление новых вложенных элементов. Это самая важная часть. Чтобы превратить пустой тег в контейнер с вложенными строками, мы должны создать новые элементы через ДокументDOM.СоздатьЭлемент() и добавить их в иерархию методом ДобавитьДочерний().
Выясним причину, по которой у автора вопроса не получалось добавить строки: он пытался использовать УстановитьАтрибут() для вставки целых объектов, в то время как атрибут — это просто текстовая пара "ключ-значение". Правильный подход выглядит так:
СписокЭлементовDOMДопСведТов = ДокументDOM.ПолучитьЭлементыПоИмени("ДопСведТов");
Для Каждого ЭлементDOM Из СписокЭлементовDOMДопСведТов Цикл
АтрибутКод = ЭлементDOM.ПолучитьАтрибут("КодТов");
// 1. Добавляем ИнфПолФХЖ2 (GTIN)
НовоеПоло = ДокументDOM.СоздатьЭлемент("ИнфПолФХЖ2");
НовоеПоло.УстановитьАтрибут("Идентиф", "GTIN");
НовоеПоло.УстановитьАтрибут("Значен", "04600000000000");
// Вставляем в родительский элемент
ЭлементDOM.ДобавитьДочерний(НовоеПоло);
// 2. Создаем структуру маркировки КИЗ
МассивКИЗ = НайтиKIZ(АтрибутКод); // Функция получения данных
Если МассивКИЗ.Количество() > 0 Тогда
УзелНомСредИдент = ДокументDOM.СоздатьЭлемент("НомСредИдентТов");
Для Каждого ТекКИЗ Из МассивКИЗ Цикл
УзелКИЗ = ДокументDOM.СоздатьЭлемент("КИЗ");
// Добавляем текстовое содержимое внутрь тега КИЗ
ТекстКИЗ = ДокументDOM.СоздатьТекст(ТекКИЗ);
УзелКИЗ.ДобавитьДочерний(ТекстКИЗ);
// Добавляем КИЗ внутрь НомСредИдентТов
УзелНомСредИдент.ДобавитьДочерний(УзелКИЗ);
КонецЦикла;
// Добавляем всю структуру в ДопСведТов
ЭлементDOM.ДобавитьДочерний(УзелНомСредИдент);
КонецЕсли;
КонецЦикла;
Важный нюанс: Обратите внимание, что при добавлении дочерних узлов в элемент <ДопСведТов />, платформа при записи автоматически уберет закрывающий слеш в начале и добавит полноценный закрывающий тег </ДопСведТов>. Программисту не нужно делать это вручную.
Проанализируем более продвинутый метод — использование фабрики XDTO. Этот способ является наиболее правильным при работе с регламентированными форматами (ФНС, ЭДО), так как он гарантирует валидность документа согласно схеме (XSD).
Рассмотрим по шагам, как модифицировать документ через XDTO:
ON_NSCHFDOPPR).СостТабл или ДопСведТов).ФабрикаXDTO.Создать().Преимущество этого метода в том, что нам не нужно вручную следить за порядком следования тегов — XDTO сделает это за нас на основании правил схемы. Однако, как было замечено в обсуждении, если структура файла хоть немного отклоняется от схемы, ПрочитатьXML() может выдать ошибку «Структура объекта не соответствует типу».
В сообщениях форума упоминалось, что при перезаписи файла через DOM меняются префиксы пространств имен (например, xmlns:xsi превращается в xmlns:xsd). Рассмотрим, почему это происходит. Построитель DOM при чтении может переопределять пространства имен, если они не зафиксированы жестко.
Чтобы избежать этой проблемы и сохранить оригинальное оформление шапки XML, рекомендуется использовать методы с поддержкой пространств имен, такие как СоздатьЭлементNS(), или настраивать параметры ЗаписьXML. Если же строгая идентичность префиксов критична для принимающей стороны, иногда проще использовать комбинированный метод: последовательное чтение ЧтениеXML и запись в новый файл через ЗаписьXML, вставляя нужные блоки кода «на лету» в момент прохождения соответствующих узлов. Для решения этой задачи можно использовать обработку для замены данных в XML-файле.
Мы разобрали основные подходы к модификации XML в 1С. Для простых задач и небольших файлов идеально подходит DOM, так как он позволяет точечно изменять структуру документа. Для работы с большими файлами лучше использовать потоковую запись (ЧтениеXML + ЗаписьXML). Если же требуется строгая проверка на соответствие государственным стандартам, лучшим выбором будет XDTO. Для разового визуального изменения структуры документа подойдёт обработка для чтения и редактирования XML-файлов.
Помните, что при добавлении вложенных строк в DOM важно разделять создание элемента, установку его атрибутов и его прикрепление к родительскому узлу. Только соблюдение этой последовательности обеспечит корректную структуру итогового XML-файла.