При работе с файлами формата Microsoft Office (DOCX, XLSX) программисты 1С часто сталкиваются с необходимостью программного изменения структуры внутренних XML-документов, например, document.xml. Одной из самых распространенных проблем является попытка добавить атрибут, имя которого содержит префикс и двоеточие, например, r:id или w:type. При использовании стандартного метода УстановитьАтрибут("r:id", "значение") платформа выдает ошибку "Недопустимое имя XML". Это происходит потому, что согласно стандартам XML двоеточие — это специальный символ, разделяющий префикс и локальное имя, и его нельзя использовать как часть обычной строки имени.
В данной статье мы разберем, как правильно работать с пространствами имен (Namespaces) в 1С, чтобы корректно записывать такие атрибуты, используя как объектную модель DOM, так и потоковую запись ЗаписьXML.
Проанализируем ситуацию: в XML-документах префиксы (такие как w, r, ve) — это лишь короткие псевдонимы, которые ссылаются на полные уникальные идентификаторы, называемые URI пространств имен. Например, префикс r в документах Word обычно ссылается на http://schemas.openxmlformats.org/officeDocument/2006/relationships. Когда мы пытаемся просто написать "r:id", 1С не понимает, что r — это префикс, и считает всю строку именем атрибута, что запрещено правилами формирования XML.
Рассмотрим два основных способа решения этой задачи.
Если мы работаем через ПостроительDOM, нам необходимо использовать специальные методы, которые умеют обрабатывать пространства имен. Эти методы всегда имеют суффикс NS (Namespace). Вместо стандартного метода УстановитьАтрибут, мы должны использовать УстановитьАтрибутNS.
Разберем по шагам, как это реализовать в коде:
// Определим URI пространств имен, которые используются в Word
URI_W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
URI_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
// Создаем элемент с указанием пространства имен
НовыйЭлемент = ДокументDOM.СоздатьЭлементNS(URI_W, "w:footerReference");
// Устанавливаем атрибуты, используя NS-метод
// Параметры: URI пространства, Квалифицированное имя (префикс:имя), Значение
НовыйЭлемент.УстановитьАтрибутNS(URI_W, "w:type", "default");
НовыйЭлемент.УстановитьАтрибутNS(URI_R, "r:id", "rId0");
// Добавляем элемент в нужное место документа
РодительскийУзел.ДобавитьДочерний(НовыйЭлемент);
Важно помнить, что при использовании DOM 1С строго следит за тем, чтобы префиксы были объявлены. Если вы укажете URI, который не объявлен в корневом элементе документа, платформа может автоматически добавить объявление xmlns в ваш узел, что иногда "раздувает" файл, но делает его валидным.
Как показывает практика обсуждений, иногда работа через DOM может быть избыточной или приводить к изменению порядка узлов. В таких случаях мы используем последовательное чтение и запись файла. Для того чтобы записать атрибут с двоеточием через ЗаписьXML, нужно использовать переопределенный метод ЗаписатьАтрибут, который принимает префикс и локальное имя отдельно.
Рассмотрим пример кода, который позволяет вставить узел в нужное место (например, перед тегом w:pgSz внутри секции параметров страницы):
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ПутьКНовомуФайлу, "UTF-8");
Пока Чтение.Прочитать() Цикл
// Копируем текущий узел в новый файл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Проверяем, не тот ли это узел, ПЕРЕД которым нужно вставить наш footerReference
Если Чтение.Имя = "w:pgSz" Тогда
// Записываем наш новый элемент с атрибутами через префиксы
Запись.ЗаписатьНачалоЭлемента("w:footerReference");
// Записываем атрибут w:type="default"
// Здесь "w" - префикс, "type" - локальное имя
Запись.ЗаписатьАтрибут("w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main", "type", "default");
// Записываем атрибут r:id="rId0"
Запись.ЗаписатьАтрибут("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id", "rId0");
Запись.ЗаписатьКонецЭлемента();
КонецЕсли;
Запись.ЗаписатьНачалоЭлемента(Чтение.Имя);
// Копируем существующие атрибуты текущего узла
Пока Чтение.ПрочитатьАтрибут() Цикл
Запись.ЗаписатьАтрибут(Чтение.Имя, Чтение.Значение);
КонецЦикла;
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
Запись.ЗаписатьКонецЭлемента();
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
Запись.ЗаписатьТекст(Чтение.Значение);
КонецЕсли;
КонецЦикла;
Запись.Закрыть();
Чтение.Закрыть();
Обратите внимание на метод ЗаписатьАтрибут. Мы передаем в него префикс r, URI пространства имен и локальное имя id. Платформа сама сконструирует строку r:id при записи в файл.
Проанализируем несколько моментов, без которых ваш XML-файл может остаться нечитаемым для Word:
r, убедитесь, что в самом начале документа (в теге w:document) присутствует объявление xmlns:r="...". Если его нет, Word выдаст ошибку "Namespace prefix r is not defined".w:sectPr (параметры секции) Word требует строгого порядка. Элементы w:headerReference и w:footerReference должны идти в самом начале списка дочерних узлов. Если вставить их после размеров страницы (w:pgSz) или полей (w:pgMar), документ может не открыться.r:id и r:ID — это разные атрибуты. В стандартах OpenXML чаще всего используется r:id.Выясним причину, почему использование простого СтрЗаменить в тексте XML — это плохая идея. При замене строк вы можете случайно нарушить кодировку или повредить данные внутри текстовых блоков документа. Работа через специализированные объекты ЗаписьXML и DOM гарантирует соблюдение синтаксиса и правильное экранирование спецсимволов.
Таким образом, для успешного добавления атрибутов с двоеточием достаточно перейти от использования простых строк к методам, поддерживающим пространства имен (NS), и четко указывать URI этих пространств.