В процессе разработки интеграций между различными конфигурациями 1С часто возникает задача обмена данными через XML с использованием механизма XDTO. Проблема появляется в тот момент, когда в базе-источнике данные формируются на основе XDTO-пакета, существующего в метаданных, а в базе-приемнике такого пакета нет. При попытке прочитать XML стандартным способом ФабрикаXDTO.ПрочитатьXML() система выдаст ошибку, так как глобальная фабрика не знает о типах данных из этого пакета.
Давайте разберемся, как решить эту задачу. Основная идея заключается в том, чтобы вместе с данными передавать и их описание (XSD-схему), а в приемнике на лету создавать временную (локальную) фабрику XDTO, которая будет "понимать" структуру принимаемых данных.
Проанализируем весь процесс по шагам: от получения схемы в источнике до чтения данных в приемнике.
Первое, что нам нужно сделать в базе, где XDTO-пакет определен в конфигурации, — это получить его описание в виде текста XSD-схемы. Это стандартный формат для описания структуры XML-документов. Платформа 1С позволяет сделать это в несколько строк кода.
Рассмотрим на примере пакета с именем мк_ПланВидовРасчета. Чтобы получить его схему, обратимся к метаданным:
// Получаем объект схемы из коллекции схем пакета.
// Обычно схема одна, поэтому получаем по индексу 0.
СхемаXML = Метаданные.ПакетыXDTO.мк_ПланВидовРасчета.СхемыXML.Получить(0);
// Из объекта схемы извлекаем ее текстовое представление
ТекстСхемыXSD = СхемаXML.ПолучитьТекстМакета();
// Теперь переменная ТекстСхемыXSD содержит полный текст XSD-схемы.
// Этот текст мы и будем передавать в базу-приемник вместе с данными.
Полученный текст можно передать как строку, сохранить в файл или включить в состав общего XML-сообщения, что является наиболее надежным подходом.
Теперь, когда у нас есть и сами данные в формате XML, и их схема в виде строки, нужно передать их в базу-приемник. Можно сделать это двумя отдельными потоками, но лучше объединить все в одно сообщение. Это исключит рассинхронизацию, когда данные пришли, а схема для них — нет.
Можно сформировать контейнерный XML-документ следующей структуры:
<КонтейнерОбмена>
<СхемаXML>
<![CDATA[
<!-- Здесь размещается полный текст XSD-схемы, полученный на шаге 1 -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" ...>
...
</xs:schema>
]]>
</СхемаXML>
<Данные>
<!-- Здесь находятся сами данные в формате XML -->
<мк_ПланВидовРасчета ...>
...
</мк_ПланВидовРасчета>
</Данные>
</КонтейнерОбмена>
Важный момент: текст схемы обернут в секцию . Это позволяет избежать проблем с парсингом спецсимволов, которые могут содержаться в XSD-схеме.
На стороне приемника мы сначала прочитаем узел <СхемаXML>, извлечем из него текст, а затем приступим к чтению данных из узла <Данные>.
Это ключевой этап. В базе-приемнике, где нет нужного XDTO-пакета, мы используем полученную XSD-схему для создания временной, или локальной, фабрики XDTO. Эта фабрика будет существовать только в рамках выполнения нашего кода и будет содержать информацию о типах из переданной схемы.
Рассмотрим два способа создания такой фабрики.
Этот способ был предложен на форуме и является абсолютно рабочим. Он заключается в том, чтобы сохранить полученную строку со схемой во временный файл, а затем создать фабрику на основе этого файла. Для надежности схему можно даже сохранить в макет конфигурации приемника.
Посмотрим на пример кода для этого подхода:
Сохраняем схему. Если схема не хранится в макете, а передается в виде строки (ТекстСхемыXSD), сохраним ее во временный файл.
// Предположим, ТекстСхемыXSD мы получили из входящего сообщения
ИмяФайлаXSD = ПолучитьИмяВременногоФайла("xsd");
ТекстовыйДокумент = Новый ТекстовыйДокумент();
ТекстовыйДокумент.УстановитьТекст(ТекстСхемыXSD);
ТекстовыйДокумент.Записать(ИмяФайлаXSD, КодировкаТекста.UTF8);
Создаем фабрику. Теперь используем системный метод СоздатьФабрикуXDTO(), передав ему путь к нашему файлу.
ЛокальнаяФабрика = СоздатьФабрикуXDTO(ИмяФайлаXSD);
// Не забываем удалить временный файл после использования
УдалитьФайлы(ИмяФайлаXSD);
Читаем данные. Используем созданную фабрику для чтения XML-данных.
// ДанныеXML - это строка с данными из узла <Данные>
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.УстановитьСтроку(ДанныеXML);
// Используем метод ПрочитатьXML именно нашей локальной фабрики, а не глобальной
ОбъектXDTO = ЛокальнаяФабрика.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();
// Теперь можно работать с ОбъектомXDTO, как обычно
Для Каждого ЭлементXDTO Из ОбъектXDTO.value Цикл
// ...
КонецЦикла;
Этот способ более эффективен, так как полностью исключает операции с файловой системой, что особенно важно при работе в серверном режиме или в веб-сервисах. Метод СоздатьФабрику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 с динамическим созданием фабрики является более надежным, гибким и профессиональным решением.