Каталог решений - Перенос данных с использованием XDTO

Перенос данных с использованием XDTO

Перенос данных с использованием XDTO

В наличии

Использование объекта типа «ОбъектXDTO» для переноса данных из одной конфигурации в другую

Категория:

Описание

Здравствуйте! Моя статья посвящена моему вниканию в XDTO, первые шаги. Статьи по XDTO есть, но там слишком много теории.

Предисловие

Мне захотелось попробовать использовать XDTO для написания своего переноса данных из одной конфигурации в другую. У меня была конкретная цель: создать управляемый перенос данных из одной конфигурации в другую. Из дописанной УТ10 в БУХ30. Естественно, в УТ10 нет БСП. У нас использовалась конвертация данных 2, я умею ей пользоваться, в некотором смысле, и даже вижу косяки в ее справке. Но гибкость переноса маловата. Данные перенести можно, но мне не нравилась малая скорость, сложность создания/изменения своего алгоритма загрузки. Например, некоторые документы мне нужно принимать, другие — нет, по каким-то условия, некоторые проводить, а некоторые — не трогать совсем, необходимость использования разных правил обмена для разных конфигураций, сложность просмотра данных при отладке и т.д. Но я в работе всегда стараюсь пробовать новые механизмы, чтобы осознавать, чем хорош/плох (хорошо, когда соотношение 50/50, люблю хорошую ортогональность) тот или иной подход. Скорее всего то понимание, которое я хочу показать, возможно завтра уже вызовет у меня только улыбку. Но я думаю стоит поделиться, уверен, кому-то поможет.

Итак, начинаю описывать то, что я понял…

Для начала, необходимо представить три понятия…

  1. …Что такое пакет XDTO. Пакет XDTO — это описание того, как нужно строить XML. Какие там узлы вложены, сколько их и как интерпретировать содержимое узлов. Интерпретация узлов зависит от…
  2. …Пространства имен. Это некое абстрактное название совокупности описаний этих интерпретаций. Видя в узле атрибут xmlns:v8="http://v8.1c.ru/8.1/data/enterprise/current-config" мы понимаем, что в подчиненных узлах этого узла данные типа <ДокументОснование xsi:type="v8:DocumentRef.Возврат">fdfddc9e-6357-11e9-9869-c86000e2d5b1</ДокументОснование> означают, что тип "DocumentRef.Возврат" относится к v8, а v8 — это префикс пространства имен, которое мы объявили для этого узла (или вышестоящего). В этом примере получается так: содержимое "fdfddc9e-6357-11e9-9869-c86000e2d5b1" узла <ДокументОснование> следует интерпретировать согласно типу "DocumentRef.Возврат", описанному в пакете с пространством имен "http://v8.1c.ru/8.1/data/enterprise/current-config". Создание объекту описанных типов согласно пространству имен занимается…
  3. …ФабрикаXDTO. ФабрикаXDTO знает типы объектов по своим пакетам и умеет создавать ОбъектXDTO по типам, описанным в них. Есть глобальная фабрика. Она знает обо всех типах данной конфигурации. Но можно создавать свою фабрику по своим схемам.

Моя задача по-большей части заключалась в том, чтобы логичным образом перенести ссылки на документы. Ссылка в одной конфигурации должна соответствовать ссылке в другой и чтобы это сразу было видно в отладчике, в свойстве ОбъектXDTO. Но вот незадача: в одной конфигурации документ называется, например, "ВозвратОтПокупателя", а в другой — "Возврат". А ссылки должны совпадать. Незадача это потому что пространство имен конфигурации в обоих базах называется одинаково: "http://v8.1c.ru/8.1/data/enterprise/current-config". Вот только в каждой из них свои объекты. Или, например, названия перечислений или значения перечислений разные.

Можно, конечно, всё создавать вручную через ЗаписьXML, все атрибуты и узлы, согласно конфигурации базы-приемника… Но! Мне далеко не всегда нравится состав реквизитов этих объектов. Например, для чего мне в формируемом XML по документу платежки данные счетов учета? Или мне не хотелось создавать в передаваемом XML данные для РасшифровкаПлатежа. Мне хотелось сделать свой ОбъектXDTO, со своими свойствами, которые сочту необходимыми для переноса. 

Решение

Создаем ПакетXDTO в базе-приемнике (это у меня БУХ30, я добавил расширение, но возможно это можно создавать и в блокноте или еще каком-то инструменте) и экспортируем его в файл .xsd. Затем экспортируем всю конфигурацию базы приемника в другой файл. Экспорт осуществляется вот:

Выгрузка .xsd конфигурации 

В базе-источнике для создания своей фабрики из двух файлов .xsd пишем вот что:

Функция ПолучитьСхемуXML(ИмяФайла)
	Файл = Новый Файл(ИмяФайла);
	ЧтениеXML = Новый ЧтениеXML;
	// Открыть файл XML
	ЧтениеXML.ОткрытьФайл(Файл.ПолноеИмя);
	// Создать построитель документа DOM по умолчанию
	ПостроительDOM = Новый ПостроительDOM;
	// Прочитать файл XML в документ DOM
	ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
	// Создать построитель схемы XML по умолчанию
	ПостроительСхемыXML = Новый ПостроительСхемXML;
	// Получить схему XML из документа DOM
	СхемаXML = ПостроительСхемыXML.СоздатьСхемуXML(ДокументDOM);
	Возврат СхемаXML;	
КонецФункции
  


НаборСхемXML = Новый НаборСхемXML;
Файл = Новый Файл("D:\XDTO\export-2.xsd");
НаборСхемXML.Добавить(ПолучитьСхемуXML(Файл.ПолноеИмя));
Файл = Новый Файл("D:\XDTO\export.xsd");
НаборСхемXML.Добавить(ПолучитьСхемуXML(Файл.ПолноеИмя));
МояФабрика = Новый ФабрикаXDTO(НаборСхемXML);

Таким образом у нас получается Фабрика, которая может создавать объекты с необходимыми типами.

Пакет в базе-приемнике выглядит так: 

 

Это то, как я хочу переносить данные. Этот мой пакет имеет пространство имен с именем (http://www.sample-package.org). Мне в документе ОплатаПлатКартой не нужны счета и все реквизиты контрагента. Мне у контрагента нужно наименование и возможно ссылка. Тип у свойства Ref типа объекта Контрагента — строка. Потому что я не собираюсь сопоставлять контрагентов по ссылке. А вот тип свойства Ref у типа объекта ОплатаПлатКартой — DocumentRef.ОплатаПлатежнойКартой из пространства имен конфигурации http://v8.1c.ru/8.1/data/enterprise/current-config. Именно поэтому нам нужна директива импорта и это то, ради чего я это делал: просмотр в отладчике этого свойства у ОбъектXDTO выдаст реальную ссылку в базе-приемнике.

ВидОперации тоже имеет тип из типов конфигурации.

А вот ДокументОснование не имеет типа, он имеет открытый тип. В базе приемнике у соответствующего документа составной тип, поэтому при формировании XML необходимо передавать тип.

Вот как выглядит функция формирования XML:

	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку();
	ЗаписьXML.ЗаписатьОбъявлениеXML();
	ЗаписьXML.ЗаписатьНачалоЭлемента("root");
	ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("", "http://www.sample-package.org");	
	ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("v8", "http://v8.1c.ru/8.1/data/enterprise/current-config");	
	
	МассивДокументов = ПолучитьСписокДокументов();
	
	Для Каждого ТекЭлемент Из МассивДокументов Цикл
		Объект = ТекЭлемент.ПолучитьОбъект();
		ТипРеализация = МояФабрика.Тип("http://v8.1c.ru/8.1/data/enterprise/current-config", "DocumentRef.Реализация");
		ТипДокумента = МояФабрика.Тип("http://www.sample-package.org", "ОплатаПлатКартой");
		ТипКонтрагента = МояФабрика.Тип("http://www.sample-package.org", "Контрагент");
		ТипВозврата = МояФабрика.Тип("http://v8.1c.ru/8.1/data/enterprise/current-config", "DocumentRef.Возврат");
		ТипОплата = МояФабрика.Тип("http://v8.1c.ru/8.1/data/enterprise/current-config", "EnumRef.ВидыОперацийПлатКарта");
		
		КонтрагентXDTO = МояФабрика.Создать(ТипКонтрагента);
		КонтрагентXDTO.Ref = XMLСтрока(Объект.Контрагент);
		КонтрагентXDTO.Description = "" + Объект.Контрагент;
		
		ОбъектXDTO = МояФабрика.Создать(ТипДокумента); 
		ОбъектXDTO.Ref = XMLСтрока(Объект.Ссылка);
		ОбъектXDTO.Description = "" + Объект;
		ОбъектXDTO.СуммаДокумента = Объект.СуммаДокумента;
		ОбъектXDTO.ВидОперации = МояФабрика.Создать(ТипОплата, "ОплатаПокупателя");
		ОбъектXDTO.Контрагент = КонтрагентXDTO;
		ОбъектXDTO.ДокументОснование = МояФабрика.Создать(ТипВозврата, Объект.ДокументОснование.УникальныйИдентификатор());
		
		МояФабрика.ЗаписатьXML(ЗаписьXML, ОбъектXDTO);
	КонецЦикла;
	
	ЗаписьXML.ЗаписатьКонецЭлемента();
	
	Результат = ЗаписьXML.Закрыть();

Функции списка документов не привожу — это просто ссылки на документы оплаты.

Объекты XDTO создаются фабрикой по типу полученному из фабрики: сначала получаем тип, потом создаем ОбъектXDTO (или ЗначениеXDTO, как в случае, например, с перечислением).

Обратите внимание, как формируется свойство Ref для Контрагента — это просто строка, полученная из ссылки.

Обратите внимание на заполнение свойства ДокументОснование. Мы создаем фабрикой значение из ТипВозврата, передавая ей уникальный идентификатор ссылки основания. У документа основания в базе-источнике составной тип: РеализацияТоваровУслуг и ВозвратОтПокупателя. А вот в базе-приемнике они называются иначе: Реализация и Возврат. 

Наименования значений перечислений в базе источнике и в базе приемнике тоже разные: Оплата, Возврат и ОплатаПокупателя, ВозвратПокупателю. В приведенном примере заполняется однозначно, но, думаю, понятно, что в реальном обмене необходимо добавлять условия, как именно заполнять создаваемый ОбъектXDTO.

Итого получается XML:

<?xml version="1.0"?>
<root xmlns="http://www.sample-package.org" xmlns:v8="http://v8.1c.ru/8.1/data/enterprise/current-config">
	<ОплатаПлатКартой xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
		<Ref>fdfddc9f-6357-11e9-9869-c86000e2d5b1</Ref>
		<Description>Оплата платежной картой 000000001 от 20.04.2019 15:35:46</Description>
		<ВидОперации>ОплатаПокупателя</ВидОперации>
		<Контрагент>
			<Ref>fdfddc9b-6357-11e9-9869-c86000e2d5b1</Ref>
			<Description>Виктор</Description>
		</Контрагент>
		<СуммаДокумента>1000</СуммаДокумента>
		<ДокументОснование xsi:type="v8:DocumentRef.Возврат">fdfddc9c-6357-11e9-9869-c86000e2d5b1</ДокументОснование>
	</ОплатаПлатКартой>
	<ОплатаПлатКартой xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
		<Ref>fdfddca0-6357-11e9-9869-c86000e2d5b1</Ref>
		<Description>Оплата платежной картой 000000002 от 20.04.2019 15:35:57</Description>
		<ВидОперации>ОплатаПокупателя</ВидОперации>
		<Контрагент>
			<Ref>fdfddc9b-6357-11e9-9869-c86000e2d5b1</Ref>
			<Description>Виктор</Description>
		</Контрагент>
		<СуммаДокумента>300</СуммаДокумента>
		<ДокументОснование xsi:type="v8:DocumentRef.Возврат">fdfddc9e-6357-11e9-9869-c86000e2d5b1</ДокументОснование>
	</ОплатаПлатКартой>
</root>

Для чтения такого XML в базе приемнике пишем короткую функцию:

	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(ДанныеXML);
	ЧтениеXML.Прочитать();
	ЧтениеXML.Прочитать();
	ТипXML = ПолучитьXMLТип(ЧтениеXML);
	ТипXDTO = ФабрикаXDTO.Тип(ТипXML);
	ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипXDTO);

ЧтениеXML.Прочитать() — это условная функция, чтобы выйти на нужный узел, добавьте циклов сами, как вам нужно. По узлу определяем ТипXML, находим его в ФабрикаXDTO (здесь фабрика — глобальная, потому что у меня прямо в конфигурации есть нужный пакет XDTO), получая ТипXDTO. По этому типу XDTO читаем объект.

После этого кода в ОбъектXDTO будет следующее:

Сравните с тем, что было в исходной базе:

Необходимые мне ссылки преобразовались, как мне было нужно.

В прилагаемом файле архив с базами, где в отладчике можно посмотреть, как это работает.

Буду рад критике и предложениям!

has been added to your cart:
Оформление заказа