Как распарсить произвольный XML-файл в 1С: все способы от простых до универсальных

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

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

В этой статье мы подробно рассмотрим все возможные архитектурные подходы для решения этой задачи. Мы разберем как простые способы быстрого чтения данных, так и напишем мощный универсальный рекурсивный алгоритм преобразования произвольного XML в привычные коллекции 1С (структуры, соответствия и массивы).

---

Способ №1. Универсальный рекурсивный обход через «ЧтениеXML»

Если нам нужно прочитать файл произвольной структуры, не загружая его целиком в оперативную память (что критически важно для файлов объемом в сотни мегабайт или гигабайты), наилучшим решением будет использование потокового объекта ЧтениеXML. Мы построим рекурсивную функцию, которая на лету преобразует XML-документ в дерево, состоящее из объектов Соответствие (или Структура) и Массив.

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

  1. Имя XML-тега становится ключом в объекте Соответствие.
  2. Если внутри тега находится простой текст, он записывается как значение этого ключа.
  3. Если тег содержит вложенные элементы, значением становится вложенное Соответствие.
  4. Если на одном уровне вложенности встречаются несколько одноименных тегов (например, строки табличной части <СтрокаТовара>), парсер автоматически преобразует их в Массив.
  5. Для считывания атрибутов тегов мы будем добавлять к их именам специальный префикс (например, символ "@"), чтобы избежать коллизий с именами вложенных тегов.

Рассмотрим реализацию этого универсального парсера на практике:


Функция РаспарситьXMLВКоллекцию(Знач ПутьКФайлу) Экспорт

    ЧтениеXML = Новый ЧтениеXML;
    Попытка
        ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
    Исключение
        ЗаписьЖурналаРегистрации("Парсинг XML", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
        ВызватьИсключение "Не удалось открыть файл для чтения: " + ОписаниеОшибки();
    КонецПопытки;
    
    // Переходим к первому элементу XML
    Если Не ЧтениеXML.Прочитать() Тогда
        ЧтениеXML.Закрыть();
        Возврат Неопределено;
    КонецЕсли;
    
    Результат = ПрочитатьТекущийУзел(ЧтениеXML);
    
    ЧтениеXML.Закрыть();
    Возврат Результат;

КонецФункции

Функция ПрочитатьТекущийУзел(ЧтениеXML)

    // Здесь мы собираем данные текущего узла
    ДанныеУзла = Новый Соответствие;
    
    // 1. Читаем атрибуты тега, если они есть
    Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
        Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
            ДанныеУзла.Вставить("@" + ЧтениеXML.Имя, ЧтениеXML.Значение);
        КонецЦикла;
    КонецЕсли;
    
    // 2. Читаем вложенное содержимое
    Пока ЧтениеXML.Прочитать() Цикл
        ТипУзла = ЧтениеXML.ТипУзла;
        
        Если ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            ИмяВложенногоТега = ЧтениеXML.Имя;
            
            // Рекурсивный вызов для вложенного узла
            ЗначениеВложенногоУзла = ПрочитатьТекущийУзел(ЧтениеXML);
            
            // Проверяем, есть ли уже элемент с таким именем в нашей коллекции
            СуществующееЗначение = ДанныеУзла.Получить(ИмяВложенногоТега);
            Если СуществующееЗначение = Неопределено Тогда
                // Добавляем новое свойство
                ДанныеУзла.Вставить(ИмяВложенногоТега, ЗначениеВложенногоУзла);
            Иначе
                // Если элемент с таким именем уже был, превращаем его в Массив
                Если ТипЗнч(СуществующееЗначение) = Тип("Массив") Тогда
                    СуществующееЗначение.Добавить(ЗначениеВложенногоУзла);
                Иначе
                    НовыйМассив = Новый Массив;
                    НовыйМассив.Добавить(СуществующееЗначение);
                    НовыйМассив.Добавить(ЗначениеВложенногоУзла);
                    ДанныеУзла.Вставить(ИмяВложенногоТега, НовыйМассив);
                КонецЕсли;
            EndЕсли;
            
        ИначеЕсли ТипУзла = ТипУзлаXML.Текст ИЛИ ТипУзла = ТипУзлаXML.СекцияCDATA Тогда
            // Если внутри тега только простой текст, возвращаем его значение
            Возврат ЧтениеXML.Значение;
            
        ИначеЕсли ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
            // Завершаем чтение текущего уровня вложенности
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    // Если у элемента нет дочерних узлов и атрибутов, возвращаем пустую строку
    Если ДанныеУзла.Количество() = 0 Тогда
        Возврат "";
    КонецЕсли;
    
    Возврат ДанныеУзла;

КонецФункции

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

---

Способ №2. Использование модели DOM и XPath-запросов

Объектная модель документа (DOM) загружает весь XML-файл в оперативную память в виде дерева объектов. Платформа 1С предоставляет для работы с ней удобный инструмент — ПостроительDOM.

Главным преимуществом использования DOM перед ручным перебором узлов является встроенная поддержка языка запросов XPath. Если структура файла сложная и неизвестная, но нам достоверно известно, что где-то в глубине файла находятся теги с конкретным именем (например, <Price> или <Article>), мы можем извлечь их одной строкой кода без необходимости писать сложные циклы обхода.

Давайте разберем по шагам, как это реализовать:


Процедура ПрочитатьXMLЧерезXPath(ПутьКФайлу)

    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
    
    // Загружаем XML в дерево DOM
    ПостроительDOM = Новый ПостроительDOM;
    ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
    ЧтениеXML.Закрыть();
    
    // Создаем XPath-запрос. 
    // Символы "//" означают поиск элементов по всему документу на любом уровне вложенности
    ВыражениеXPath = "//Product/Price"; 
    
    РезультатXPath = ДокументDOM.ВычислитьВыражениеXPath(ВыражениеXPath, ДокументDOM);
    
    // Обходим найденные узлы
    УзелDOM = РезультатXPath.ПолучитьСледующий();
    Пока УзелDOM <> Неопределено Цикл
        // Извлекаем текстовое значение узла
        ЗначениеЦены = УзелDOM.ТекстовоеСодержимое;
        Сообщить("Найдена цена: " + ЗначениеЦены);
        
        // Переходим к следующему узлу
        УзелDOM = РезультатXPath.ПолучитьСледующий();
    КонецЦикла;

КонецПроцедуры

Использование XPath делает код невероятно лаконичным, гибким и устойчивым к изменениям структуры родительских тегов во входящем XML-файле. Разобраться во всех тонкостях и синтаксисе таких запросов поможет практическое руководство по работе с XPath в 1С.

---

Способ №3. Динамическая фабрика XDTO со схемами XSD

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

Эту проблему можно решить динамическим созданием фабрики XDTO на основе схемы данных xsd. Если поставщик данных предоставляет схему вместе с XML, мы можем загрузить ее прямо в коде:


Функция ПрочитатьXMLЧерезДинамическийXDTO(ПутьКXML, ПутьКXSD)

    // Создаем коллекцию схем и загружаем файл схемы
    КоллекцияСхем = Новый КоллекцияСхемXML;
    КоллекцияСхем.Добавить(ПутьКXSD);
    
    // Создаем локальную фабрику XDTO, которая теперь "знает" структуру нашего XML
    ЛокальнаяФабрика = Новый ФабрикаXDTO(КоллекцияСхем);
    
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.ОткрытьФайл(ПутьКXML);
    
    // Чтение происходит автоматически в типизированный объект XDTO
    Попытка
        ОбъектXDTO = ЛокальнаяФабрика.ПрочитатьXML(ЧтениеXML);
    Исключение
        Сообщить("Ошибка чтения схемы XDTO: " + ОписаниеОшибки());
        ЧтениеXML.Закрыть();
        Возврат Неопределено;
    КонецПопытки;
    
    ЧтениеXML.Закрыть();
    Возврат ОбъектXDTO;

КонецФункции

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

---

Способ №4. Промежуточная конвертация XML в JSON

Современная платформа 1С предлагает мощный и быстрый механизм десериализации данных в формате JSON — функцию ПрочитатьJSON(). Она автоматически преобразует JSON-строку во вложенные структуры и массивы 1С без написания сложного кода.

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


Функция ПревратитьJSONВКоллекции(СтрокаJSON)

    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
    
    // Платформа 1С автоматически сформирует Соответствия и Массивы
    Результат = ПрочитатьJSON(ЧтениеJSON);
    ЧтениеJSON.Закрыть();
    
    Возврат Результат;

КонецФункции

---

Способ №5. Нормализация данных с помощью XSLT-преобразований

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

Используя файл XSL-шаблона, мы можем трансформировать любой сложный и нестандартный XML в плоский, понятный XML-файл прямо в памяти компьютера. После такой "нормализации" прочитать результирующий файл стандартными средствами 1С не составит никакого труда.


Процедура НормализоватьИПрочитатьXML(ПутьКXML, ПутьКШаблонуXSL, ПутьКРезультату)

    Преобразование = Новый ПреобразованиеXSL;
    Преобразование.ЗагрузитьПравила(ПутьКШаблонуXSL);
    
    // Трансформируем "грязный" XML в чистый и структурированный файл
    Преобразование.Преобразовать(ПутьКXML, ПутьКРезультату);
    
    // Далее читаем полученный файл стандартными средствами
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.ОткрытьФайл(ПутьКРезультату);
    // ... дальнейшая обработка ...
    ЧтениеXML.Закрыть();

КонецПроцедуры

---

Способ №6. Оптимизация производительности: FastInfoset

Если перед нами стоит задача регулярной передачи и парсинга огромных объемов данных произвольного формата, и мы можем повлиять на отправляющую сторону, имеет смысл использовать формат FastInfoset (бинарный XML). Чтобы автоматизировать первый этап этого процесса, можно настроить регулярный сбор файлов с FTP, HTTP и почты.

Использование объектов ЧтениеFastInfoset и ЗаписьFastInfoset в 1С вместо стандартных текстовых XML-объектов позволяет значительно ускорить парсинг данных, уменьшить размер файлов при передаче по сети и снизить нагрузку на процессор.

---

Сравнительный анализ методов парсинга

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

  1. Рекурсивный обход через «ЧтениеXML»: Обладает максимальной производительностью, минимальным потреблением оперативной памяти и полной независимостью от структуры данных. Подходит для сверхбольших файлов.
  2. Использование DOM и XPath: Идеально подходит, если файл имеет средний размер, но сложную запутанную структуру, из которой нужно извлечь только выборочные данные.
  3. Динамическое XDTO: Лучшее решение, если у вас есть XSD-схема. Вы получите строго типизированные данные 1С с возможностью обращения к свойствам "через точку".
  4. Конвертация в JSON: Удобный современный способ, позволяющий использовать эффективные встроенные алгоритмы платформы 1С для работы с JSON-форматом.

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

← На главную