Книга: Технологии интеграции "1С:Предприятия 8.3""
Назад: Стратегия распространения данных
Дальше: Стратегия разрешения коллизий

Обмен данными с разной структурой

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

Рассмотрим простой пример обмена данными с различной структурой. Например, в базе узла-получателя в иерархическом справочнике Номенклатура присутствует дополнительный реквизит по сравнению с базой узла-отправителя, и наоборот.

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

Для этого дополним процедуру ЗаписатьСообщениеСИзменениями() в модуле плана обмена (см. листинг 3.59) следующим образом (листинг 3.65).

Листинг 3.65. Процедура «ЗаписатьСообщениеСИзменениями»

Процедура ЗаписатьСообщениеСИзменениями() Экспорт

 

// Получить выборку измененных данных.

// *** Механизм регистрации изменений.

ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения);

Пока ВыборкаИзменений.Следующий() Цикл

Данные = ВыборкаИзменений.Получить();

 

// Проверить, нужен ли перенос данных. Если нет, то записать удаление этих данных.

Если Не ОбменСУдаленнымиСкладами.НуженПереносДанных(ЗаписьСообщения.Получатель, Данные) Тогда

ОбменСУдаленнымиСкладами.УдалениеДанных(Данные);

КонецЕсли;

 

// Записать данные в сообщение *** XML-сериализация.

ОбменСУдаленнымиСкладами.ЗаписатьДанные(ЗаписьXML, Данные);

КонецЦикла;

 

КонецПроцедуры

Добавленный фрагмент выделен жирным шрифтом. В этом фрагменте данные, полученные в цикле перебора записей регистрации изменений, сериализуются в открытый XML-файл с помощью процедуры ЗаписатьДанные(), расположенной в общем модуле ОбменСУдаленнымиСкладами. В параметре Данные в процедуру передается полученный объект обмена (листинг 3.66).

Листинг 3.66. Процедура «ЗаписатьДанные»

Процедура ЗаписатьДанные(ЗаписьXML, Данные) Экспорт

 

Удаление = ?(ТипЗнч(Данные) = Тип("УдалениеОбъекта"), Истина, Ложь);

 

// Получить объект описания метаданного, соответствующий данным.

ОбъектМетаданных = ?(Удаление, Данные.Ссылка.Метаданные(), Данные.Метаданные());

 

Если Не Удаление И ОбъектМетаданных = Метаданные.Справочники.Номенклатура Тогда

// Записать элемент справочника вручную.

ЗаписатьXMLНоменклатура(ЗаписьXML, Данные);

Иначе

 

// Записать данные с помощью стандартного метода.

ЗаписатьXML(ЗаписьXML, Данные);

КонецЕсли

 

КонецПроцедуры

В процедуре производится проверка: если записывается не удаление данных и записываемый объект является элементом справочника Номенклатура, то вызывается процедура ЗаписатьXMLНоменклатура(), расположенная в общем модуле ОбменСУдаленнымиСкладами, для записи элемента справочника вручную (листинг 3.67). В противном случае запись производится с помощью стандартного метода ЗаписатьXML().

Листинг 3.67. Процедура «ЗаписатьXMLНоменклатура»

Процедура ЗаписатьXMLНоменклатура(ЗаписьXML, Товар )Экспорт

 

// Записать начало элемента XML.

ЗаписьXML.ЗаписатьНачалоЭлемента("CatalogObject.Номенклатура.Вручную");

 

// Ссылка

ЗаписатьXML(ЗаписьXML, Товар.Ссылка, "Ref", НазначениеТипаXML.Явное);

// ЭтоГруппа

ЗаписатьXML(ЗаписьXML, Товар.ЭтоГруппа, "IsFolder", НазначениеТипаXML.Явное);

// Родитель

ЗаписатьXML(ЗаписьXML, Товар.Родитель, "Parent", НазначениеТипаXML.Явное);

// Наименование

ЗаписатьXML(ЗаписьXML, Товар.Наименование, "Description", НазначениеТипаXML.Явное);

// Код

ЗаписатьXML(ЗаписьXML, Товар.Код, "Code", НазначениеТипаXML.Явное);

 

// Записать реквизиты, выгружаемые только для элемента справочника.

Если Не Товар.ЭтоГруппа Тогда

// ЗакупочнаяЦена

ЗаписатьXML(ЗаписьXML, Товар.ЗакупочнаяЦена, "ЗакупочнаяЦена", НазначениеТипаXML.Явное);

// ФайлКартинки

ЗаписатьXML(ЗаписьXML, Товар.ФайлКартинки, "ФайлКартинки", НазначениеТипаXML.Явное);

// Картинка

ЗаписатьXML(ЗаписьXML, Товар.Картинка, "Картинка", НазначениеТипаXML.Явное);

КонецЕсли;

 

// Записать конец элемента.

ЗаписьXML.ЗаписатьКонецЭлемента();

 

КонецПроцедуры

В процедуре ЗаписатьXMLНоменклатура() производится «ручное» формирование элемента CatalogObject.Номенклатура.Вручную.

Сначала в открытый XML-файл мы записываем начало элемента с заголовком, указывающим на ручное формирование элемента. Затем при помощи метода ЗаписатьXML() записываем значения «общих» реквизитов, которые хотим передать с помощью обмена. Третьим параметром передаем строковое имя записываемого реквизита и в качестве четвертого параметра указываем значение перечисления НазначениеТипаXML, определяющее необходимость явного указания типа данных XML. После этого мы завершаем запись элемента и записываем в XML-файл конец элемента.

В процедуру ПрочитатьСообщенияСИзменениями() в модуле плана обмена (см. листинг 3.61) внесем следующие изменения (листинг 3.68).

Листинг 3.68. Процедура «ПрочитатьСообщениеСИзменениями»

Процедура ПрочитатьСообщениеСИзменениями() Экспорт

 

// Прочитать данные из сообщения в цикле. *** XML-сериализация.

Пока ОбменСУдаленнымиСкладами.ВозможностьЧтенияДанных(ЧтениеXML) Цикл

 

// Прочитать очередное значение.

Данные = ОбменСУдаленнымиСкладами.ПрочитатьДанные(ЧтениеXML);

 

// Записать полученные данные.

Данные.ОбменДанными.Отправитель = ЧтениеСообщения.Отправитель;

Данные.ОбменДанными.Загрузка = Истина;

Данные.Записать();

 

КонецЦикла;

 

КонецПроцедуры

Добавленный фрагмент выделен жирным шрифтом. В этом фрагменте в цикле мы выполняем чтение данных, содержащихся в сообщении обмена. При этом для каждого элемента в функции ВозможностьЧтенияДанных(), расположенной в общем модуле ОбменСУдаленнымиСкладами (см. листинг 3.69), проверяется возможность чтения данных. Если имя типа – CatalogObject.Товары.Вручную, возвращается значение Истина. В противном случае вызывается стандартный метод ВозможностьЧтенияXML(), с помощью которого из объекта ЧтениеXML получается очередной тип данных XML и определяется, имеется ли соответствующий тип «1С:Предприятия».

Листинг 3.69. Функция «ВозможностьЧтенияДанных»

Функция ВозможностьЧтенияДанных(ЧтениеXML)

 

// Получить тип данных XML, который может быть считан в данный момент.

ТипXML = ПолучитьXMLТип(ЧтениеXML);

Если ТипXML = Неопределено Тогда

Возврат Ложь;

КонецЕсли;

 

Если ТипXML.ИмяТипа = "CatalogObject.Номенклатура.Вручную" И ТипXML.URIПространстваИмен = "" Тогда

Возврат Истина;

КонецЕсли;

 

Возврат ВозможностьЧтенияXML(ЧтениеXML);

 

КонецФункции

В цикле чтения данных в процедуре ПрочитатьСообщениеСИзменениями() вызывается функция ПрочитатьДанные(), расположенная в общем модуле ОбменСУдаленнымиСкладами (см. листинг 3.70), в которой производится чтение данных из элемента. При этом если читается элемент CatalogObject.Номенклатура.Вручную, то вызывается функция ПрочитатьXMLНоменклатура(), расположенная в общем модуле ОбменСУдаленнымиСкладами (см. листинг 3.71) для «ручного» чтения данных, в противном случае чтение осуществляется с помощью стандартного метода ПрочитатьXML.

Листинг 3.70. Функция «ПрочитатьДанные»

Функция ПрочитатьДанные(ЧтениеXML)

 

ТипXML = ПолучитьXMLТип(ЧтениеXML);

Если ТипXML = Неопределено Тогда

Возврат Неопределено;

КонецЕсли;

 

Если ТипXML.ИмяТипа = "CatalogObject.Номенклатура.Вручную" И ТипXML.URIПространстваИмен = "" Тогда

// Прочитать значение справочника Номенклатура.

Возврат ПрочитатьXMLНоменклатура(ЧтениеXML);

КонецЕсли;

 

// Прочитать значение из объекта ЧтениеXML стандартным образом.

Возврат ПрочитатьXML(ЧтениеXML);

 

КонецФункции

Листинг 3.71. Функция «ПрочитатьXMLНоменклатура»

Функция ПрочитатьXMLНоменклатура(ЧтениеXML)Экспорт

 

Если ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда

ВызватьИсключение "Ошибка чтения XML";

КонецЕсли;

 

// Прочитать следующий узел XML-документа.

ЧтениеXML.Прочитать();

 

// Прочитать ссылку на элемент справочника Номенклатура.

ТоварСсылка = ПрочитатьXML(ЧтениеXML);

Если ТипЗнч(ТоварСсылка) <> Тип("СправочникСсылка.Номенклатура") Тогда

ВызватьИсключение "Ошибка чтения XML";

КонецЕсли;

 

// Создать объект по полученной ссылке.

Товар = ТоварСсылка.ПолучитьОбъект();

 

// Прочитать признак группы.

ЭтоГруппа = ПрочитатьXML(ЧтениеXML);

Если Товар <> Неопределено Тогда

Если Товар.ЭтоГруппа <> ЭтоГруппа Тогда

ВызватьИсключение "Некорректные данные";

КонецЕсли;

 

Иначе

// Создать элемент справочника Номенклатура.

Если ЭтоГруппа = Истина Тогда

Товар = Справочники.Номенклатура.СоздатьГруппу();

Иначе

Товар = Справочники.Номенклатура.СоздатьЭлемент();

КонецЕсли;

 

// Устанавить значение ссылки для нового объекта.

Товар.УстановитьСсылкуНового(ТоварСсылка);

КонецЕсли;

 

// Родитель

Товар.Родитель = ПрочитатьXML(ЧтениеXML);

// Наименование

Товар.Наименование = ПрочитатьXML(ЧтениеXML);

// Код

Товар.Код = ПрочитатьXML(ЧтениеXML);

 

// Прочитать реквизиты, загружаемые только для элемента справочника.

Если Не Товар.ЭтоГруппа Тогда

// ЗакупочнаяЦена

Товар.ЗакупочнаяЦена = ПрочитатьXML(ЧтениеXML);

// ФайлКартинки

Товар.ФайлКартинки = ПрочитатьXML(ЧтениеXML);

// Картинка

Товар.Картинка = ПрочитатьXML(ЧтениеXML);

КонецЕсли;

 

 

// Проверить, что текущим узлом является КонецЭлемента.

Если ЧтениеXML.ТипУзла <> ТипУзлаXML.КонецЭлемента Тогда

ВызватьИсключение "Ошибка чтения XML";

КонецЕсли;

 

// Прочитать следующий узел для завершение чтения элемента XML-документа.

ЧтениеXML.Прочитать();

Возврат Товар;

 

КонецФункции

В функции ПрочитатьXMLНоменклатура() производится последовательное считывание каждого узла элемента справочника Номенклатура, записанного вручную в сообщение обмена.

Сначала мы проверяем, что находимся в XML-файле на начале элемента, затем двигаемся на следующий узел методом Прочитать() объекта ЧтениеXML. Затем считываем ссылку на элемент справочника и пытаемся создать объект по полученной ссылке.

Если это сделать не удалось, значит, такого объекта еще не существует, и мы создаем или новую группу, или новый элемент справочника – в зависимости от значения реквизита ЭтоГруппа, считанного из сообщения обмена. Затем последовательно считываем (в том порядке, в котором записывали) и устанавливаем значения «общих» реквизитов, которые мы ранее вручную выгрузили в процедуре ЗаписатьXMLНоменклатура(), см. листинг 3.67.

В завершение проверяем: если считана вся информация о номенклатуре (достигнут конец элемента), то двигаемся на следующий элемент данных в сообщении обмена.

В результате функция возвращает данные о прочитанном элементе номенклатуры в процедуру ПрочитатьСообщениеСИзменениями(), в переменную Данные (см. листинг 3.68).

В случае стандартного чтения данных методом ПрочитатьXML переменная Данные будет содержать любой другой объект «1С:Предприятия», полученный из сообщения обмена.

Назад: Стратегия распространения данных
Дальше: Стратегия разрешения коллизий