1. Введение в проблему.
Думаю всем знакомо сообщение "Ошибка преобразования данных XML" при использовании обработки ВыгрузкаЗагрузкаДанныхXML82.epf:
Оно всегда возникает в самый неподходящий момент. Означает либо разницу в последовательности реквизитов в объекте, либо, что еще хуже, разницу в количестве реквизов. Всегда приводит к дополнительным затратам времени на диагностику и устранение проблемы.
Может я бы и не стал заморачиваться и переписывать велосипед заново, если бы не одно большое НО: у меня 90% функциональности хранится в настроечных таблицах, а не в конфигурации. В конфигурации хранится только ядро системы, которое постоянно совершенствуется.
Как следствие, если мне нужно перебросить уже разработанную функциональность от клиента к клиенту, возникают проблемы совместимости во время выгрузки/загрузки xml файла похожих конфигураций.
Задумано - сделано! Заодно добавлено несколько полезных возможностей.
Что вышло в результате - судить Вам.
2. Обработка будет полезна в случаях когда:
2.1 нужно обменяться данными между рабочей и тестовой конфигурацией
2.2 нужно перенести настройки конфигурации хранимых в справочниках и регистрах сведений из младшей версии в старшую
2.3 диагостировать ошибку преобразования xml в других случаях
3. Основной принцип работы "расширенного режима":
Для того, чтобы обеспечить возможность загрузки данных объектов конфигурации в любой последовательности реквизитов, необходимо в файл xml выгрузить информацию о типах передаваемых значений.
Использование для выгрузки команды ЗаписатьXML(ЗаписьXML, Объект, НазначениеТипаXML.Явное) к желаемому результату не привела. Формальный тип был присвоен всему узлу целиком, отдельные реквизиты остались не типизированны.
Пришлось написать собственную процедуру ЗаписатьXMLЯвно(ЗаписьXML, Объект) в которой для каждого типа объекта, каждого реквизита была реализован алгоритм выгрузки. В результате получили xml-документ в ожидаемом формате:
Таким образом возможность реализовать независимую от последовательности реквизитов объектв загрузку появляется только в результате ручного кодинга выгрузки/загрузки всех объектов.
4.Внесенные изменния:
4.1 На панели "Выгрузка" реализован режим "Расширенная обработка" для выгрузки xml данных в расширенном формате.
Режим реализован по принципу обратной совместимости, выгруженные данные в режиме "Расширенная обработка" загрузятся в любом случае. Однако загрузка в режиме "Расширенная обработка" предполагает и выгрузку только режиме "Расширенная обработка".
4.2 На панели "Загрузка" реализован режим "Расширенная обработка" для загрузки xml данных в расширенном формате.
Режим "просмотр данных" - позволяет видеть результаты загрузки и открыть уже загруженные объекты.
Режим "автопроведение" позволяет перепроводить загруженные документы.
Кнопка "Предварительный просмотр" позволяет увидеть содержимое xml файла без сохранения его содержимого в конфигурации
Во время загрузки производится расширенная диагностика ошибок преобразования xml данных.
Ошибки выводятся в список.
4.3 Добавлен секундомер для оценки производительности.
5. Ограничения
В виду, того, что обработка предполагает ручной кодинг выгрузки и загрузки для всех типов объектов, для решения основных задач режим "Расширенная обработка" реализован только для следующих объектов:
5.1 Варианты обмена между справочниками:
1-Иерархический
2-Без иерархии
5.2 Варианты записи между документами:
1-без вариантов
5.3 Варианты записи между регистрами сведений:
1-не периодический
2-переодический
3-не подчиненный регистратору
4-подчиненный регистратору
5-основной отбор по периоду
5.4 Варианты записи между регистрами накопления:
1-Остатки и обороты
2-Только обороты
5.5 Варианты записи между регистрами бухгалтерии:
1-С корреспонденцией счетов
2-Без корреспонденцией счетов
Обмен между другими объектами будет добавлен позже, если возникнут пожелания.
6. Методика испытаний
Ручной кодинг операций выгрузки/загрузки объектов предполагает возможность некорректной загрузки
объекта. По этому была разработана серьезная программа испытаний для подтверждения надежности работы
ручных алгоритмов.
6.1 Все данные испытуемой конфигурации полностью выгружаются в файл etalon.xml в стандартном режиме.
6.2 Все данные испытуемой конфигурации полностью выгружаются в файл test.xml в расширенном режиме.
6.3 Все данные испытуемой конфигурации полностью загружаются из файла test.xml в расширенном режиме.
6.4 Все данные испытуемой конфигурации полностью выгружаются в файл etalon2.xml в стандартном режиме.
Файлы etalon.xml и etalon2.xml сравниваются байт в байт.
Тест считается пройденным, если оба файла идентичны.
Конфигурации, которые были использованы в испытаниях:
1. Авторские конфигурации
2. УТП
3. Бухгалтерия
4. УПП
5. СКАТ-профессионал
В процессе испытаний была выявлена следующая особенность:
В случае, если в реквизите хранятся только пробелы, после выгрузки/загрузки реквизит будет содержать пустую строку.
Данная особенность присуща обоим режимам: стандартному и расширенному, таким образом эта ошибка не может считаться
привнесенной. Проблема лежит в особенности хранения пустых строк в xml формате и решается другими средствами.
7. Производительность
Учитывая ручное кодирование всех операций выгрузки/загрузки особое внимание было уделено вопросам производительности.
Общее падение производительности операций в режиме расширеной выгрузки/загрузки составило 20-30%, что можно считать приемлемой платой за универсальность.
8. Использование пространства имен "http://www.w3.org/2001/XMLSchema"
Выгрузка объектов каждого реквизита с помощью механизма формального описания типов приводит к избыточному описанию типа для каждого элемента:
использование механизма соответствия пространства имен позволяет значительно сократить объем выходного файла:
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("_1CV8DtUD", "http://www.1c.ru/V8/1CV8DtUD/");
Если РасширеннаяОбработка=Истина Тогда
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("xs","http://www.w3.org/2001/XMLSchema");
КонецЕсли;
в результате xml-документ принимает вид:
9. Дополнительные изменения
Для реализации расширенного режима в исходный код стандартной обработки были внесены следующие изменения:
9.1 Пропатчены:
1 Процедура ОбработкаРезультатаЗапроса
2 Процедура ВыполнитьЗагрузку
9.2 Добавлены:
// ========================= Доработка Запись =========================
Процедура Записать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) Экспорт
// ================= Сервисные функции ====================
Функция ПолучитьПредставлениеВремени(Секунды) Экспорт
// ================= Доработка Конец ======================
Функции из секции "Доработка Чтение" могут использоваться как шаблоны кода для обмена с другими
информационными системами, к примеру с помощью EDI.
Описание стандарта CommerceML EDI можно найти здесь
10. Тем кому интересна тема, рекомендую обмен остальных объектов реализовать самостоятельно,
уж очень познавательно получается. Начальные сведения представлены здесь:
А.Г. Габец "Профессиональная разработка в системе 1С:Предприятие" Глава 14. Интеграция с другими информационными системами. Работа с xml-документами.
PS На самом деле xml не так уж и сложен, как может показаться на первый взгляд.
11. Пример использование обработки ВыгрузкаЗагрузкаДанныхXML82Beta.epf как библиотеки:
Ниже приведены примеры использования техники выгрузки/загрузки xml-документов с помощью обработки ВыгрузкаЗагрузкаДанныхXML82Beta.epf. Базовые методы обработки реализованы как экспортные функции, что позволяет реализовать внешнии вызовы:
Листинг №1 Выгрузка данных в xml-документ.
ФайлXML = Новый ЗаписьXML;
ФайлXML.ОткрытьФайл("test.xml", "UTF-8");
ФайлXML.ЗаписатьОбъявлениеXML();
ФайлXML.ЗаписатьНачалоЭлемента("_1CV8DtUD", "http://www.1c.ru/V8/1CV8DtUD/");
ФайлXML.ЗаписатьСоответствиеПространстваИмен("V8Exch","http://www.1c.ru/V8/1CV8DtUD/");
ФайлXML.ЗаписатьСоответствиеПространстваИмен("xs","http://www.w3.org/2001/XMLSchema");
ФайлXML.ЗаписатьСоответствиеПространстваИмен("xsi","http://www.w3.org/2001/XMLSchema-instance");
ФайлXML.ЗаписатьСоответствиеПространстваИмен("v8","http://v8.1c.ru/data");
ФайлXML.ЗаписатьНачалоЭлемента("V8Exch:Data");
Библиотека=Обработки.ВыгрузкаЗагрузкаДанныхXML82Beta.Создать();
// Запись справочника
Об=Справочники.ВидыРабот.НайтиПоКоду(1).ПолучитьОбъект();
Библиотека.ЗаписатьXMLЯвно_Справочник(ФайлXML,Об);
// Запись документа
Об=Документы.Заявка.НайтиПоНомеру("000001",'20130801').ПолучитьОбъект();
Библиотека.ЗаписатьXMLЯвно_Документ(ФайлXML,Об);
// Запись регистра сведений
НаборЗаписей = РегистрыСведений.РегистрСведенийТест.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Измерение1.Установить(Справочники.Мастера.НайтиПоКоду(15));
НаборЗаписей.Отбор.Измерение2.Установить(Справочники.Контролеры.НайтиПоКоду(2));
НаборЗаписей.Прочитать();
Библиотека.ЗаписатьXMLЯвно_НаборЗаписейРегистраСведений(ФайлXML,НаборЗаписей);
// Запись регистра накопления
ДокСсылка=Документы.ДокументТест.НайтиПоНомеру("000001",'20130801');
НаборЗаписей = РегистрыНакопления.ТМЦ.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокСсылка);
НаборЗаписей.Прочитать();
Библиотека.ЗаписатьXMLЯвно_НаборЗаписейРегистраНакопления(ФайлXML,НаборЗаписей);
// Запись регистра бухгалтерии
ДокСсылка=Документы.ДокументТест.НайтиПоНомеру("000001",'20130801');
НаборЗаписей = РегистрыБухгалтерии.Тест1.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокСсылка);
НаборЗаписей.Прочитать();
Библиотека.ЗаписатьXMLЯвно_НаборЗаписейРегистраНакопления(ФайлXML,НаборЗаписей);
ФайлXML.ЗаписатьКонецЭлемента(); //V8Exc:Data
ФайлXML.ЗаписатьКонецЭлемента(); //V8Exc:_1CV8DtUD
ФайлXML.Закрыть();
Листинг №2 Загрузка данных из xml-документа.
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("test.xml");
// ============= проверка формата файла обмена ==============
Если Не ЧтениеXML.Прочитать() Или
ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента Или
ЧтениеXML.ЛокальноеИмя <> "_1CV8DtUD" Или
ЧтениеXML.URIПространстваИмен <> "http://www.1c.ru/V8/1CV8DtUD/" Тогда
Предупреждение("Неверный формат файла выгрузки", 0, "Ошибка загрузки локального имени '_1CV8DtUD' !!!");
Возврат;
КонецЕсли;
Если Не ЧтениеXML.Прочитать() Или
ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента Или
ЧтениеXML.ЛокальноеИмя <> "Data" Или
ЧтениеXML.URIПространстваИмен <> "http://www.1c.ru/V8/1CV8DtUD/" Тогда
Предупреждение("Неверный формат файла выгрузки", 0, "Ошибка загрузки локального имени 'Data' !!!");
Возврат;
КонецЕсли;
// чтение и запись в ИБ записанных в выгрузке объектов
Если Не ЧтениеXML.Прочитать() Тогда
Предупреждение("Неверный формат файла выгрузки", 0, "Ошибка загрузки!!!");
Возврат;
КонецЕсли;
Библиотека=Обработки.ВыгрузкаЗагрузкаДанныхXML82Beta.Создать();
// ============= Начало чтения xml-данных ==================
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
ЗаписанноеЗначение=Библиотека.ПрочитатьXMLЯвно(ЧтениеXML);
Попытка // Планы обмена свойства ОбменДанными не имеют
ЗаписанноеЗначение.ОбменДанными.Загрузка = Истина;
Исключение
КонецПопытки;
Попытка
ЗаписанноеЗначение.Записать();
Исключение
Если Вопрос("При записи произошла ошибка:" + Символы.ПС + ОписаниеОшибки() + Символы.ПС + "Продолжит загрузку?", РежимДиалогаВопрос.ДаНет) = КодВозвратаДиалога.Нет Тогда
ВызватьИсключение;
КонецЕсли;
КонецПопытки;
КонецЦикла;
// ============= Конец чтения xml-данных ====================
// проверка формата файла обмена
Если ЧтениеXML.ТипУзла <> ТипУзлаXML.КонецЭлемента Или
ЧтениеXML.ЛокальноеИмя <> "Data" Или
ЧтениеXML.URIПространстваИмен <> "http://www.1c.ru/V8/1CV8DtUD/" Тогда
#Если Клиент Тогда
Предупреждение("Неверный формат файла выгрузки", 0, "Ошибка загрузки!!!");
#КонецЕсли
Возврат;
КонецЕсли;
Если Не ЧтениеXML.Прочитать() Или
ЧтениеXML.ТипУзла <> ТипУзлаXML.КонецЭлемента Или
ЧтениеXML.ЛокальноеИмя <> "_1CV8DtUD" Или
ЧтениеXML.URIПространстваИмен <> "http://www.1c.ru/V8/1CV8DtUD/" Тогда
#Если Клиент Тогда
Предупреждение("Неверный формат файла выгрузки", 0, "Ошибка загрузки!!!");
#КонецЕсли
Возврат;
КонецЕсли;
ЧтениеXML.Закрыть();