Как исправить XML-файл из ТСД с лишними пробелами и ошибками кодировки?

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

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

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

Выясним причину: почему появляются «пробелы» и иероглифы

Проанализируем ситуацию: визуальные «пробелы» между символами — это не настоящие пробелы (код 32), а нулевые байты (null-bytes, 0x00). Это происходит из-за того, что устройство записывает данные в кодировке UTF-16LE. В этой кодировке каждый символ занимает ровно два байта. Для стандартных латинских символов и цифр первый байт содержит код символа, а второй — нулевой. Если открыть такой файл в редакторе, который ожидает однобайтовую кодировку (например, Windows-1251 или UTF-8), эти нулевые байты будут отображаться как пустоты или спецсимволы.

Однако главная проблема даже не в этом. Рассмотрим, почему файл «ломается» посередине:

  1. Смешанный формат переноса строк: ТСД записывает основной текст в двухбайтовом формате (UTF-16), но при переходе на новую строку записывает стандартный символ переноса CRLF как однобайтовый (0x0D 0x0A вместо правильных для UTF-16 0x0D 0x00 0x0A 0x00).
  2. Байтовый сдвиг: Как только в потоке данных встречается «короткий» перенос строки, все последующие байты сдвигаются на одну позицию. Старший байт следующего символа становится младшим байтом предыдущего. В результате 1С начинает интерпретировать пары байтов неправильно, и вместо текста мы видим иероглифы.
  3. Неверный заголовок: Часто в самом XML-файле указано encoding="UTF-8", хотя фактически данные лежат в UTF-16, что окончательно сбивает с толку парсер 1С.

Способ 1. Программное исправление через бинарное чтение

Поскольку файл поврежден на уровне байтов, мы не можем работать с ним как с текстом. Нам необходимо прочитать его как ДвоичныеДанные, найти некорректные последовательности и заменить их. Рассмотрим алгоритм исправления «сдвига» байтов.

Проанализируем пример кода, который восстанавливает структуру UTF-16LE, корректируя символы переноса строк:


Функция ИсправитьБитыйФайлТСД(ПутьКФайлу)
    // Читаем файл в двоичном виде
    ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
    Буфер = ОбластьДанных(ДвоичныеДанныеФайла); // Получаем доступ к байтам
    
    // Создаем новый буфер для исправленных данных
    НовыйБуфер = Новый БуферДвоичныхДанных(Буфер.Размер * 1.5); 
    
    СчетчикНового = 0;
    Для Индекс = 0 По Буфер.Размер - 1 Цикл
        Байт = Буфер[Индекс];
        
        // Проверяем на наличие последовательности 0D 0A (перенос строки)
        Если Байт = 13 И (Индекс + 1 < Буфер.Размер) И Буфер[Индекс + 1] = 10 Тогда
            // Если нашли короткий перенос, превращаем его в правильный UTF-16LE
            НовыйБуфер[СчетчикНового] = 13;
            НовыйБуфер[СчетчикНового + 1] = 0;
            НовыйБуфер[СчетчикНового + 2] = 10;
            НовыйБуфер[СчетчикНового + 3] = 0;
            СчетчикНового = СчетчикНового + 4;
            Индекс = Индекс + 1; // Пропускаем обработанный 0A
        Иначе
            НовыйБуфер[СчетчикНового] = Байт;
            СчетчикНового = СчетчикНового + 1;
        КонецЕсли;
    КонецЦикла;
    
    // Отрезаем лишнее от буфера и сохраняем
    ИтоговыеДанные = НовыйБуфер.ПрочитатьДвоичныеДанные(0, СчетчикНового);
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
    ИтоговыеДанные.Записать(ИмяВременногоФайла);
    
    Возврат ИмяВременногоФайла;
КонецФункции

Важный момент: если файл начинается с BOM (Byte Order Mark) для UTF-8 (EF BB BF), а данные внутри — UTF-16, 1С не сможет его прочитать. В этом случае в начале файла нужно заменить эти три байта на FF FE (маркер UTF-16LE).

Способ 2. Работа через ЧтениеТекста с явным указанием кодировки

Если «сдвига» байтов нет, а проблема только в лишних нулевых символах (например, весь файл — честный UTF-16, но без BOM), мы можем попробовать прочитать его, принудительно указав кодировку UTF-16. Рассмотрим, как это сделать правильно:


Текст = Новый ЧтениеТекста;
// Указываем кодировку UTF-16 явно
Текст.Открыть(ПутьКФайлу, "UTF-16");
Содержимое = Текст.Прочитать();
Текст.Закрыть();

// Теперь заменяем ошибочный заголовок, если он мешает парсеру
Содержимое = СтрЗаменить(Содержимое, "encoding=""UTF-8""", "encoding=""UTF-16""");

// Записываем исправленный текст обратно в UTF-8 для стандартного ЧтениеXML
ТекстЗаписи = Новый ЗаписьТекста(ПутьКФайлуИсправленный, КодировкаТекста.UTF8);
ТекстЗаписи.Записать(Содержимое);
ТекстЗаписи.Закрыть();

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

Способ 3. Декодирование данных Base64

Проанализируем содержимое атрибута BarCodeBase64 из примера. Даже если сам XML выглядит странно, данные внутри часто упакованы в Base64. После того как вы восстановили структуру XML и смогли прочитать узлы, вам потребуется декодировать значения.

В 1С для этого используется объект Base64Значение. Посмотрим на пример обработки строки из файла:


// Пример значения из атрибута: "MjA4MTA0NzU3ODUxNA=="
ЗначениеBase64 = "MjA4MTA0NzU3ODUxNA==";
ДвоичныеДанныеШтрихкода = Base64Значение(ЗначениеBase64);
ШтрихкодТекст = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанныеШтрихкода, КодировкаТекста.UTF8);
// Результат: "2081047578514"

Рекомендации по настройке ТСД

Чтобы не заниматься «лечением» файлов в 1С, рекомендуется проверить настройки самого ТСД и его программного обеспечения:

Используя предложенные методы бинарной коррекции, вы сможете стабильно загружать данные в 1С даже из «проблемных» устройств, обеспечивая корректный учет товаров и оборудования.

← На главную