Как преобразовать произвольный XML в объект ТаблицаЗначений в 1С с использованием XDTO?

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

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

Предположим, у нас есть некий произвольный XML-документ, например, содержащий список пунктов выдачи заказов (ПВЗ):



    
        
            ПВЗ Октябрьская
            PVZ001
            Москва
            
ул. Октябрьская, 1
1
ПВЗ Ленина PVZ002 Санкт-Петербург
пр-т Ленина, 5
2

Мы хотим получить из него стандартную ТаблицаЗначений 1С, например, со следующими колонками: "Название", "КодПВЗ", "Город", "Адрес", "КодГорода". Рассмотрим возможности и ограничения платформы.

Почему прямое преобразование произвольного XML в ТаблицуЗначений через СериализаторXDTO не работает

Многие разработчики надеются, что, используя СериализаторXDTO, можно "скормить" ему произвольный XML и получить на выходе ТаблицуЗначений. Конструкции, подобные следующей, кажутся интуитивно понятными:


ЧтениеXMLДанных = Новый ЧтениеXML;
ЧтениеXMLДанных.УстановитьСтроку(СтрокаXML);
ТЗ = СериализаторXDTO.ПрочитатьXML(ЧтениеXMLДанных); // Ожидается ТаблицаЗначений

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

Для ТаблицыЗначений платформа 1С ожидает XML-структуру, которая включает определенные элементы, атрибуты и пространства имен (например, http://v8.1c.ru/8.1/data/ui/system). Произвольный XML, полученный из внешнего источника, практически никогда не будет соответствовать этой внутренней схеме. Поэтому СериализаторXDTO не сможет его корректно распознать и преобразовать в ТаблицуЗначений.

Попытки создать собственный XDTO-пакет, который бы "объяснил" платформе, как сопоставить произвольную XML-структуру с ТаблицейЗначений, также не увенчаются успехом. Механизм XDTO-пакетов служит для описания типов данных, а не для определения логики их преобразования. Мы можем описать пользовательские типы, которые будут десериализованы в объекты XDTO, но не можем заставить СериализаторXDTO десериализовать наш произвольный XML в системный тип ТаблицаЗначений на основе нашего собственного XDTO-пакета, игнорируя встроенные правила. Попытка создать "альтернативный" пакет для ТаблицыЗначений приведет к конфликту со встроенными схемами платформы, либо Сериализатор просто проигнорирует наш пакет, пытаясь применить свои жестко закодированные правила.

Таким образом, "волшебной кнопки" для прямого преобразования произвольного XML в ТаблицуЗначений средствами XDTO не существует. Нам придется выбрать один из двух рабочих подходов.

Подход 1: Ручной разбор XML и заполнение ТаблицыЗначений

Этот подход является наиболее прямолинейным и прозрачным. Он включает в себя последовательное чтение XML-документа, создание промежуточных объектов XDTO (согласно схеме XML, если она есть, или без нее, используя "свободные" объекты XDTO), а затем ручное заполнение колонок и строк ТаблицыЗначений данными из этих объектов.

Пошаговое описание

  1. Создаем пустую ТаблицуЗначений: Определяем необходимые колонки и их типы. Это гарантирует, что наша таблица будет иметь нужную структуру.
  2. Инициализируем ЧтениеXML: Устанавливаем в него нашу исходную XML-строку или файл.
  3. Читаем XML в объекты XDTO: Используем ФабрикаXDTO.ПрочитатьXML() для десериализации XML в объект или коллекцию объектов XDTO. Если у нас есть схема для входящего XML, мы можем предварительно загрузить её в ФабрикуXDTO. Если схемы нет, ФабрикаXDTO создаст "свободные" XDTO-объекты, структуру которых можно будет обходить.
  4. Обходим объекты XDTO в цикле: Перебираем полученные объекты XDTO. Для каждого объекта создаем новую строку в нашей ТаблицеЗначений.
  5. Заполняем колонки ТаблицыЗначений: Присваиваем значения свойствам созданной строки, извлекая данные из соответствующих свойств объекта XDTO.

Пример кода

Рассмотрим пример, который реализует этот подход для нашего XML с ПВЗ:


Функция ПреобразоватьXMLВТаблицуЗначенийРучнойСпособ(СтрокаXML) Экспорт
    // 1. Создаем пустую ТаблицуЗначений с нужными колонками
    тзПВЗ = Новый ТаблицаЗначений;
    тзПВЗ.Колонки.Добавить("Название", Новый ОписаниеТипов("Строка"));
    тзПВЗ.Колонки.Добавить("КодПВЗ", Новый ОписаниеТипов("Строка"));
    тзПВЗ.Колонки.Добавить("Город", Новый ОписаниеТипов("Строка"));
    тзПВЗ.Колонки.Добавить("Адрес", Новый ОписаниеТипов("Строка"));
    тзПВЗ.Колонки.Добавить("КодГорода", Новый ОписаниеТипов("Строка"));

    // 2. Инициализируем ЧтениеXML
    ЧтениеXMLДанных = Новый ЧтениеXML;
    ЧтениеXMLДанных.УстановитьСтроку(СтрокаXML);

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

    // 4. Получаем список элементов "Pvz".
    // Если XML имеет такую структуру: ......
    // то СписокПВЗ будет коллекцией XDTO-объектов.
    СписокПВЗ = ОбъектXDTO.PvzList.Pvz; // или ОбъектXDTO.ПолучитьСписок("Pvz") в зависимости от структуры и XSD

    // Убедимся, что СписокПВЗ является коллекцией, даже если в XML только один элемент.
    // XDTO-фабрика может вернуть один объект, если элементов типа Pvz только один.
    Если ТипЗнч(СписокПВЗ) = Тип("ОбъектXDTO") Тогда
        ВременныйСписок = Новый Массив;
        ВременныйСписок.Добавить(СписокПВЗ);
        СписокПВЗ = ВременныйСписок;
    КонецЕсли;

    // 5. Обходим объекты XDTO и заполняем ТаблицуЗначений
    Для каждого ПВЗ Из СписокПВЗ Цикл
        стр = тзПВЗ.Добавить();
        стр.Название = ПВЗ.Name;
        стр.КодПВЗ = ПВЗ.Code;
        стр.Город = ПВЗ.City;
        стр.Адрес = ПВЗ.Address;
        стр.КодГорода = ПВЗ.CityCode;
    КонецЦикла;

    Возврат тзПВЗ;
КонецФункции

// Пример использования:
СтрокаИсходногоXML = "ПВЗ ОктябрьскаяPVZ001Москва
ул. Октябрьская, 1
1
ПВЗ ЛенинаPVZ002Санкт-Петербург
пр-т Ленина, 5
2
"; ТЗ_Результат = ПреобразоватьXMLВТаблицуЗначенийРучнойСпособ(СтрокаИсходногоXML);

Достоинства и недостатки

  1. Достоинства:
    • Прозрачность: Код явно показывает, как данные из XML сопоставляются с колонками ТаблицыЗначений.
    • Гибкость: Легко адаптируется к изменениям в структуре входящего XML или требованиям к ТаблицеЗначений.
    • Отладка: Проще отлаживать, так как логика преобразования находится непосредственно в коде 1С.
    • Контроль: Полный контроль над процессом извлечения и обработки данных.
  2. Недостатки:
    • Многословность: Для сложных XML-структур код может стать довольно объемным.
    • Необходимость цикла: Требует явного обхода элементов, что противоречит желанию "одного заклинания".
    • Производительность: Для очень больших XML-файлов ручной перебор может быть менее производительным, чем нативное XSLT-преобразование.

Подход 2: XSLT-преобразование с последующей десериализацией XDTO

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

Пошаговое описание

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

Пример XSLT-шаблона и кода 1С

Для нашего примера с ПВЗ, XSLT-шаблон будет выглядеть следующим образом. Обратите внимание на использование пространств имен http://v8.1c.ru/8.1/data/ui/system, которые необходимы для корректной десериализации ТаблицыЗначений в 1С.


// XSLT-шаблон (СтрокаСхемыXSL)


    

    
        
            
            
            
            
            
            
            
            

            
            
                
                    
                    
                        
                    
                    
                        
                    
                    
                        
                    
                    
                        
                    
                    
                        
                    
                
            
        
    

Важное замечание по XSLT: в выражениях XPath для выбора дочерних элементов (например, Name, Code) следует использовать прямой путь (Name) или относительный (./Name), если контекст элемента уже установлен, а не атрибутный (@Name), если это не является атрибутом. Если у вас возникли проблемы с XSLT, проверьте корректность XPath-выражений, особенно для выбора дочерних узлов. Также в XSLT-шаблонах следует избегать вызова шаблонов внутри для простых операций, это может усложнить читаемость и отладку.

Код 1С для выполнения преобразования:


Функция ПреобразоватьXMLВТаблицуЗначенийЧерезXSLT(СтрокаXML, СтрокаСхемыXSL) Экспорт
    // 1. Инициализируем ПреобразованиеXSL и загружаем шаблон
    Преобразование_ПВЗ = Новый ПреобразованиеXSL;
    Преобразование_ПВЗ.ЗагрузитьИзСтроки(СтрокаСхемыXSL);

    // 2. Выполняем преобразование исходного XML в целевой формат ТаблицыЗначений
    СтрокаXML_ПВЗ = Преобразование_ПВЗ.ПреобразоватьИзСтроки(СтрокаXML);

    // 3. Десериализуем полученный XML в ТаблицуЗначений
    ЧтениеXML_ПВЗ = Новый ЧтениеXML;
    ЧтениеXML_ПВЗ.УстановитьСтроку(СтрокаXML_ПВЗ);
    ТЗ_Результат = СериализаторXDTO.ПрочитатьXML(ЧтениеXML_ПВЗ);

    Возврат ТЗ_Результат;
КонецФункции

// Пример использования:
СтрокаИсходногоXML = "ПВЗ ОктябрьскаяPVZ001Москва
ул. Октябрьская, 1
1
ПВЗ ЛенинаPVZ002Санкт-Петербург
пр-т Ленина, 5
2
"; СтрокаXSLTШаблона = // ... здесь должен быть ваш XSLT-шаблон из примера выше ... ТЗ_Результат = ПреобразоватьXMLВТаблицуЗначенийЧерезXSLT(СтрокаИсходногоXML, СтрокаXSLTШаблона);

Достоинства и недостатки

  1. Достоинства:
    • Компактность кода 1С: После создания XSLT-шаблона, код на 1С становится очень коротким и понятным.
    • Производительность: XSLT-преобразование выполняется на более низком уровне платформы, что может быть быстрее для больших объемов данных по сравнению с ручным перебором в цикле 1С.
    • Разделение логики: Логика преобразования данных вынесена в отдельный XSLT-файл, что позволяет ее изменять без перекомпиляции кода 1С.
  2. Недостатки:
    • Сложность XSLT: Написание и отладка сложных XSLT-шаблонов требуют специфических знаний и инструментов.
    • Промежуточная трансформация: Необходимость выполнения промежуточного шага преобразования XML, что является тем "обходным путем", который автор хотел избежать.
    • Пороги входа: Высокий порог входа для разработчиков, не знакомых с XSLT.

Ключевые объекты и методы 1С, используемые в решениях

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

Мы выяснили, что универсального "волшебного заклинания" для прямого преобразования произвольного XML в ТаблицуЗначений средствами XDTO, без дополнительной логики или трансформаций, не существует. Механизм СериализаторXDTO требует, чтобы входящий XML соответствовал жестко определенной внутренней схеме 1С для ТаблицыЗначений.

Таким образом, мы имеем два основных рабочих подхода:

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

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

← На главную