При интеграции 1С с внешними информационными системами часто возникает задача передать текстовый или бинарный файл (например, документ MS Word, лог-файл или HTML-страницу) внутри XML-пакета. Напрямую записать бинарный файл или текст со спецсимволами в XML нельзя, так как это нарушит структуру XML-документа. В этой статье мы подробно рассмотрим несколько способов решения этой задачи в зависимости от формата исходного файла и требований к результату.
Если нам необходимо поместить любой файл (будь то плоский текст, картинка или документ Word .docx) внутрь XML-тега в виде текстовой строки, наиболее надежным решением является использование кодирования Base64. Этот стандарт преобразует двоичные данные в набор безопасных символов ASCII.
Рассмотрим пошагово, как реализовать этот алгоритм в коде 1С:
ДвоичныеДанные.Base64Строка().ЗаписьXML.Проанализируем пример кода, реализующий этот метод:
// Укажем пути к исходному файлу и создаваемому XML
ПутьКФайлу = "C:\temp\instruction.docx";
ПутьКXML = "C:\temp\output.xml";
// 1. Читаем файл в двоичные данные
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
// 2. Кодируем в строку Base64
СтрокаBase64 = Base64Строка(ДвоичныеДанныеФайла);
// 3. Записываем структуру XML
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКXML, "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("FileTransfer");
ЗаписьXML.ЗаписатьАтрибут("FileName", "instruction.docx");
ЗаписьXML.ЗаписатьНачалоЭлемента("FileData");
ЗаписьXML.ЗаписатьТекст(СтрокаBase64); // Помещаем закодированные данные
ЗаписьXML.ЗаписатьКонецЭлемента(); // FileData
ЗаписьXML.ЗаписатьКонецЭлемента(); // FileTransfer
ЗаписьXML.Закрыть();
Важное ограничение: Обратите внимание, что при работе с файлами очень большого размера (сотни мегабайт) преобразование в единую Base64-строку может привести к значительному потреблению оперативной памяти на сервере 1С. Для очень больших файлов рекомендуется использовать потоковую передачу.
Бывают ситуации, когда исходный документ представляет собой обычный текст (например, HTML-код, конфигурационные файлы или системные логи), который должен оставаться легко читаемым внутри XML-файла без кодирования в Base64. Однако такой текст может содержать служебные символы XML, такие как <, >, &, которые нарушат синтаксис XML-парсера.
Чтобы избежать ошибок парсинга и сохранить текст в исходном виде, мы можем использовать секцию CDATA (Unparsed Character Data). Все символы внутри этой секции игнорируются парсером XML.
Посмотрим на пример реализации с использованием метода ЗаписатьСекциюCDATA():
ТекстЛога = "Ошибка выполнения процесса: Значение1 < Значение2 & ОшибкаРегистрации";
ПутьКXML = "C:\temp\log_export.xml";
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКXML, "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("LogContainer");
// Записываем неформатированный текст в секцию CDATA
ЗаписьXML.ЗаписатьСекциюCDATA(ТекстЛога);
ЗаписьXML.ЗаписатьКонецЭлемента(); // LogContainer
ЗаписьXML.Закрыть();
В результате работы этого кода текст будет автоматически обернут в конструкцию <![CDATA[ ... ]]>, что гарантирует его корректное чтение принимающей стороной.
Если перед нами стоит задача вытащить текстовое содержимое из документа MS Word (формата .docx) и перенести его в XML, нам не обязательно использовать стороннее программное обеспечение или COM-объекты. Файл формата .docx физически представляет собой обычный ZIP-архив, внутри которого вся структура и тексты хранятся в формате XML.
Мы можем программно распаковать этот архив средствами 1С и прочитать нужные файлы. Текстовое содержимое документа находится по пути word/document.xml.
Выясним, как прочитать этот файл без использования Windows-зависимых библиотек, что особенно актуально при работе на серверах под управлением Linux:
ПутьКDocx = "C:\temp\document.docx";
ПапкаРаспаковки = "C:\temp\unpacked_docx\";
// Распаковываем docx как обычный ZIP-архив
Архив = Новый ЧтениеZipФайла(ПутьКDocx);
Архив.ИзвлечьВсе(ПапкаРаспаковки, РежимВосстановленияПутейФайловZIP.Восстанавливать);
Архив.Закрыть();
// Путь к основному XML-файлу с текстом документа
ПутьКDocumentXML = ПапкаРаспаковки + "word/document.xml";
// Читаем извлеченный XML-файл
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКDocumentXML);
Пока ЧтениеXML.Прочитать() Цикл
// Здесь мы можем анализировать структуру документа Word
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "t" Тогда
ЧтениеXML.Прочитать();
Сообщить("Текст из Word: " + ЧтениеXML.Значение);
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
Ограничение метода: При разборе извлеченных XML-файлов Word с использованием DOM-модели (объект ПостроительDOM) учитывайте платформенную особенность: элементы, содержащие только пробелы (например, теги форматирования пробелов между словами <w:t xml:space="preserve">), могут распознаваться как пустые строки. Это может привести к склеиванию слов при обратной сборке документа.
Если база данных работает на операционной системе Windows и на компьютере (или сервере 1С) установлен пакет Microsoft Office, мы можем выполнить полноценное преобразование документа Word в формат WordprocessingML (стандартизированный XML-формат от Microsoft).
Для этого мы воспользуемся COM-соединением с приложением Word:
Попытка
// Создаем COM-объект MS Word
MSWord = Новый COMОбъект("Word.Application");
MSWord.Visible = Ложь;
// Открываем исходный документ
Документ = MSWord.Documents.Open("C:\temp\document.docx");
// Сохраняем в формате Word XML (код формата 11 или 12)
// 11 соответствует формату Word XML Document
Документ.SaveAs("C:\temp\document_converted.xml", 11);
// Закрываем приложение
Документ.Close();
MSWord.Quit();
Сообщить("Конвертация успешно завершена!");
Исключение
Сообщить("Ошибка при конвертации документа: " + ОписаниеОшибки());
КонецПопытки;
Этот способ обеспечивает точное сохранение структуры и оформления документа, однако он полностью неприменим в Linux-среде и требует обязательного наличия лицензии Microsoft Office на стороне исполняющего код компьютера.