При работе с интеграциями и разборе XML-файлов в 1С:Предприятии программисты часто сталкиваются с ситуацией, когда при чтении XML в ОбъектXDTO некоторые значения как будто «исчезают». Вроде бы тег в файле есть, и текст внутри него присутствует, но при обращении к свойству объекта через точку мы получаем пустоту или неопределенность. Рассмотрим подробнее, почему так происходит и как правильно извлекать данные в таких случаях.
Проблема, с которой мы столкнулись, чаще всего связана с тем, что в структуре XML элемент определяется как тип со смешанным содержимым. В терминах XML это означает, что узел может содержать одновременно и вложенные дочерние теги, и просто текстовые фрагменты. Платформа 1С, встречая такой узел, не может однозначно сопоставить текст какому-то конкретному именованному свойству XDTO, так как у обычного текста в XML-схеме нет собственного имени.
Проанализируем ситуацию: когда мы используем метод ФабрикаXDTO.ПрочитатьXML() без жестко заданной схемы (XSD), 1С строит тип объекта «на лету». Если внутри тега, например <param>, находится текст, платформа помещает его в специальный системный механизм — ПоследовательностьXDTO (Sequence). Именно поэтому прямое обращение к ОбъектXDTO.param возвращает ссылку на объект или список, но не само текстовое значение.
Как выяснилось в ходе обсуждения, самым быстрым способом добраться до «скрытых» данных является обращение к свойству Последовательность. Это свойство хранит все элементы узла в порядке их следования в XML, включая текстовые блоки.
Рассмотрим пример кода, который позволяет получить текст из первого элемента списка:
// Предположим, ОбъектXDTO уже прочитан из ЧтениеXML
Если ОбъектXDTO.Свойства().Получить("param") <> Неопределено Тогда
// Обращаемся к последовательности конкретного элемента
ЗначениеТекста = ОбъектXDTO.param[0].Последовательность().ПолучитьТекст(0);
Сообщить(ЗначениеТекста);
КонецЕсли;
Важно помнить, что метод ПолучитьТекст() принимает индекс текстового блока. Если текст внутри тега разбит другими тегами или комментариями, текстовых блоков может быть несколько. Метод ПолучитьТекст(0) вернет только первый фрагмент.
Поскольку индексное обращение может быть рискованным (мы не всегда знаем, на какой позиции находится текст), проанализируем более надежный способ — перебор всей последовательности объекта. Этот метод позволяет гарантированно собрать весь текст, даже если он разделен вложенными узлами.
Посмотрим на пример реализации такого обхода:
ТекстРезультат = "";
Последовательность = ОбъектXDTO.Последовательность();
Для Индекс = 0 По Последовательность.Количество() - 1 Цикл
// Проверяем, является ли текущий элемент последовательности текстом
// Текстовые узлы в последовательности не имеют метаданных свойства
Если Последовательность.ПолучитьСвойство(Индекс) = Неопределено Тогда
ТекстРезультат = ТекстРезультат + Последовательность.ПолучитьТекст(Индекс);
КонецЕсли;
КонецЦикла;
Сообщить("Полный текст узла: " + ТекстРезультат);
Этот подход особенно полезен при разборе сложных форматов, таких как YML (Yandex Market Language) или выгрузки из интернет-магазинов, где описания товаров могут содержать как текст, так и HTML-подобную разметку внутри одного тега.
Иногда поведение ЧтениеXML влияет на то, как XDTO интерпретирует данные. При установке параметров чтения можно указать, как обрабатывать пробельные символы и CDATA. Выясним, как правильно инициализировать чтение, чтобы минимизировать потерю данных:
ЧтениеXML = Новый ЧтениеXML;
// Параметры: ... Игнорировать пробелы = Истина, Расширять префиксы = Истина
ПараметрыЧтенияХМЛ = Новый ПараметрыЧтенияXML(,,,,,,,,Истина, Истина);
ЧтениеXML.УстановитьСтроку(ТекущаяСтрока, ПараметрыЧтенияХМЛ);
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
Использование флага ИгнорироватьПробелы помогает избавиться от лишних «пустых» текстовых узлов в последовательности, оставляя только значимую информацию.
Если работа с ПоследовательностьXDTO кажется слишком громоздкой или методы 1С ведут себя непредсказуемо, можно рассмотреть вариант с использованием ПостроительDOM. Хотя в обсуждении упоминалось, что это более трудоемкий процесс, он дает полный контроль над структурой документа.
Проанализируем, как это работает:
ЧтениеXML и загружаем в него данные.ПостроительDOM для получения ДокументDOM.ТекстовоеСодержимое (TextContent) узла.Пример кода через DOM:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекущаяСтрока);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
СписокУзлов = ДокументDOM.ПолучитьЭлементыПоИмени("param");
Для Каждого Узел Из СписокУзлов Цикл
// Свойство ТекстовоеСодержимое соберет весь текст внутри тега автоматически
Значение = Узел.ТекстовоеСодержимое;
Сообщить(Значение);
КонецЦикла;
XDTO (через последовательность) эффективен, когда вам нужно быстро преобразовать XML в объектную модель и вы точно знаете структуру. Однако слабая документированность методов вроде ПолучитьТекст() заставляет разработчиков тратить время на поиск решений.
DOM является «стандартом де-факто» для работы с произвольными XML-документами. Главное преимущество здесь — свойство ТекстовоеСодержимое, которое избавляет от необходимости вручную склеивать фрагменты из последовательности. Однако DOM потребляет больше оперативной памяти, так как загружает всё дерево документа целиком.
Подводя итог, если вы столкнулись с «пустыми» значениями в ОбъектXDTO, первым делом проверьте наличие свойства Последовательность. В 90% случаев данные находятся именно там, скрытые механизмом обработки смешанного содержимого платформы 1С.