Почему возникает ошибка «XML содержит недопустимый символ» при чтении Excel с кодами маркировки и как её исправить?

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

При автоматизации загрузки накладных из формата Excel (особенно УПД от поставщиков обуви, одежды или табака) разработчики часто сталкиваются со специфической ошибкой: «Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа... Ошибка преобразования данных XDTO». В тексте ошибки обычно указывается на наличие недопустимого символа в определенной позиции. Давайте разберем природу этой проблемы и рассмотрим эффективные способы её решения.

Выясним причину возникновения ошибки

Проанализируем ситуацию: ошибка возникает не в момент самого чтения файла методом Прочитать(), а в момент передачи объекта ТабличныйДокумент из серверной функции обратно на клиент. В 1С:Предприятии 8 при передаче сложных объектов между клиентом и сервером происходит их сериализация в формат XML.

Основная причина кроется в содержимом ячеек Excel. Если файл содержит коды маркировки (DataMatrix), в них часто присутствует спецсимвол GS (Group Separator), имеющий ASCII-код 29. Согласно стандарту XML 1.0, этот символ является «непечатным» и запрещенным к использованию в XML-структурах. Как только парсер XDTO встречает символ с кодом 29 в составе строки ячейки табличного документа, процесс передачи прерывается с ошибкой.

Рассмотрим подробнее позицию 71, упомянутую в тексте ошибки. В кодах маркировки «Честный Знак» это место часто совпадает с разделителем между различными группами данных (например, после серийного номера перед датой или кодом проверки). Это подтверждает, что проблема именно в специфических символах маркировки.

Решение 1. Обработка данных на стороне сервера без возврата объекта

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

Разберем по шагам, как изменить код:

  1. Прочитаем файл во временный файл на сервере.
  2. Загрузим его в объект ТабличныйДокумент.
  3. Обойдем строки таблицы и извлечем данные в «безопасный» формат (Массив структур или Таблица значений).
  4. Вернем на клиент только очищенные данные.

Пример реализации серверной функции:


&НаСервере
Функция ПрочитатьДанныеФайлаНаСервере(АдресДокументаВХранилище, Расширение)
    
    ДанныеДокумента = ПолучитьИзВременногоХранилища(АдресДокументаВХранилище);
    ИмяФайла = ПолучитьИмяВременногоФайла(Расширение);
    ДанныеДокумента.Записать(ИмяФайла);
    
    ТабДок = Новый ТабличныйДокумент;
    ТабДок.Прочитать(ИмяФайла);
    
    // Создаем структуру для возврата данных
    Результат = Новый Массив;
    
    // Проходим по строкам (например, со 2-й строки, если 1-я — заголовок)
    Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
        СтрокаДанных = Новый Структура;
        
        ТекстКодаМаркировки = ТабДок.Область(НомерСтроки, 5).Текст; // Допустим, код в 5-й колонке
        
        // Очищаем текст от недопустимых символов XML перед добавлением в структуру
        СтрокаДанных.Вставить("Номенклатура", ТабДок.Область(НомерСтроки, 1).Текст);
        СтрокаДанных.Вставить("КодМаркировки", ОбщегоНазначения.ЗаменитьНедопустимыеСимволыXML(ТекстКодаМаркировки));
        СтрокаДанных.Вставить("Количество", ТабДок.Область(НомерСтроки, 3).Значение);
        
        Результат.Добавить(СтрокаДанных);
    КонецЦикла;
    
    Попытка
        УдалитьФайлы(ИмяФайла);
    Исключение
        // Логируем ошибку удаления, если необходимо
    КонецПопытки;
    
    Возврат Результат; // Массив структур успешно передается через XDTO
КонецФункции

Решение 2. Использование функции очистки спецсимволов

Если вам все же необходимо вывести данные в табличный документ на форме, воспользуйтесь встроенным механизмом БСП (Библиотеки Стандартных Подсистем). Функция ОбщегоНазначения.ЗаменитьНедопустимыеСимволыXML() заменяет символы с кодами 0-31 (кроме разрешенных) на пробелы или удаляет их.

Важный нюанс: Помните, что для системы «Честный Знак» символ GS является критически важным. Если вы удалите его из строки перед тем, как отправить код на проверку в сервис маркировки, код может стать невалидным. Поэтому:

Решение 3. Использование COM-объекта (Excel.Application)

Как упоминалось в обсуждении, альтернативным способом является чтение файла через COM-соединение. Этот метод позволяет обращаться к данным напрямую, минуя механизмы ТабличногоДокумента 1С.

Проанализируем этот подход:


Попытка
    Excel = Новый COMОбъект("Excel.Application");
    Книга = Excel.Workbooks.Open(ИмяФайла);
    Лист = Книга.Sheets(1);
    
    Для Стр = 1 По Лист.UsedRange.Rows.Count Цикл
        ЗначениеЯчейки = Лист.Cells(Стр, 1).Value;
        // Здесь мы можем сразу очистить строку
        ЧистоеЗначение = ОбщегоНазначения.ЗаменитьНедопустимыеСимволыXML(Строка(ЗначениеЯчейки));
        // Дальнейшая логика...
    КонецЦикла;
    
    Книга.Close(Ложь);
    Excel.Quit();
Исключение
    // Обработка ошибок при отсутствии Excel на сервере
КонецПопытки;

Однако помните, что этот метод требует установленного Microsoft Excel на сервере (если код выполняется &НаСервере) или на клиенте. Кроме того, работа через COM значительно медленнее, чем прямое чтение файла платформой 1С.

Рекомендации по использованию готовых решений

Если вы хотите избежать написания кода с нуля, рекомендуется рассмотреть типовые инструменты 1С:

  1. Обработка «Загрузка данных из табличного документа»: Она уже содержит множество проверок и оптимизаций для работы с различными форматами. Подобные инструменты доступны на ИТС или в составе многих типовых конфигураций.
  2. СредстваЧтенияExcel: Начиная с версии платформы 8.3.10, можно использовать встроенные объекты для чтения xlsx, которые работают быстрее и не требуют наличия стороннего ПО.

Подводя итог, отметим: столкнувшись с ошибкой недопустимых символов XML, первым делом проверьте, не пытаетесь ли вы вернуть ТабличныйДокумент с «сырыми» кодами маркировки с сервера на клиент. Перенос логики обработки данных на сервер — самый надежный способ исправить эту ошибку и повысить производительность вашей обработки.

← На главную