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

Публикация № 1051370

Обмен - Обмен через XML

XDTO обмен

29
Использование объекта типа "Объект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 пишем вот что:

Функция ПолучитьСхему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 будет следующее:

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

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

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

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

29

Скачать файлы

Наименование Файл Версия Размер
Перенос данных с использованием XDTO
.zip 212,13Kb
20.04.19
1
.zip 212,13Kb 1 Скачать

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. HAMMER_59 77 23.04.19 07:23 Сейчас в теме
Все подумываю написать статью "XDTO для чайников", а тут смотрю может уже и не нужно.
Сейчас также пишу синхронизацию между доработанной УТ 10.1 и БП 3, рекомендую посмотреть стандартные правила обмена УТ 10.3 -> БП 3.
По статье отметил бы:
- Непонятно зачем программно делать экспорт схемы, когда можно через графический интерфейс.
- У меня самый большой затык был с коллекциями, например, строки табличной части документа, на самом деле все просто, но без примера сложно разобраться.
2. PLAstic 210 23.04.19 09:10 Сейчас в теме
(1) На этом форуме их полно уже. Напишите лучше про какие-нибудь интересные нюансы вроде:
1) Как с помощью XDTO сформировать массив из нуля элементов и выгрузить его в JSON.
2) Как недопустить платформенного эксепшна при парсинге JSON по XDTO при наличии в нём пустого массива.

Я откровенно задолбался общаться с 1Сниками, не хотят они регистрировать эти ошибки. Уже всё им прислал, даже ссыль на RFC с переводом.
4. plevakin 23.04.19 09:27 Сейчас в теме
(2) ПрочитатьJSON(ЧтениеJSON,истина) не предлагать?
5. PLAstic 210 23.04.19 09:55 Сейчас в теме
(4) Конечно, нет. Мне же надо преобразовать к типу объекта со всеми вытекающими проверками структуры пакета и значений.
7. axae 75 23.04.19 11:21 Сейчас в теме
(1)
о статье отметил бы:
- Непонятно зачем программно делать экспорт сх
А если поменяется конфа бухгалтерии? Допускаю, что это редко, но всё же... Тут просто интересно было, на самом деле конечно можно и так взять откуда-нибудь. Конкретно в моей ситуации схему бухгалтерии отдает httpСервис.
8. axae 75 23.04.19 11:26 Сейчас в теме
(1)
XDTO для чайников
- Я как раз тот чайник! Но спросить, к сожалению, не у кого все эти нюансы, да и элементарные вещи.
3. plevakin 23.04.19 09:25 Сейчас в теме
А если есть схема не в XSD а в таком виде

<?xml version="1.0" encoding="utf-8" ?>
- <edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
- <edmx:DataServices>
- <Schema Namespace="Request.WebAPI.Models.V1" xmlns="http://docs.oasis-open.org/odata/ns/edm">
- <EntityType Name="Request">
- <Key>
<PropertyRef Name="Id" />
</Key>


Ее можно как-то прочитать средствами 1C?
6. PLAstic 210 23.04.19 10:02 Сейчас в теме
Оставьте свое сообщение