Как разделить файл XML или объект XDTO на два файла по условию в 1С?

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

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

Рассмотрим основные способы решения этой задачи в платформе 1С:Предприятие, проанализируем их плюсы, минусы и особенности реализации.

Подход 1: Модификация через объектную модель XDTO (ОбъектXDTO)

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

Разберем по шагам алгоритм работы с XDTO:

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

Важная особенность: Списочные свойства элементов XDTO представляют собой коллекцию СписокXDTO. При удалении элементов из СписокXDTO метод Удалить(Индекс) смещает индексы оставшихся элементов. Поэтому обход списка необходимо выполнять строго в обратном порядке — с конца в начало.

Рассмотрим пример кода для очистки списка счетов в объекте XDTO:


// Пример обхода коллекции XDTO в обратном порядке
Для Каждого Пациент Из ОбъектXDTO.Пациенты Цикл
    СписокСчетов = Пациент.Счета;
    ВсегоСчетов = СписокСчетов.Количество();
    
    Для Индекс = 1 По ВсегоСчетов Цикл
        ОбратныйИндекс = ВсегоСчетов - Индекс;
        ТекущийСчет = СписокСчетов.Получить(ОбратныйИндекс);
        
        // Для первого файла удаляем безналичные счета
        Если ТекущийСчет.ВидОплаты = "Безнал" Тогда
            СписокСчетов.Удалить(ОбратныйИндекс);
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Подход 2: Загрузка в ДеревоЗначений и запись в два файла

Если XSD-схема отсутствует или работа с XDTO по какому-то параметру не подходит, можно построить промежуточную структуру данных с помощью объекта ДеревоЗначений.

Рассмотрим порядок действий для этого способа:

  1. С помощью объекта ЧтениеXML рекурсивно или поуровнево читаем исходный файл и заполняем ДеревоЗначений, воспроизводя иерархию узлов (вложенность порядка 8 уровней).
  2. Создаем два итоговых дерева значений (или клонируем исходное).
  3. В первом дереве удаляем строки, не соответствующие первому условию (например, безнал), а во втором — не соответствующие второму условию (наличные). Строки пациентов, у которых после фильтрации не осталось счетов, также удаляются из дерева.
  4. С помощью ЗаписьXML последовательно выгружаем оба дерева значений обратно в XML-формат.

Подход 3: Потоковая обработка через ЧтениеXML и ЗаписьXML

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

Проанализируем алгоритм потоковой обработки:

  1. Открываем исходный файл через один объект ЧтениеXML.
  2. Создаем два объекта ЗаписьXML для файла 1 (Наличные) и файла 2 (Безналичные).
  3. Читаем документ узлами: при входе в узел контейнера (например, Пациент) считываем его поддерево во временную структуру или анализируем счета на лету.
  4. Если у пациента есть наличные счета, записываем шапку пациента и его наличные счета в первый файл. Если есть безналичные счета — аналогично во второй файл.

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

Подход 4: Использование объектной модели DOM

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

Далее выполняем обход узлов и удаляем не подходящие элементы вызовом метода УдалитьДочерний(). После модификации сохраняем документ в файл с помощью объекта ЗаписьDOM.

Резюме и рекомендации

  1. Если у вас есть XSD-схема и файл небольшого или среднего размера — используйте ОбъектXDTO с удалением элементов из коллекций СписокXDTO в обратном порядке (от конца к началу).
  2. Если файл имеет гигантский размер — применяйте потоковую обработку через ЧтениеXML и два объекта ЗаписьXML.
  3. Если структура не фиксирована и схемы нет — используйте промежуточную выгрузку в ДеревоЗначений.
← На главную