При работе с системой 1С:Предприятие мы часто сталкиваемся с необходимостью интеграции с внешними приложениями и форматами файлов. Одной из таких задач является загрузка содержимого файлов Microsoft Word (DOC, DOCX) в реквизиты конфигурации, предназначенные для хранения форматированного текста, например, типа «Форматированный документ». На первый взгляд, задача кажется простой – достаточно прочитать файл и записать его содержимое. Однако, при попытке использовать объект ТекстовыйДокумент для чтения Word-файлов, мы можем столкнуться с неожиданной ошибкой: "текст xml содержит недопустимый символ".
В этом руководстве мы подробно разберем, почему возникает эта ошибка, какие особенности имеет тип данных «Форматированный документ» в 1С, и, самое главное, рассмотрим несколько способов решения данной задачи, включая наиболее эффективный метод с сохранением форматирования.
Давайте выясним причину, по которой наша первоначальная попытка прочитать вордовский файл как текстовый документ приводит к ошибке, связанной с XML. Когда мы используем код:
Текст = Новый ТекстовыйДокумент;
Попытка
Текст.Прочитать(ИмяФайла);
Объект.Описание = Текст.ПолучитьТекст();
Исключение
Сообщить("Не удалось прочитать файл: " + ОписаниеОшибки,СтатусСообщения.ОченьВажное);
Возврат;
КонецПопытки;
Мы ожидаем, что объект ТекстовыйДокумент сможет обработать содержимое файла Word. Однако файлы Word, особенно в современном формате DOCX, не являются простыми текстовыми файлами или даже обычными XML-документами в том смысле, как их интерпретирует 1С. Разберем подробнее:
Формат DOCX: Файлы с расширением .docx – это на самом деле архивы формата ZIP. Внутри такого архива находится набор XML-файлов, которые описывают структуру документа, его содержимое, форматирование, стили, метаданные, изображения и другие объекты. Эти XML-файлы связаны между собой и следуют сложной спецификации Open XML. Когда ТекстовыйДокумент в 1С пытается прочитать такой архив или один из его внутренних XML-файлов, он может столкнуться с символами или структурами, которые не соответствуют ожидаемому синтаксису "чистого" XML или простого текста, что и приводит к ошибке "текст xml содержит недопустимый символ".
Формат DOC: Старые файлы с расширением .doc имеют бинарный формат, который еще более далек от простого текста или XML. Они содержат сложную внутреннюю структуру, которую без специализированных библиотек или OLE-автоматизации невозможно корректно разобрать как текст.
Объект ТекстовыйДокумент в 1С: Этот объект предназначен для работы с обычным текстовым содержимым (UTF-8, ANSI и т.д.) или с HTML-разметкой, если она соответствует определенным правилам и может быть интерпретирована как текст. Он не обладает функционалом для парсинга сложных бинарных или архивных форматов, таких как DOC или DOCX.
Таким образом, попытка прямого чтения файла Word с использованием ТекстовыйДокумент обречена на провал, поскольку мы подаем на вход объекту данные, которые он не предназначен обрабатывать.
Прежде чем перейти к решениям, давайте кратко рассмотрим, что представляет собой тип данных «Форматированный документ» (FormattedDocument) в 1С и как мы можем с ним работать. Этот объект появился в 1С:Предприятии начиная с версии 8.2.11 и предоставляет широкие возможности для работы с текстом, который включает различные стили, шрифты, размеры, начертания (полужирный, курсив, подчеркивание), цвета, выравнивание, отступы, списки (маркированные, нумерованные) и даже вставку изображений и гиперссылок.
Важные особенности использования:
Реквизит формы, а не объекта: ФорматированныйДокумент нельзя напрямую указать как тип реквизита объекта базы данных (например, справочника, документа или плана видов характеристик). Вместо этого, он используется как тип реквизита в форме. Например, у вас может быть реквизит формы с типом ФорматированныйДокумент, который привязан к элементу управления «Поле форматированного документа».
Хранение в базе данных: Для сохранения содержимого ФорматированныйДокумент в базе данных мы обычно используем объект ХранилищеЗначения. Мы помещаем объект типа ФорматированныйДокумент в ХранилищеЗначения и затем записываем это хранилище в реквизит объекта базы данных (который имеет тип ХранилищеЗначения).
// Пример сохранения форматированного документа в хранилище
Описание = Новый ФорматированныйДокумент;
// Заполняем Описание (например, из элемента формы)
// ...
ЗначениеХранилища = Новый ХранилищеЗначения(Описание, Новый СжатиеДанных(9)); // Сжимаем для экономии места
Объект.Реквизит_Хранилище = ЗначениеХранилища;
При чтении данных из базы, мы извлекаем ХранилищеЗначения и десериализуем его обратно в объект ФорматированныйДокумент для отображения или программной работы.
// Пример загрузки форматированного документа из хранилища
Если Не Объект.Реквизит_Хранилище.Пусто() Тогда
Описание = Объект.Реквизит_Хранилище.Получить();
// Теперь мы можем работать с объектом Описание или вывести его на форму
КонецЕсли;
Программное управление: Объект ФорматированныйДокумент предоставляет ряд методов для программной работы с его содержимым:
ПолучитьТекст(): Возвращает весь текст документа без форматирования.УстановитьТекст(Строка): Устанавливает простой текст в документ.ПолучитьHTML(): Возвращает содержимое документа в виде HTML-разметки. Этот метод очень полезен для экспорта форматированного текста.УстановитьHTML(СтрокаHTML): Устанавливает содержимое документа из HTML-строки. Именно этот метод мы будем активно использовать для загрузки форматированного текста из Word.Вставить(), Добавить(): Методы для манипулирования содержимым.Понимание этих особенностей критически важно для корректной реализации загрузки форматированного текста. Для детального разбора работы с этим типом данных подойдёт руководство по использованию форматированного документа в 1С.
Наиболее полный и надежный способ загрузки форматированного текста из файла Word с сохранением большей части форматирования – это использование OLE-автоматизации (COM-технологии) Microsoft Word. Этот подход позволяет нам "удаленно" управлять приложением Word, открывать документы, извлекать их содержимое и затем передавать его в 1С. В данном случае мы будем извлекать содержимое Word-документа в формате HTML, поскольку объект ФорматированныйДокумент в 1С отлично работает с HTML-разметкой. Для освоения базовых принципов такого взаимодействия подойдёт руководство по работе с COM-объектами в 1С.
Для начала нам необходимо установить соединение с приложением Microsoft Word. Это возможно только на операционных системах семейства Windows, где установлено приложение Word. Мы должны проверить тип платформы и создать объект COMОбъект("Word.Application"). Важно учесть возможные ошибки при создании COM-объекта, если Word не установлен или произошла другая проблема.
&НаКлиенте
Процедура ЗагрузитьОписаниеИзФайла(Команда)
Перем ИмяФайла;
Если Не ВыбратьФайл(ИмяФайла) Тогда
Возврат;
КонецЕсли;
Попытка
// Проверяем тип платформы, т.к. OLE работает только в Windows
СисИнфо = Новый СистемнаяИнформация;
Если Не (СисИнфо.ТипПлатформы = ТипПлатформы.Windows_x86 ИЛИ СисИнфо.ТипПлатформы = ТипПлатформы.Windows_x86_64) Тогда
Сообщить("Загрузка из MS Word доступна только на платформе Windows.", СтатусСообщения.ОченьВажное);
Возврат;
КонецЕсли;
WordПриложение = Новый COMОбъект("Word.Application");
WordПриложение.Visible = Ложь; // Скрываем окно Word, если оно не нужно
Исключение
Сообщить("Ошибка инициализации MS Word: " + ОписаниеОшибки() + ". Убедитесь, что MS Word установлен.", СтатусСообщения.ОченьВажное);
Возврат;
КонецПопытки;
В этом коде мы сначала проверяем, работаем ли мы на платформе Windows. Затем создаем экземпляр объекта Word.Application. Параметр Visible = Ложь позволяет работать с Word в фоновом режиме, что удобно для пользователя.
После успешного подключения к приложению Word, нам необходимо открыть целевой документ и извлечь его содержимое. Для максимально полного сохранения форматирования мы будем получать содержимое в формате HTML. MS Word позволяет легко это сделать.
&НаКлиенте
Процедура ПродолжениеЗагрузки(ИмяФайла, WordПриложение) // Предполагаем, что WordПриложение уже создано
WordДокумент = Неопределено;
Попытка
WordДокумент = WordПриложение.Documents.Open(ИмяФайла);
Если WordДокумент = Неопределено Тогда
ВызватьИсключение("Не удалось открыть документ Word.");
КонецЕсли;
// Извлекаем содержимое документа как HTML
СтрокаHTML = WordДокумент.Content.FormattedText.HTML;
// Закрываем документ и приложение Word
WordДокумент.Close(0); // 0 = wdDoNotSaveChanges, закрыть без сохранения
WordПриложение.Quit();
// Передаем HTML-строку в обработчик на сервере
ЗагрузитьHTMLНаСервере(СтрокаHTML);
Исключение
Сообщить("Ошибка при работе с документом Word: " + ОписаниеОшибки(), СтатусСообщения.ОченьВажное);
Если WordДокумент <> Неопределено Тогда
WordДокумент.Close(0);
КонецЕсли;
Если WordПриложение <> Неопределено Тогда
WordПриложение.Quit();
КонецЕсли;
КонецПопытки;
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьHTMLНаСервере(СтрокаHTML)
// Создаем новый объект ФорматированныйДокумент для загрузки HTML
// Или используем существующий реквизит формы, если он типа ФорматированныйДокумент
Если Объект.Описание = Неопределено Тогда
Объект.Описание = Новый ФорматированныйДокумент(); // Предполагаем, что Описание это реквизит типа ХранилищеЗначения на объекте
КонецЕсли;
ФорматированныйДокНаФорме = Неопределено;
// Если реквизит формы Описание имеет тип ФорматированныйДокумент:
// ФорматированныйДокНаФорме = Элементы.Описание; // Пример для элемента формы
// Если реквизит на объекте имеет тип ХранилищеЗначения, то нужно его получить
Если Объект.Реквизит_Хранилище_Описание.Получить() = Неопределено Тогда
ФорматированныйДокНаФорме = Новый ФорматированныйДокумент();
Иначе
ФорматированныйДокНаФорме = Объект.Реквизит_Хранилище_Описание.Получить();
КонецЕсли;
// Устанавливаем HTML-содержимое
ФорматированныйДокНаФорме.УстановитьHTML(СтрокаHTML);
// Сохраняем обратно в хранилище значений
Объект.Реквизит_Хранилище_Описание = Новый ХранилищеЗначения(ФорматированныйДокНаФорме, Новый СжатиеДанных(9));
Сообщить("Описание успешно загружено из файла Word.", СтатусСообщения.Информация);
КонецПроцедуры
В этом примере мы открываем документ с помощью WordПриложение.Documents.Open(ИмяФайла). Затем самая важная строка: СтрокаHTML = WordДокумент.Content.FormattedText.HTML; извлекает всё содержимое документа, включая форматирование, в виде HTML-строки. После этого мы закрываем документ (WordДокумент.Close(0)) и само приложение Word (WordПриложение.Quit()), чтобы освободить ресурсы.
Обратите внимание, что работа с COM-объектами должна выполняться на клиенте, а сохранение данных в объект 1С – на сервере. Поэтому мы разделяем логику на клиентскую (работа с Word) и серверную (сохранение в 1С).
Полученную HTML-строку мы теперь можем использовать для заполнения нашего реквизита типа ФорматированныйДокумент в 1С. Для этого применяется метод УстановитьHTML().
Мы уже показали это в предыдущем примере. Важно помнить, что если реквизит объекта имеет тип ХранилищеЗначения, то мы сначала должны получить из него объект ФорматированныйДокумент, затем установить HTML и потом снова поместить обновленный ФорматированныйДокумент в ХранилищеЗначения.
Важные моменты и возможные ограничения при использовании OLE:
Зависимость от установленного MS Word: Данный метод требует, чтобы на компьютере, где выполняется код (обычно это клиентская машина пользователя), был установлен Microsoft Word. Без него COM-объект не может быть создан.
Ограничения форматирования 1С: Объект ФорматированныйДокумент в 1С, хоть и функционален, может не поддерживать 100% всех возможностей форматирования MS Word. Некоторые специфические стили, сложные объекты или макеты могут быть потеряны или отображены некорректно. Результат может быть не идентичен исходному документу Word.
Проблемы безопасности и производительности: Запуск внешнего приложения через OLE может быть медленным и потреблять значительные ресурсы. Также могут возникать вопросы безопасности, если Word запускается на сервере. В большинстве случаев рекомендуется выполнять OLE на стороне клиента.
Обработка ошибок и очистка: Крайне важно корректно обрабатывать исключения и всегда закрывать открытые Word-документы и само приложение Word (методы Close() и Quit()), чтобы избежать "зависших" процессов Word в памяти.
Если по каким-либо причинам использование OLE-автоматизации MS Word напрямую из 1С нежелательно или невозможно (например, на компьютерах пользователей нет Word, или мы работаем в Linux), мы можем рассмотреть вариант с предварительной конвертацией файла Word в HTML-формат с помощью внешних утилит или вручную.
Последовательность действий:
Конвертация Word-файла в HTML: Это можно сделать несколькими способами:
Загрузка HTML-файла в 1С: После того как у нас есть HTML-файл, мы можем прочитать его содержимое с помощью объекта ТекстовыйДокумент (он способен читать HTML, если он корректно сформирован) и затем передать полученную HTML-строку в метод УстановитьHTML() нашего реквизита ФорматированныйДокумент.
&НаКлиенте
Процедура ЗагрузитьHTMLИзФайла(Команда)
Перем ИмяФайлаHTML;
Если Не ВыбратьФайл(ИмяФайлаHTML) Тогда
Возврат;
КонецЕсли;
ТекстHTMLДокумента = Новый ТекстовыйДокумент;
Попытка
ТекстHTMLДокумента.Прочитать(ИмяФайлаHTML);
СтрокаHTML = ТекстHTMLДокумента.ПолучитьТекст();
// Передаем HTML-строку в обработчик на сервере
ЗагрузитьHTMLНаСервере(СтрокаHTML);
Исключение
Сообщить("Не удалось прочитать HTML-файл: " + ОписаниеОшибки(), СтатусСообщения.ОченьВажное);
КонецПопытки;
КонецПроцедуры
// Функция ЗагрузитьHTMLНаСервере() будет такая же, как в Решении 1
Этот метод более гибок в плане зависимостей, но требует либо ручных действий пользователя, либо интеграции с внешними компонентами/сервисами для автоматической конвертации, что может быть более сложной задачей, чем прямая OLE-автоматизация.
В некоторых случаях форматирование может быть не критично, и нам достаточно получить только "чистый" текст из Word-документа. В этом случае задача значительно упрощается, но мы должны понимать, что вся информация о шрифтах, цветах, выравнивании и т.п. будет потеряна.
Самый простой способ, требующий минимального программирования, но максимального участия пользователя:
После вставки в 1С мы можем сохранить полученный простой текст в ХранилищеЗначения. При программной записи это будет выглядеть как Объект.Описание.УстановитьТекст(ПростойТекст), а затем сохранение в хранилище.
Этот вариант более автоматизирован, чем ручное копирование, но также приводит к потере форматирования.
ТекстовыйДокумент в 1С может легко прочитать.
&НаКлиенте
Процедура ЗагрузитьОбычныйТекстИзФайла(Команда)
Перем ИмяФайлаTXT;
Если Не ВыбратьФайл(ИмяФайлаTXT) Тогда
Возврат;
КонецЕсли;
ТекстовыйДокумент = Новый ТекстовыйДокумент;
Попытка
ТекстовыйДокумент.Прочитать(ИмяФайлаTXT);
ПростойТекст = ТекстовыйДокумент.ПолучитьТекст();
// Передаем простой текст в обработчик на сервере
ЗагрузитьПростойТекстНаСервере(ПростойТекст);
Исключение
Сообщить("Не удалось прочитать текстовый файл: " + ОписаниеОшибки(), СтатусСообщения.ОченьВажное);
КонецПопытки;
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьПростойТекстНаСервере(ПростойТекст)
ФорматированныйДокНаФорме = Неопределено;
// Если реквизит на объекте имеет тип ХранилищеЗначения, то нужно его получить
Если Объект.Реквизит_Хранилище_Описание.Получить() = Неопределено Тогда
ФорматированныйДокНаФорме = Новый ФорматированныйДокумент();
Иначе
ФорматированныйДокНаФорме = Объект.Реквизит_Хранилище_Описание.Получить();
КонецЕсли;
// Устанавливаем простой текст
ФорматированныйДокНаФорме.УстановитьТекст(ПростойТекст);
// Сохраняем обратно в хранилище значений
Объект.Реквизит_Хранилище_Описание = Новый ХранилищеЗначения(ФорматированныйДокНаФорме, Новый СжатиеДанных(9));
Сообщить("Описание (без форматирования) успешно загружено из файла.", СтатусСообщения.Информация);
КонецПроцедуры
Мы видим, что варианты загрузки обычного текста значительно проще в реализации, но всегда связаны с потерей всего форматирования, что часто неприемлемо для поля "Форматированный документ".
Заключение
Мы проанализировали проблему загрузки текста из Word-файлов в реквизит 1С типа «Форматированный документ» и выяснили, что прямая попытка с использованием ТекстовыйДокумент приводит к ошибке из-за сложной структуры Word-файлов. Мы рассмотрели особенности работы с типом ФорматированныйДокумент, включая его хранение через ХранилищеЗначения и методы работы с HTML.
Наиболее эффективным решением, позволяющим сохранить форматирование, является использование OLE-автоматизации Microsoft Word для извлечения содержимого в HTML-формате, который затем легко импортируется в 1С с помощью метода УстановитьHTML(). Если OLE-автоматизация не подходит, можно рассмотреть промежуточную конвертацию Word-документа в HTML внешними средствами. Для случаев, когда форматирование не критично, подойдут более простые методы загрузки обычного текста, но с потерей всех стилей.
Выбор оптимального решения всегда зависит от требований к сохранению форматирования, доступности MS Word на клиентских машинах и общих архитектурных решений вашей системы.