При интеграции систем и обмене данными через XML-формат разработчики 1С часто сталкиваются со специфическим поведением фабрики XDTO. Классическая проблема возникает тогда, когда узел XML-документа содержит одновременно и атрибуты, и текстовое значение. Проанализируем типичный пример такого элемента:
<casdo:CustomsTaxModeCode codeListId="2010">2010</casdo:CustomsTaxModeCode>
С чтением атрибута codeListId сложностей не возникает — платформа автоматически сопоставляет его со свойством объекта XDTO. Но как получить само текстовое значение (в данном примере — «2010»)? Напрямую обратиться к какому-то свойству вроде Значение или Текст у динамически прочитанного объекта невозможно, так как платформа не знает структуры документа заранее.
В этой статье мы подробно разберем, почему возникает эта проблема, как безопасно извлечь текст программно, а также рассмотрим архитектурно правильный способ решения задачи с помощью предварительной настройки XDTO-пакета.
Выясним, почему платформа 1С ведет себя именно так при динамическом чтении XML. Когда мы используем методы ЧтениеXML и ФабрикаXDTO.ПрочитатьXML() без жестко заданной схемы (XSD) в конфигурации, платформа анализирует структуру «на лету»:
<ModeCode>2010</ModeCode>), 1С прочитала бы его как простое ЗначениеXDTO (XDTOValue). В этом случае его значение было бы доступно напрямую.XDTODataObject) универсального типа xsd:anyType.Sequence).Попытка обратиться напрямую к объекту вернет только список его свойств-атрибутов, а сам текст останется «скрытым» внутри последовательности.
Рассмотрим первый способ решения проблемы в режиме реального времени, когда структура XML читается динамически. Один из участников обсуждения предложил использовать метод ПолучитьТекст(0) из последовательности объекта XDTO. Посмотрим на этот подход подробнее.
Действительно, простой вызов выглядит следующим образом:
Последовательность = ОбъектXDTO.Последовательность();
Значение = Последовательность.ПолучитьТекст(0);
Важное предупреждение: Использование жестко заданного индекса (0) в реальной разработке крайне небезопасно! Если в XML-файле перед текстом случайно окажутся символы переноса строки, лишние пробелы, комментарии или другие вложенные элементы, индекс текста сместится. Это приведет к тому, что код либо вернет пустую строку, либо вызовет критическую ошибку «Индекс находится за границами диапазона».
Разберем безопасный алгоритм обхода последовательности, который гарантирует корректное извлечение текста в любых условиях:
// Открываем файл и считываем объект XDTO
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
// Получаем последовательность объекта
Последовательность = ОбъектXDTO.Последовательность();
КолвоЭлементов = Последовательность.Количество();
ЗначениеТекста = "";
// Безопасный обход элементов последовательности в цикле
Для Индекс = 0 По КолвоЭлементов - 1 Цикл
// Если ПолучитьСвойство() возвращает Неопределено — значит, на этой позиции расположен текст
Если Последовательность.ПолучитьСвойство(Индекс) = Неопределено Тогда
ТекстовыйФрагмент = Последовательность.ПолучитьТекст(Индекс);
// Очищаем от возможных системных пробелов и переносов строк
ЗначениеТекста = СокрЛП(ТекстовыйФрагмент);
Если Не ПустаяСтрока(ЗначениеТекста) Тогда
Прервать; // Текст успешно найден
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Теперь в переменной ЗначениеТекста гарантированно находится "2010"
ЧтениеXML.Закрыть();
Этот код универсален. Он перебирает все элементы последовательности, определяет, какие из них являются текстовыми фрагментами (у них отсутствует свойство XDTO), очищает их от пробельных символов и собирает итоговое значение.
Если вы регулярно работаете с файлами определенной структуры (например, отчетность регулирующих органов, таможенные декларации, банковские выписки), динамическое чтение через xsd:anyType усложняет код. Гораздо эффективнее импортировать XSD-схему в конфигурацию в виде XDTO-пакета.
В этом случае платформа предоставляет специализированный механизм настройки свойств. Выясним, как правильно настроить тип объекта XDTO в конфигураторе 1С, чтобы напрямую считывать текстовые данные:
Значение).При использовании формы представления «Текст» в конфигураторе накладываются жесткие системные ограничения, о которых необходимо помнить:
Если тип настроен верно (создано свойство-атрибут codeListId с формой «Атрибут» и свойство Значение с формой «Текст»), то чтение XML-кода становится максимально простым и лаконичным:
// Чтение с использованием готового типа из XDTO-пакета
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
// Происходит автоматическая валидация по схеме
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ФабрикаXDTO.Тип("http://www.customs.ru/casdo", "CustomsTaxModeCode"));
// Прямой доступ к данным без использования последовательностей
КодСписка = ОбъектXDTO.codeListId; // Получим значение атрибута: "2010"
ЗначениеКода = ОбъектXDTO.Значение; // Получим текстовое значение элемента: "2010"
ЧтениеXML.Закрыть();
Рассмотрим обратную задачу: когда вам необходимо сформировать подобный XML-узел программно и отправить его внешнему контрагенту.
Если вы попытаетесь собрать такой объект динамически без XDTO-пакета, напрямую добавляя текст в последовательность xsd:anyType через метод Добавить(), платформа может выдать ошибку, так как динамические типы не поддерживают свободную запись смешанного содержимого без жестких правил схемы.
С использованием предварительно настроенного XDTO-пакета создание объекта превращается в тривиальное заполнение полей:
// Создаем новый объект по схеме из XDTO-пакета
ТипИзПакета = ФабрикаXDTO.Тип("http://www.customs.ru/casdo", "CustomsTaxModeCode");
НовыйОбъект = ФабрикаXDTO.Создать(ТипИзПакета);
// Заполняем атрибуты и текст
НовыйОбъект.codeListId = "2010"; // Свойство с формой "Атрибут"
НовыйОбъект.Значение = "2010"; // Свойство с формой "Текст"
// Записываем объект в XML-файл
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлуДляЗаписи);
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, НовыйОбъект);
ЗаписьXML.Закрыть();
При выгрузке платформа 1С самостоятельно проанализирует метаданные свойств, определит их формы и сгенерирует абсолютно валидный XML-код, содержащий как заполненный атрибут, так и текстовое тело элемента.
Используйте рассмотренные нами методы работы с последовательностями для быстрого и безопасного разбора сторонних XML-файлов «на лету», а для крупных интеграционных проектов всегда проектируйте полноценные XDTO-пакеты с формой свойств «Текст» — это сделает ваш код чистым, понятным и производительным.