Как прочитать текстовое значение XML-узла с атрибутами через XDTO в 1С

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

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

В этой статье мы подробно разберем, почему возникает эта проблема, детально проанализируем внутреннее устройство XDTO в 1С, изучим быстрый способ обхода ограничения с помощью последовательностей, предотвратим опасные ошибки парсинга единичных элементов и рассмотрим наиболее надежные архитектурные решения — создание собственного пакета XDTO и использование объектной модели DOM.

Выясняем причину: архитектура смешанного содержимого в XDTO

Для того чтобы понять, почему 1С не показывает текстовое значение тега напрямую, нам необходимо заглянуть под капот механизма XDTO. Когда мы читаем XML-файл с помощью глобальной фабрики XDTO без предварительного указания конкретной XSD-схемы (то есть динамически), платформа создает объекты типов по умолчанию. Для узлов с атрибутами и текстом создается тип anyType пространства имен http://www.w3.org/2001/XMLSchema.

С точки зрения стандартов XML, такой узел представляет собой элемент со смешанным содержимым (mixed content). Платформа 1С обрабатывает его следующим образом:

  1. Все атрибуты узла XML (в нашем примере это InsertDate) преобразуются в именованные свойства созданного объекта ОбъектXDTO. К ним можно легко обратиться напрямую: КодXDTO.InsertDate.
  2. Поскольку у самого текстового значения внутри тега нет явного имени (это не дочерний тег, а просто текст), платформа не может сопоставить его ни с одним стандартным свойством.
  3. Чтобы не потерять эти данные, 1С помещает весь текст в специальную внутреннюю коллекцию объекта — Последовательность XDTO (ПоследовательностьXDTO). Она хранит элементы данных в порядке их следования в XML-документе.

Попытка прочитать значение тега напрямую через обращение к свойству или через метод Получить() не принесет результата, так как это свойство просто не спроецировано в структуру объекта как стандартное поле.

Решение №1: Быстрое чтение через Последовательность XDTO

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

Рассмотрим пример кода, который позволяет получить текст первого элемента:


// Получаем текст из последовательности конкретного объекта XDTO
ТекстКода = ОбъектКода.Последовательность().ПолучитьТекст(0);

В данном случае индекс 0 указывает на то, что мы берем самый первый текстовый блок внутри тега. Метод работает стабильно, если структура XML строго фиксирована и внутри тега гарантированно нет лишних переносов строк, комментариев или вложенных подтегов, которые могли бы сместить индекс текста в последовательности.

Опасность «ловушки единичного элемента» и ее обход

При использовании быстрого метода чтения через последовательности программисты часто совершают критическую ошибку, которая приводит к падению системы в реальной эксплуатации. Эта проблема называется ловушкой единичного элемента.

Проанализируем поведение платформы 1С при чтении списков XML-элементов через фабрику XDTO без явной схемы:

  1. Если в XML-файле внутри родительского тега содержится несколько дочерних тегов (например, два и более тегов <Code>), фабрика XDTO автоматически преобразует их в коллекцию — СписокXDTO. В этом случае обращение по индексу вида обХДТО.Code[0] отработает корректно.
  2. Если же во входящем файле окажется ровно один тег <Code>, платформа 1С не станет создавать список. Она прочитает этот элемент как одиночный ОбъектXDTO. Попытка обратиться к нему как к массиву (обХДТО.Code[0]) вызовет критическую ошибку выполнения: «Получение элемента по индексу для значения не разрешено».

Чтобы ваш код работал надежно при любом количестве элементов во входящем XML-файле, необходимо всегда выполнять проверку типа возвращаемого значения. Посмотрим на пример универсального и безопасного алгоритма:


// Проверяем, существует ли свойство "Code" в прочитанном объекте
Если обХДТО.Свойства().Получить("Code") <> Неопределено Тогда
    
    ЗначениеCode = обХДТО.Code;
    
    Если ТипЗнч(ЗначениеCode) = Тип("СписокXDTO") Тогда
        // Сценарий 1: В файле найдено несколько кодов маркировки (это список)
        Для Каждого Элемент Из ЗначениеCode Цикл
            Если Элемент.Последовательность().Количество() > 0 Тогда
                ТекстКода = Элемент.Последовательность().ПолучитьТекст(0);
                // Выполняем обработку полученного текста кода
                ЗаписатьКодВБазу(ТекстКода, Элемент.InsertDate);
            КонецЕсли;
        КонецЦикла;
        
    ИначеЕсли ТипЗнч(ЗначениеCode) = Тип("ОбъектXDTO") Тогда
        // Сценарий 2: В файле присутствует только один код (это одиночный объект)
        Если ЗначениеCode.Последовательность().Количество() > 0 Тогда
            ТекстКода = ЗначениеCode.Последовательность().ПолучитьТекст(0);
            // Выполняем обработку единственного кода
            ЗаписатьКодВБазу(ТекстКода, ЗначениеCode.InsertDate);
        КонецЕсли;
    КонецЕсли;
    
КонецЕсли;

Этот подход гарантирует стабильность работы интеграции независимо от объема передаваемых данных.

Решение №2: Программный перебор последовательности без привязки к индексу

Обращение к тексту по жесткому индексу ПолучитьТекст(0) не всегда безопасно. В реальных XML-файлах перед полезным текстом могут находиться невидимые символы форматирования, пробелы, знаки переноса строк или XML-комментарии. В таких случаях индекс полезного текста может оказаться отличным от нуля.

Рассмотрим более надежный способ обхода последовательности. Мы будем программно перебирать все элементы последовательности объекта XDTO и искать именно текстовые узлы:


Последовательность = ЭлементКода.Последовательность();
ТекстКода = "";

Для Индекс = 0 По Последовательность.Количество() - 1 Цикл
    // Если метод ПолучитьСвойство возвращает Неопределено, 
    // значит данный элемент последовательности является простым текстом, а не дочерним свойством
    Если Последовательность.ПолучитьСвойство(Индекс) = Неопределено Тогда
        ТекстКода = СокрЛП(Последовательность.ПолучитьТекст(Индекс));
        Если Не ПустаяСтрока(ТекстКода) Тогда
            // Нашли полезное текстовое содержимое, выходим из цикла
            Прервать;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Использование этого алгоритма полностью защищает ваш код от сдвигов структуры внутри тегов XML.

Решение №3: Создание пакета XDTO и использование свойства __content

Использование последовательностей — отличный обходной путь, однако с точки зрения архитектуры 1С правильным и наиболее производительным решением является типизация данных. Для этого необходимо импортировать или вручную создать схему XML (пакет XDTO) в вашей конфигурации.

Разберем по шагам, как правильно настроить схему XDTO для чтения смешанного содержимого:

  1. В ветке метаданных конфигурации Общие -> XDTO-пакеты добавьте новый пакет. Вы можете импортировать готовую схему XSD (если она предоставлена разработчиками внешней системы) либо описать структуру вручную.
  2. Создайте тип объекта (например, CodeType).
  3. Добавьте в этот тип свойство для атрибута. Назовите его InsertDate, укажите тип (например, dateTime) и обязательно установите свойство Форма представления в значение Атрибут.
  4. Добавьте свойство для хранения самого текстового значения кода маркировки. Задайте ему имя (в платформе 1С для таких целей по умолчанию используется системное имя __content, но вы можете назвать его по своему усмотрению, например, Значение). Установите для этого свойства Форма представления в значение Текст.

После того как схема создана и привязана к чтению XML-документа, платформа 1С автоматически сопоставит текстовое содержимое тега с вашим свойством __content. Код разбора XML станет лаконичным, легко читаемым и быстрым:


// Пример чтения XML с использованием типизированного пакета XDTO
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

// Читаем объект с указанием типа из нашего пакета XDTO
ОбъектМаркировки = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ФабрикаXDTO.Тип("http://www.yourdomain.ru/marks", "MarkCodes"));

Для Каждого Элемент Из ОбъектМаркировки.Code Цикл
    // Чтение атрибута и значения теперь выполняется максимально просто "через точку"
    ДатаСоздания = Элемент.InsertDate;
    ТекстКода    = Элемент.__content; // или имя, которое вы задали в схеме
    
    // Обработка данных...
КонецЦикла;

ЧтениеXML.Закрыть();

Главное преимущество этого способа — отсутствие необходимости писать сложные разветвленные проверки типов и вручную обходить последовательности. Платформа 1С берет всю рутину по парсингу структуры на себя.

Решение №4: Альтернативный разбор через объектную модель DOM

Если создание пакета XDTO по каким-то причинам невозможно (например, схема часто меняется внешним поставщиком услуг, а решение должно быть максимально гибким), а писать громоздкий код обработки последовательностей XDTO не хочется, можно полностью отказаться от XDTO в пользу технологии DOM (Document Object Model).

Объектная модель документов DOM загружает весь XML-файл в память в виде дерева объектов. Она лишена недостатка XDTO, связанного с разделением на списки и одиночные объекты, и позволяет одинаково просто обращаться как к атрибутам, так и к текстовому наполнению любых узлов.

Проанализируем пример реализации чтения XML через DOM:


// Открываем файл для чтения
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);

// Строим объектную модель документа (DOM)
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);

// Получаем все элементы с именем тега "Code" независимо от уровня их вложенности
СписокЭлементов = ДокументDOM.ПолучитьЭлементыПоИмени("Code");

Для Каждого ЭлементDOM Из СписокЭлементов Цикл
    // Извлечение значения атрибута "InsertDate"
    ДатаВставки = ЭлементDOM.ПолучитьАтрибут("InsertDate");
    
    // Извлечение текстового содержимого, находящегося внутри тега
    ТекстКода = СокрЛП(ЭлементDOM.ТекстовоеСодержимое);
    
    // Выполняем дальнейшие операции с данными
    ОбработатьДанныеDOM(ТекстКода, ДатаВставки);
КонецЦикла;

// Обязательно закрываем файл чтения
ЧтениеXML.Закрыть();

Этот способ крайне надежен, лаконичен и отлично подходит для файлов небольшого и среднего размера. Однако стоит учитывать, что DOM загружает весь файл в оперативную память целиком, поэтому для обработки очень больших файлов (от 100 Мегабайт и выше) лучше использовать последовательное чтение через ЧтениеXML или оптимизированные пакеты XDTO.

Сравнительный анализ решений

Для того чтобы выбрать наиболее подходящий метод для вашего проекта, сопоставим рассмотренные подходы по ключевым критериям:

  1. Метод через Последовательность XDTO: Отличное быстрое решение для разовых задач. Не требует изменения метаданных конфигурации. Минусы: требует написания громоздких проверок типов из-за «ловушки единичного элемента» и аккуратного обращения с индексами текстовых узлов.
  2. Типизированный пакет XDTO (свойство __content): Самый производительный и красивый с точки зрения архитектуры подход. Код получается чистым и понятным. Идеально для постоянных интеграционных процессов с фиксированным форматом обмена. Минус: требует внесения изменений в метаданные (создания XDTO-пакета).
  3. Объектная модель DOM: Простой и надежный способ без жесткой привязки к схемам. Код не зависит от количества элементов в файле. Минус: повышенное потребление оперативной памяти при разборе больших объемов данных.

Рекомендуем всегда отдавать предпочтение созданию полноценных пакетов XDTO. Это гарантирует высокую скорость выполнения операций, строгую типизацию данных и упрощает дальнейшую поддержку программного кода вашими коллегами. Для предварительного контроля входящих файлов на соответствие правилам схемы можно использовать инструмент для проверки валидности XML-файлов по схеме XSD или пакету XDTO.

← На главную