Как получить данные из объекта XDTO и обойти свойства в 1С

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

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

Проанализируем ситуацию, выясним причины такого поведения платформы 1С:Предприятие и разберем по шагам, как правильно извлекать данные из объектов XDTO, а также какие альтернативные подходы к разбору XML существуют.

Почему возникают ошибки при обращении к ОбъектXDTO

Для понимания проблемы разберем внутреннюю архитектуру работы механизмов XDTO в платформе 1С:

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

Способ 1. Правильный обход свойств объекта XDTO в цикле

Посмотрим на пример правильного перебора всех доступных свойств, входящих в состав конкретного ОбъектXDTO. Коллекцией является не сам объект, а результат вызова его метода Свойства(), который возвращает СписокXDTO с описаниями реквизитов.

Рассмотрим код для обхода свойств:


Для Каждого СвойствоXDTO Из ПолеОбъектXDTO.Свойства() Цикл
    ИмяСвойства = СвойствоXDTO.Имя;
    
    // Проверяем, заполнено ли свойство в объекте
    Если ПолеОбъектXDTO.Установлено(ИмяСвойства) Тогда
        Значение = ПолеОбъектXDTO[ИмяСвойства];
        // Выполняем обработку значения
    КонецЕсли;
КонецЦикла;

Обратите внимание на метод Установлено(): он позволяет избежать ошибок при попытке прочитать опциональное свойство, значение которого не было передано в XML-файле.

Способ 2. Получение текстового содержимого через последовательность

Если тег содержит внутри себя просто текст, но был прочитан как нетипизированный ОбъектXDTO, его свойства будут пустыми, а метод Свойства().Количество() вернет ноль. В таком случае значение хранится в виде последовательности XML.

Разберем, как прочитать этот текст программно:


Если ПолеОбъектXDTO.Последовательность().Количество() > 0 Тогда
    ТекстЗначения = ПолеОбъектXDTO.Последовательность().ПолучитьТекст(0);
КонецЕсли;

Способ 3. Использование явной типизации при чтении

Чтобы фабрика не создавала пустые или универсальные структуры xsd:anyType, при чтении следует передавать ожидаемый тип данных из схемы (пакета XDTO). Если тип задан строго, платформа автоматически сопоставит XML-теги со структурой свойств.


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("имяфайла.xml");

ТипДанных = ФабрикаXDTO.Тип("http://v8.1c.ru/edi/edi_stnd", "ИмяТипаДанных");
Данные = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипДанных);

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

Способ 4. СериализаторXDTO для штатных выгрузок 1С

Если файл был сформирован штатными механизмами платформы 1С (например, выгрузка в XML через метод ЗаписатьXML()), ручной разбор через ФабрикаXDTO избыточен. Гораздо проще применить СериализаторXDTO, который автоматически восстанавливает прикладные типы 1С (структуры, таблицы значений, ссылки):


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("имяфайла.xml");

Данные = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);

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

Способ 5. Потоковое чтение больших XML-файлов через ЧтениеXML

Когда речь идет о журнале регистрации или объемных выгрузках, чтение через ФабрикаXDTO.ПрочитатьXML() или ПостроительDOM может привести к аварийной остановке с ошибкой Недостаточно памяти. Фабрика строит полное дерево объектов в оперативной памяти целиком.

Для обхода больших файлов оптимально использовать прямое последовательное чтение через объект ЧтениеXML. Проанализируем пример такого потокового обхода:


Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("имяфайла.xml");

Пока Чтение.Прочитать() Цикл
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        ИмяУзла = Чтение.Имя;
        
        // Читаем атрибуты, если они есть
        Пока Чтение.ПрочитатьАтрибут() Цикл
            ИмяАтрибута = Чтение.Имя;
            ЗначениеАтрибута = Чтение.Значение;
        КонецЦикла;
        
    ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст Тогда
        ЗначениеТекста = Чтение.Значение;
        
    ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
        // Обработка завершения чтения тега
    КонецЕсли;
КонецЦикла;

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

Такой подход читает XML-файл построчно и фрагментарно, потребляет минимальное количество оперативной памяти и успешно справляется с файлами объемом в сотни мегабайт и гигабайты.

← На главную