Как определить тип документа по первому тегу в XML при использовании ФабрикиXDTO

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При интеграции 1С с внешними системами часто возникает задача обработки больших XML-файлов. Традиционный подход с использованием объекта ПостроительDOM прост в реализации, но имеет существенный недостаток: он считывает весь файл в оперативную память целиком. Для файлов объемом в десятки и сотни мегабайт это приводит к критическому замедлению работы или ошибке "Недостаточно памяти".

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

Способ 1. Последовательное чтение через ЧтениеXML

Самый простой и эффективный способ — это «подсмотреть» имя корневого элемента до того, как основной механизм XDTO начнет разбор файла. Объект ЧтениеXML позволяет перемещаться по узлам документа последовательно, не загружая его целиком.

Рассмотрим по шагам, как реализовать этот алгоритм:

  1. Создадим объект ЧтениеXML и откроем файл.
  2. Используем метод Прочитать() или ПерейтиКСодержимому(), чтобы встать на первый значащий узел (корневой элемент).
  3. Проанализируем свойство Имя или ЛокальноеИмя.
  4. Передадим этот же объект ЧтениеXML в метод Фабрики для окончательной загрузки.

Пример кода для реализации этого подхода:


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

// Переходим к первому элементу (пропуская заголовки и комментарии)
Пока Чтение.Прочитать() Цикл
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        Прервать;
    КонецЕсли;
КонецЦикла;

ИмяДокумента = Чтение.ЛокальноеИмя;

Если ИмяДокумента = "ЗаявкаПокупателя" Тогда
    // Выполняем загрузку через ФабрикуXDTO
    ТипОбъекта = ФабрикаXDTO.Тип("http://www.your-namespace.com", "Заявка");
    ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(Чтение, ТипОбъекта);
ИначеЕсли ИмяДокумента = "ВозвратТоваров" Тогда
    // Обработка другого типа документа
КонецЕсли;

Важный нюанс: Метод ФабрикаXDTO.ПрочитатьXML(Чтение) начинает чтение именно с той позиции, на которой сейчас находится указатель объекта ЧтениеXML. Если вы уже «прочитали» корневой тег, Фабрика начнет искать данные внутри него, что и позволяет нам гибко управлять логикой загрузки.

Способ 2. Правильное проектирование XSD-схемы (Salami Slice)

Если мы хотим, чтобы ФабрикаXDTO автоматически понимала тип документа без лишних условий в коде, нам необходимо обратить внимание на структуру используемого пакета XDTO (XSD-схемы). Существует несколько подходов к проектированию схем, и для автоматического распознавания корня лучше всего подходит структура Salami Slice (Нарезанная салями).

В этой структуре каждый потенциальный корневой элемент объявляется в схеме как глобальный элемент (element), а не просто как тип (complexType). Проанализируем разницу:

Выясним причину появления anyType в отладчике: это часто происходит, когда Фабрика находит пространство имен, но не видит в пакете XDTO объявленного глобального элемента с соответствующим именем. Проверьте свойства вашего пакета XDTO в конфигураторе: во вкладке "Объекты" должны быть именно Элементы, а не только Типы объектов.

Способ 3. Оптимизация работы с очень большими файлами

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

Разберем алгоритм «порционного» чтения:

  1. С помощью ЧтениеXML доходим до начала повторяющегося блока (например, тег <СтрокаТовара>).
  2. Внутри цикла вызываем ФабрикаXDTO.ПрочитатьXML(Чтение, ТипСтроки).
  3. Обрабатываем одну строку, записываем данные в базу или массив и переходим к следующей итерации.
  4. После завершения цикла закрываем чтение.

Этот метод объединяет в себе строгость типов XDTO и минимальное потребление оперативной памяти, свойственное последовательному чтению.


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

ИмяКорня = Чтение.ЛокальноеИмя;

Пока Чтение.Прочитать() Цикл
    // Ищем начало табличной части
    Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.ЛокальноеИмя = "Строка" Тогда
        // Читаем только один элемент в объект XDTO
        СтрокаОбъект = ФабрикаXDTO.ПрочитатьXML(Чтение, ФабрикаXDTO.Тип(URI, "ТипСтроки"));
        // Обрабатываем данные...
    КонецЕсли;
КонецЦикла;

Рекомендации по повышению надежности

Проанализируем еще несколько важных моментов, которые помогут избежать ошибок при загрузке:

1. Использование URI пространства имен. Проверка только по ЛокальноеИмя может быть ненадежной, если в систему могут поступать файлы разных форматов с одинаковыми именами тегов. Всегда проверяйте Чтение.URIПространстваИмен, чтобы убедиться, что файл соответствует ожидаемому стандарту.

2. Метод ПерейтиКСодержимому(). Вместо ручного цикла Пока Чтение.Прочитать() рекомендуется использовать встроенный метод ПерейтиКСодержимому(). Он автоматически пропускает пролог XML, инструкции обработки, комментарии и пустые текстовые узлы, позиционируя чтение на первом важном элементе.

3. Валидация. Если файл может прийти с ошибками структуры, полезно включить валидацию по схеме. Для этого при открытии файла в ЧтениеXML передаются параметры чтения с указанием схемы. Это позволит 1С выдать ошибку сразу при обнаружении несоответствия, не дожидаясь этапа записи в базу данных.

Таким образом, использование ФабрикиXDTO в сочетании с предварительным анализом через ЧтениеXML является наиболее производительным и гибким способом обработки внешних данных в 1С:Предприятии 8.

← На главную