При обмене данными через формат XML программисты 1С часто сталкиваются с неожиданным поведением парсеров. Одна из самых коварных ошибок — искажение числовых значений, когда, например, число 20.0 при загрузке превращается в 200. На первый взгляд код кажется верным, файл в текстовом редакторе выглядит корректно, но объектная модель документа (DOM) выдает неверный результат. Проанализируем эту ситуацию, выясним причины такого поведения и рассмотрим надежные способы решения проблемы.
Рассмотрим фрагмент кода, с которого обычно начинаются подобные проблемы. Программист пытается прочитать файл, используя объект ПостроительDOM. Однако даже на этапе инициализации чтения часто допускаются опечатки, которые могут усложнить отладку. Посмотрим на пример:
// Ошибка в названии переменной и подходе
ЗаписьXML = Новый ЧтениеXML; // Используется объект чтения, но назван как запись
ЗаписьXML.ОткрытьФайл(Объект.ИмяКаталога,,,"UTF-8");
Построитель = Новый ПостроительDOM;
Документ = Построитель.Прочитать(ЗаписьXML);
Первое, на что стоит обратить внимание: объект ПостроительDOM строит дерево объектов в оперативной памяти. Если во входном потоке ЧтениеXML встречаются символы, которые парсер не может однозначно интерпретировать как часть текстового узла, или если разделитель представлен в виде специальной сущности, результат может быть непредсказуемым. Выясним, почему точка может «исчезнуть».
Одной из наиболее вероятных причин является то, что точка в исходном XML-файле записана не как обычный символ ASCII (код 46), а как HTML-сущность, например, .. Рассмотрим подробнее: при визуальном просмотре в браузере или продвинутом текстовом редакторе такая запись автоматически отображается как точка. Однако ПостроительDOM при определенных настройках может проигнорировать неизвестную или некорректно экранированную сущность, просто «склеив» стоящие рядом цифры.
Если система, выгрузившая файл, произвела двойное кодирование спецсимволов, парсер 1С воспримет 20.0 как текстовый узел 20 и еще один узел, который может быть отброшен, если он не соответствует стандартам XML в текущем контексте. В итоге мы получаем значение 200.
Объект ПостроительDOM по своей сути работает со строками. Для него значение между тегами <Quantity> — это просто набор символов. Если мы хотим, чтобы 1С понимала, что перед нами число, и правильно обрабатывала разделители, необходимо использовать типизацию. Без четко заданной схемы (XSD) система не знает, является ли точка десятичным разделителем или разделителем групп разрядов (как это бывает в некоторых региональных стандартах).
Проанализируем наиболее профессиональный и надежный способ загрузки XML-данных. Вместо простого перебора узлов DOM-дерева, воспользуемся механизмом XDTO. Этот метод позволяет автоматически преобразовывать строковые значения из XML в соответствующие типы данных 1С (Число, Дата, Булево).
Выполним следующие шаги для настройки загрузки:
Quantity тип xs:decimal.
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);
// Используем типизированное чтение через фабрику
Попытка
Данные = ФабрикаXDTO.ПрочитатьXML(Чтение);
Количество = Данные.Quantity; // Здесь уже будет тип Число
Исключение
Сообщить("Ошибка разбора XML: " + ОписаниеОшибки());
КонецПопытки;
Важный момент: Если использовать ФабрикаXDTO.ПрочитатьXML() без заранее определенной схемы, система все равно будет считывать данные как тип AnyType (строки), и проблема с точкой может сохраниться. Поэтому наличие схемы критически важно для корректного преобразования типов.
Если построение DOM-дерева не является обязательным требованием, рассмотрим альтернативный подход — последовательное чтение файла с помощью объекта ЧтениеXML. Этот метод потребляет меньше памяти и позволяет более гибко контролировать процесс обработки каждого узла. Проанализируем пример обхода:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "Quantity" Тогда
ЧтениеXML.Прочитать(); // Переходим к текстовому содержимому
ЗначениеСтрокой = ЧтениеXML.Значение;
// Принудительно заменяем возможные проблемы и преобразуем в число
// Учитываем, что в XML разделитель всегда точка
ЧисловоеЗначение = Число(СтрЗаменить(ЗначениеСтрокой, " ", ""));
// Дальнейшая логика
КонецЕсли;
КонецЦикла;
В данном случае мы работаем с «сырым» строковым значением. Если проблема была в специфических невидимых символах или некорректных сущностях, метод ЧтениеXML.Значение часто возвращает более предсказуемый результат, чем нормализованный узел ПостроителяDOM.
Как показывает практика, часто проблема решается не на стороне 1С, а на стороне системы-источника. Выясним причины формирования «плохого» XML. Если отправитель использует специфические библиотеки для формирования файлов (например, старые версии PHP или самописные скрипты на Python), они могут принудительно экранировать точку.
Нужно убедиться, что:
или #160), которые могут вклиниваться между цифрами при форматировании чисел на стороне отправителя.Резюме: Если вы столкнулись с превращением 20.0 в 200, в первую очередь проверьте файл в HEX-редакторе на наличие скрытых символов. Затем попробуйте сменить ПостроительDOM на ЧтениеXML или применить ФабрикуXDTO с жестко заданной XSD-схемой. Это обеспечит корректную интерпретацию типов данных и стабильную работу вашей интеграции.