Как загрузить XML через XDTO, если в базе-приемнике нет нужного пакета?

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

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

Давайте разберемся, как решить эту задачу. Основная идея заключается в том, чтобы вместе с данными передавать и их описание (XSD-схему), а в приемнике на лету создавать временную (локальную) фабрику XDTO, которая будет "понимать" структуру принимаемых данных.

Проанализируем весь процесс по шагам: от получения схемы в источнике до чтения данных в приемнике.

Шаг 1. Программное получение XSD-схемы в базе-источнике

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

Рассмотрим на примере пакета с именем мк_ПланВидовРасчета. Чтобы получить его схему, обратимся к метаданным:


// Получаем объект схемы из коллекции схем пакета. 
// Обычно схема одна, поэтому получаем по индексу 0.
СхемаXML = Метаданные.ПакетыXDTO.мк_ПланВидовРасчета.СхемыXML.Получить(0);

// Из объекта схемы извлекаем ее текстовое представление
ТекстСхемыXSD = СхемаXML.ПолучитьТекстМакета();

// Теперь переменная ТекстСхемыXSD содержит полный текст XSD-схемы.
// Этот текст мы и будем передавать в базу-приемник вместе с данными.

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

Шаг 2. Передача схемы и данных в базу-приемник

Теперь, когда у нас есть и сами данные в формате XML, и их схема в виде строки, нужно передать их в базу-приемник. Можно сделать это двумя отдельными потоками, но лучше объединить все в одно сообщение. Это исключит рассинхронизацию, когда данные пришли, а схема для них — нет.

Можно сформировать контейнерный XML-документ следующей структуры:


<КонтейнерОбмена>
    <СхемаXML>
        <![CDATA[
            <!-- Здесь размещается полный текст XSD-схемы, полученный на шаге 1 -->
            <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" ...>
                ...
            </xs:schema>
        ]]>
    </СхемаXML>
    <Данные>
        <!-- Здесь находятся сами данные в формате XML -->
        <мк_ПланВидовРасчета ...>
            ...
        </мк_ПланВидовРасчета>
    </Данные>
</КонтейнерОбмена>

Важный момент: текст схемы обернут в секцию . Это позволяет избежать проблем с парсингом спецсимволов, которые могут содержаться в XSD-схеме.

На стороне приемника мы сначала прочитаем узел <СхемаXML>, извлечем из него текст, а затем приступим к чтению данных из узла <Данные>.

Шаг 3. Создание локальной фабрики и чтение данных в приемнике

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

Рассмотрим два способа создания такой фабрики.

Решение 1: Создание фабрики из файла или макета

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

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

  1. Сохраняем схему. Если схема не хранится в макете, а передается в виде строки (ТекстСхемыXSD), сохраним ее во временный файл.

  2. 
    // Предположим, ТекстСхемыXSD мы получили из входящего сообщения
    ИмяФайлаXSD = ПолучитьИмяВременногоФайла("xsd");
        
    ТекстовыйДокумент = Новый ТекстовыйДокумент();
    ТекстовыйДокумент.УстановитьТекст(ТекстСхемыXSD);
    ТекстовыйДокумент.Записать(ИмяФайлаXSD, КодировкаТекста.UTF8);
    
  3. Создаем фабрику. Теперь используем системный метод СоздатьФабрикуXDTO(), передав ему путь к нашему файлу.

  4. 
    ЛокальнаяФабрика = СоздатьФабрикуXDTO(ИмяФайлаXSD);
    // Не забываем удалить временный файл после использования
    УдалитьФайлы(ИмяФайлаXSD);
    
  5. Читаем данные. Используем созданную фабрику для чтения XML-данных.

  6. 
    // ДанныеXML - это строка с данными из узла <Данные>
    ЧтениеXML = Новый ЧтениеXML();
    ЧтениеXML.УстановитьСтроку(ДанныеXML);
    
    // Используем метод ПрочитатьXML именно нашей локальной фабрики, а не глобальной
    ОбъектXDTO = ЛокальнаяФабрика.ПрочитатьXML(ЧтениеXML);
    ЧтениеXML.Закрыть();
    
    // Теперь можно работать с ОбъектомXDTO, как обычно
    Для Каждого ЭлементXDTO Из ОбъектXDTO.value Цикл 
        // ...
    КонецЦикла;
    

Решение 2: Создание фабрики напрямую из строки (рекомендуемый)

Этот способ более эффективен, так как полностью исключает операции с файловой системой, что особенно важно при работе в серверном режиме или в веб-сервисах. Метод СоздатьФабрикуXDTO() может принимать не только путь к файлу, но и массив строк, каждая из которых содержит текст XSD-схемы.

Давайте посмотрим, как это выглядит в коде:


// ТекстСхемыXSD - строка со схемой, полученная из источника
// ДанныеXML - строка с данными

// 1. Готовим массив схем
МассивСхем = Новый Массив();
МассивСхем.Добавить(ТекстСхемыXSD);

// 2. Создаем локальную фабрику напрямую из массива
// Второй параметр (ЛокальныеИмена) можно не указывать, если не требуется
ЛокальнаяФабрика = СоздатьФабрикуXDTO(МассивСхем);

// 3. Читаем данные с помощью созданной фабрики
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.УстановитьСтроку(ДанныеXML);
ОбъектXDTO = ЛокальнаяФабрика.ПрочитатьXML(ЧтениеXML); 
ЧтениеXML.Закрыть();

// Готово, данные успешно десериализованы в объект XDTO
Для Каждого ЭлементXDTO Из ОбъектXDTO.value Цикл 
    Сообщить(ЭлементXDTO.Ссылка);
КонецЦикла;

Как видите, этот подход проще и чище. Он является предпочтительным в большинстве случаев.

Альтернативный подход: разбор XML без XDTO

Стоит упомянуть, что в некоторых случаях, когда структура XML проста и не требует строгой типизации и валидации, можно обойтись и вовсе без XDTO. Для этого используется последовательное чтение документа с помощью объекта ЧтениеXML и ручной анализ узлов (ТипУзла, Имя, Значение и т.д.).

Преимущества:

Недостатки:

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

← На главную