Как загрузить текст из файла Microsoft Word в реквизит 1С типа «Форматированный документ» без ошибок?

Программист 1С v8.3 (Управляемые формы)
← На главную

При работе с системой 1С:Предприятие мы часто сталкиваемся с необходимостью интеграции с внешними приложениями и форматами файлов. Одной из таких задач является загрузка содержимого файлов Microsoft Word (DOC, DOCX) в реквизиты конфигурации, предназначенные для хранения форматированного текста, например, типа «Форматированный документ». На первый взгляд, задача кажется простой – достаточно прочитать файл и записать его содержимое. Однако, при попытке использовать объект ТекстовыйДокумент для чтения Word-файлов, мы можем столкнуться с неожиданной ошибкой: "текст xml содержит недопустимый символ".

В этом руководстве мы подробно разберем, почему возникает эта ошибка, какие особенности имеет тип данных «Форматированный документ» в 1С, и, самое главное, рассмотрим несколько способов решения данной задачи, включая наиболее эффективный метод с сохранением форматирования.

Почему возникает ошибка "текст xml содержит недопустимый символ"?

Давайте выясним причину, по которой наша первоначальная попытка прочитать вордовский файл как текстовый документ приводит к ошибке, связанной с XML. Когда мы используем код:


Текст = Новый ТекстовыйДокумент;
Попытка
    Текст.Прочитать(ИмяФайла);
    Объект.Описание = Текст.ПолучитьТекст();
Исключение
    Сообщить("Не удалось прочитать файл: " + ОписаниеОшибки,СтатусСообщения.ОченьВажное);
    Возврат;
КонецПопытки;

Мы ожидаем, что объект ТекстовыйДокумент сможет обработать содержимое файла Word. Однако файлы Word, особенно в современном формате DOCX, не являются простыми текстовыми файлами или даже обычными XML-документами в том смысле, как их интерпретирует 1С. Разберем подробнее:

  1. Формат DOCX: Файлы с расширением .docx – это на самом деле архивы формата ZIP. Внутри такого архива находится набор XML-файлов, которые описывают структуру документа, его содержимое, форматирование, стили, метаданные, изображения и другие объекты. Эти XML-файлы связаны между собой и следуют сложной спецификации Open XML. Когда ТекстовыйДокумент в 1С пытается прочитать такой архив или один из его внутренних XML-файлов, он может столкнуться с символами или структурами, которые не соответствуют ожидаемому синтаксису "чистого" XML или простого текста, что и приводит к ошибке "текст xml содержит недопустимый символ".

  2. Формат DOC: Старые файлы с расширением .doc имеют бинарный формат, который еще более далек от простого текста или XML. Они содержат сложную внутреннюю структуру, которую без специализированных библиотек или OLE-автоматизации невозможно корректно разобрать как текст.

  3. Объект ТекстовыйДокумент в 1С: Этот объект предназначен для работы с обычным текстовым содержимым (UTF-8, ANSI и т.д.) или с HTML-разметкой, если она соответствует определенным правилам и может быть интерпретирована как текст. Он не обладает функционалом для парсинга сложных бинарных или архивных форматов, таких как DOC или DOCX.

Таким образом, попытка прямого чтения файла Word с использованием ТекстовыйДокумент обречена на провал, поскольку мы подаем на вход объекту данные, которые он не предназначен обрабатывать.

Тип данных "Форматированный документ" в 1С и его особенности

Прежде чем перейти к решениям, давайте кратко рассмотрим, что представляет собой тип данных «Форматированный документ» (FormattedDocument) в 1С и как мы можем с ним работать. Этот объект появился в 1С:Предприятии начиная с версии 8.2.11 и предоставляет широкие возможности для работы с текстом, который включает различные стили, шрифты, размеры, начертания (полужирный, курсив, подчеркивание), цвета, выравнивание, отступы, списки (маркированные, нумерованные) и даже вставку изображений и гиперссылок.

Важные особенности использования:

  1. Реквизит формы, а не объекта: ФорматированныйДокумент нельзя напрямую указать как тип реквизита объекта базы данных (например, справочника, документа или плана видов характеристик). Вместо этого, он используется как тип реквизита в форме. Например, у вас может быть реквизит формы с типом ФорматированныйДокумент, который привязан к элементу управления «Поле форматированного документа».

  2. Хранение в базе данных: Для сохранения содержимого ФорматированныйДокумент в базе данных мы обычно используем объект ХранилищеЗначения. Мы помещаем объект типа ФорматированныйДокумент в ХранилищеЗначения и затем записываем это хранилище в реквизит объекта базы данных (который имеет тип ХранилищеЗначения).

    
    // Пример сохранения форматированного документа в хранилище
    Описание = Новый ФорматированныйДокумент;
    // Заполняем Описание (например, из элемента формы)
    // ...
    ЗначениеХранилища = Новый ХранилищеЗначения(Описание, Новый СжатиеДанных(9)); // Сжимаем для экономии места
    Объект.Реквизит_Хранилище = ЗначениеХранилища;
    

    При чтении данных из базы, мы извлекаем ХранилищеЗначения и десериализуем его обратно в объект ФорматированныйДокумент для отображения или программной работы.

    
    // Пример загрузки форматированного документа из хранилища
    Если Не Объект.Реквизит_Хранилище.Пусто() Тогда
        Описание = Объект.Реквизит_Хранилище.Получить();
        // Теперь мы можем работать с объектом Описание или вывести его на форму
    КонецЕсли;
    
  3. Программное управление: Объект ФорматированныйДокумент предоставляет ряд методов для программной работы с его содержимым:

    • ПолучитьТекст(): Возвращает весь текст документа без форматирования.
    • УстановитьТекст(Строка): Устанавливает простой текст в документ.
    • ПолучитьHTML(): Возвращает содержимое документа в виде HTML-разметки. Этот метод очень полезен для экспорта форматированного текста.
    • УстановитьHTML(СтрокаHTML): Устанавливает содержимое документа из HTML-строки. Именно этот метод мы будем активно использовать для загрузки форматированного текста из Word.
    • Вставить(), Добавить(): Методы для манипулирования содержимым.

Понимание этих особенностей критически важно для корректной реализации загрузки форматированного текста. Для детального разбора работы с этим типом данных подойдёт руководство по использованию форматированного документа в 1С.

Решение 1: Загрузка через OLE-автоматизацию MS Word с сохранением форматирования

Наиболее полный и надежный способ загрузки форматированного текста из файла Word с сохранением большей части форматирования – это использование OLE-автоматизации (COM-технологии) Microsoft Word. Этот подход позволяет нам "удаленно" управлять приложением Word, открывать документы, извлекать их содержимое и затем передавать его в 1С. В данном случае мы будем извлекать содержимое Word-документа в формате HTML, поскольку объект ФорматированныйДокумент в 1С отлично работает с HTML-разметкой. Для освоения базовых принципов такого взаимодействия подойдёт руководство по работе с COM-объектами в 1С.

  1. Шаг 1: Подключение к MS Word как COM-объекту

    Для начала нам необходимо установить соединение с приложением 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 в фоновом режиме, что удобно для пользователя.

  2. Шаг 2: Открытие Word-документа и извлечение форматированного содержимого в HTML

    После успешного подключения к приложению 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С).

  3. Шаг 3: Загрузка HTML-содержимого в реквизит формы типа "Форматированный документ" 1С

    Полученную HTML-строку мы теперь можем использовать для заполнения нашего реквизита типа ФорматированныйДокумент в 1С. Для этого применяется метод УстановитьHTML().

    Мы уже показали это в предыдущем примере. Важно помнить, что если реквизит объекта имеет тип ХранилищеЗначения, то мы сначала должны получить из него объект ФорматированныйДокумент, затем установить HTML и потом снова поместить обновленный ФорматированныйДокумент в ХранилищеЗначения.

    Важные моменты и возможные ограничения при использовании OLE:

    1. Зависимость от установленного MS Word: Данный метод требует, чтобы на компьютере, где выполняется код (обычно это клиентская машина пользователя), был установлен Microsoft Word. Без него COM-объект не может быть создан.

    2. Ограничения форматирования 1С: Объект ФорматированныйДокумент в 1С, хоть и функционален, может не поддерживать 100% всех возможностей форматирования MS Word. Некоторые специфические стили, сложные объекты или макеты могут быть потеряны или отображены некорректно. Результат может быть не идентичен исходному документу Word.

    3. Проблемы безопасности и производительности: Запуск внешнего приложения через OLE может быть медленным и потреблять значительные ресурсы. Также могут возникать вопросы безопасности, если Word запускается на сервере. В большинстве случаев рекомендуется выполнять OLE на стороне клиента.

    4. Обработка ошибок и очистка: Крайне важно корректно обрабатывать исключения и всегда закрывать открытые Word-документы и само приложение Word (методы Close() и Quit()), чтобы избежать "зависших" процессов Word в памяти.

Решение 2: Использование внешних утилит или ручная конвертация в HTML

Если по каким-либо причинам использование OLE-автоматизации MS Word напрямую из 1С нежелательно или невозможно (например, на компьютерах пользователей нет Word, или мы работаем в Linux), мы можем рассмотреть вариант с предварительной конвертацией файла Word в HTML-формат с помощью внешних утилит или вручную.

Последовательность действий:

  1. Конвертация Word-файла в HTML: Это можно сделать несколькими способами:

    • Вручную: Открыть Word-документ в MS Word и выбрать "Файл" -> "Сохранить как..." и в качестве типа файла указать "Веб-страница (*.htm; *.html)".
    • С помощью внешних утилит/сервисов: Существуют онлайн-конвертеры и локальные программы, которые могут конвертировать DOC/DOCX в HTML. Результатом будет HTML-файл.
  2. Загрузка HTML-файла в 1С: После того как у нас есть HTML-файл, мы можем прочитать его содержимое с помощью объекта ТекстовыйДокумент (он способен читать HTML, если он корректно сформирован) и затем передать полученную HTML-строку в метод УстановитьHTML() нашего реквизита ФорматированныйДокумент.

    
    &НаКлиенте
    Процедура ЗагрузитьHTMLИзФайла(Команда)
        Перем ИмяФайлаHTML;
        Если Не ВыбратьФайл(ИмяФайлаHTML) Тогда
            Возврат;
        КонецЕсли;
    
        ТекстHTMLДокумента = Новый ТекстовыйДокумент;
        Попытка
            ТекстHTMLДокумента.Прочитать(ИмяФайлаHTML);
            СтрокаHTML = ТекстHTMLДокумента.ПолучитьТекст();
            // Передаем HTML-строку в обработчик на сервере
            ЗагрузитьHTMLНаСервере(СтрокаHTML);
        Исключение
            Сообщить("Не удалось прочитать HTML-файл: " + ОписаниеОшибки(), СтатусСообщения.ОченьВажное);
        КонецПопытки;
    КонецПроцедуры
    
    // Функция ЗагрузитьHTMLНаСервере() будет такая же, как в Решении 1
    

    Этот метод более гибок в плане зависимостей, но требует либо ручных действий пользователя, либо интеграции с внешними компонентами/сервисами для автоматической конвертации, что может быть более сложной задачей, чем прямая OLE-автоматизация.

Решение 3: Загрузка обычного текста (с потерей форматирования)

В некоторых случаях форматирование может быть не критично, и нам достаточно получить только "чистый" текст из Word-документа. В этом случае задача значительно упрощается, но мы должны понимать, что вся информация о шрифтах, цветах, выравнивании и т.п. будет потеряна.

  1. Вариант А: Ручное копирование и вставка через Блокнот

    Самый простой способ, требующий минимального программирования, но максимального участия пользователя:

    1. Открыть Word-документ.
    2. Выделить весь текст (Ctrl+A).
    3. Скопировать его (Ctrl+C).
    4. Вставить в Блокнот (Notepad) или любой другой простой текстовый редактор. Это действие очищает текст от форматирования.
    5. Скопировать текст из Блокнота.
    6. Вставить его в поле «Форматированный документ» в 1С.

    После вставки в 1С мы можем сохранить полученный простой текст в ХранилищеЗначения. При программной записи это будет выглядеть как Объект.Описание.УстановитьТекст(ПростойТекст), а затем сохранение в хранилище.

  2. Вариант Б: Сохранение из Word в "Обычный текст" (*.txt)

    Этот вариант более автоматизирован, чем ручное копирование, но также приводит к потере форматирования.

    1. Сохранить файл Word как TXT: Пользователь открывает Word-документ, выбирает "Файл" -> "Сохранить как...", и в диалоге сохранения выбирает тип файла "Обычный текст (*.txt)". Word предложит параметры кодировки; обычно подходит "Windows (по умолчанию)" или "UTF-8".
    2. Загрузка TXT-файла в 1С: Полученный TXT-файл теперь является обычным текстовым документом, который ТекстовыйДокумент в 1С может легко прочитать.
    
    &НаКлиенте
    Процедура ЗагрузитьОбычныйТекстИзФайла(Команда)
        Перем ИмяФайлаTXT;
        Если Не ВыбратьФайл(ИмяФайлаTXT) Тогда
            Возврат;
        КонецЕсли;
    
        ТекстовыйДокумент = Новый ТекстовыйДокумент;
        Попытка
            ТекстовыйДокумент.Прочитать(ИмяФайлаTXT);
            ПростойТекст = ТекстовыйДокумент.ПолучитьТекст();
            // Передаем простой текст в обработчик на сервере
            ЗагрузитьПростойТекстНаСервере(ПростойТекст);
        Исключение
            Сообщить("Не удалось прочитать текстовый файл: " + ОписаниеОшибки(), СтатусСообщения.ОченьВажное);
        КонецПопытки;
    КонецПроцедуры
    
    &НаСервере
    Процедура ЗагрузитьПростойТекстНаСервере(ПростойТекст)
        ФорматированныйДокНаФорме = Неопределено;
        // Если реквизит на объекте имеет тип ХранилищеЗначения, то нужно его получить
        Если Объект.Реквизит_Хранилище_Описание.Получить() = Неопределено Тогда
            ФорматированныйДокНаФорме = Новый ФорматированныйДокумент();
        Иначе
            ФорматированныйДокНаФорме = Объект.Реквизит_Хранилище_Описание.Получить();
        КонецЕсли;
    
        // Устанавливаем простой текст
        ФорматированныйДокНаФорме.УстановитьТекст(ПростойТекст);
    
        // Сохраняем обратно в хранилище значений
        Объект.Реквизит_Хранилище_Описание = Новый ХранилищеЗначения(ФорматированныйДокНаФорме, Новый СжатиеДанных(9));
    
        Сообщить("Описание (без форматирования) успешно загружено из файла.", СтатусСообщения.Информация);
    КонецПроцедуры
    

Мы видим, что варианты загрузки обычного текста значительно проще в реализации, но всегда связаны с потерей всего форматирования, что часто неприемлемо для поля "Форматированный документ".

Заключение

Мы проанализировали проблему загрузки текста из Word-файлов в реквизит 1С типа «Форматированный документ» и выяснили, что прямая попытка с использованием ТекстовыйДокумент приводит к ошибке из-за сложной структуры Word-файлов. Мы рассмотрели особенности работы с типом ФорматированныйДокумент, включая его хранение через ХранилищеЗначения и методы работы с HTML.

Наиболее эффективным решением, позволяющим сохранить форматирование, является использование OLE-автоматизации Microsoft Word для извлечения содержимого в HTML-формате, который затем легко импортируется в 1С с помощью метода УстановитьHTML(). Если OLE-автоматизация не подходит, можно рассмотреть промежуточную конвертацию Word-документа в HTML внешними средствами. Для случаев, когда форматирование не критично, подойдут более простые методы загрузки обычного текста, но с потерей всех стилей.

Выбор оптимального решения всегда зависит от требований к сохранению форматирования, доступности MS Word на клиентских машинах и общих архитектурных решений вашей системы.

← На главную