Сохранить в 1с в xml

Обновлено: 08.07.2024

Представленные в публикации процедуры были рождены потребностью сохранять настройки внешних обработок с возможностью последующего их использования на других компьютерах и в других информационных базах. Работают они, однако, не только для обработок, но и для любых других объектов 1С, имеющих реквизиты и табличные части. Сам я пользуюсь ими достаточно часто, при решении самых различных задач, потому решил поделиться, глядишь кому-нибудь пригодится. Так же, думаю, этот материал может быть полезен начинающим программистам как пример рекурсивного чтения структуры XML-файла, к тому же процедуры малы, просты и легко "допиливаются" под специфические задачи.

Сохранение производится процедурой СохранитьРеквизитыИТабличныеЧасти . В качестве параметров она принимает сохраняемый объект и имя файла. Ссылочные реквизиты сохраняются в виде GUID.

Процедура СохранитьРеквизитыИТабличныеЧасти ( Объект , ИмяФайлаXML =Неопределено) Экспорт
ФайлXML = Новый ЗаписьXML ;
ФайлXML . ОткрытьФайл ( ИмяФайлаXML );
ФайлXML . ЗаписатьОбъявлениеXML ();
ФайлXML . ЗаписатьНачалоЭлемента ( "Root" );
ФайлXML . ЗаписатьАтрибут ( "Объект" , Объект . Метаданные (). Имя );
//Сохраняем реквизиты
Для Каждого Реквизит Из Объект . Метаданные (). Реквизиты Цикл
ФайлXML . ЗаписатьНачалоЭлемента ( "Реквизит" );
ФайлXML . ЗаписатьАтрибут ( "Имя" , Реквизит . Имя );
ТипЗначения = ТипЗнч ( Объект [ Реквизит . Имя ]);
Если Не ТипЗначения = Тип ( "Неопределено" ) Тогда
ФайлXML . ЗаписатьАтрибут ( "ИмяТипа" , XMLТип ( ТипЗначения ). ИмяТипа );
ФайлXML . ЗаписатьАтрибут ( "URI" , XMLТип ( ТипЗначения ). URIПространстваИмен );
КонецЕсли;
ФайлXML . ЗаписатьТекст ( XMLСтрока ( Объект [ Реквизит . Имя ]));
ФайлXML . ЗаписатьКонецЭлемента ();
КонецЦикла;
//Сохраняем табличные части
Для Каждого ТЧ из Объект . Метаданные (). ТабличныеЧасти Цикл
ФайлXML . ЗаписатьНачалоЭлемента ( "ТабличнаяЧасть" );
ФайлXML . ЗаписатьАтрибут ( "Имя" , ТЧ . Имя );
Для Каждого СтрокаТЧ из Объект [ ТЧ . Имя ] Цикл
ФайлXML . ЗаписатьНачалоЭлемента ( "ЭлементКоллекции" );
Для Каждого РеквизитТЧ Из ТЧ . Реквизиты Цикл
ФайлXML . ЗаписатьНачалоЭлемента ( "Реквизит" );
ФайлXML . ЗаписатьАтрибут ( "Имя" , РеквизитТЧ . Имя );
ТипЗначения = ТипЗнч ( СтрокаТЧ [ РеквизитТЧ . Имя ]);
Если Не ТипЗначения = Тип ( "Неопределено" ) Тогда
ФайлXML . ЗаписатьАтрибут ( "ИмяТипа" , XMLТип ( ТипЗначения ). ИмяТипа );
ФайлXML . ЗаписатьАтрибут ( "URI" , XMLТип ( ТипЗначения ). URIПространстваИмен );
КонецЕсли;
ФайлXML . ЗаписатьТекст ( XMLСтрока ( СтрокаТЧ [ РеквизитТЧ . Имя ]));
ФайлXML . ЗаписатьКонецЭлемента ();
КонецЦикла;
ФайлXML . ЗаписатьКонецЭлемента ();
КонецЦикла;
ФайлXML . ЗаписатьКонецЭлемента ();
КонецЦикла;
Если Не ФайлXML =Null Тогда
ФайлXML . ЗаписатьКонецЭлемента ();
ФайлXML . Закрыть ();
КонецЕсли;
КонецПроцедуры

За чтение объекта отвечают процедуры ЗагрузитьРеквизитыИТабличныеЧасти и ЗагрузитьОбъектРекурсивно . Чтобы прочитать объект вызывается первая, ей передаются объект, который необходимо заполнить, и имя файла. Вторая является вспомогательной.

Процедура ЗагрузитьРеквизитыИТабличныеЧасти ( Объект , ИмяФайлаXML =Неопределено) Экспорт
Если Не ИмяФайлаXML = Неопределено Тогда
ФайлXML = Новый ЧтениеXML ;
ФайлXML . ОткрытьФайл ( ИмяФайлаXML );
Пока ФайлXML . Прочитать () Цикл
Если ФайлXML . ТипУзла = ТипУзлаXML . НачалоЭлемента Тогда
ЗагрузитьОбъектРекурсивно ( ФайлXML , Объект , ФайлXML . Имя );
КонецЕсли
КонецЦикла;
КонецЕсли;
КонецПроцедуры

Процедура ЗагрузитьОбъектРекурсивно ( ФайлXML , Объект , знач ИмяУзла )
ИмяТипа = "" ;
ПространствоИмен = "" ;
Пока ФайлXML . ПрочитатьАтрибут () Цикл
Если ФайлXML . Имя = "ИмяТипа" Тогда
ИмяТипа = ФайлXML . Значение ;
ИначеЕсли ФайлXML . Имя = "URI" Тогда
ПространствоИмен = ФайлXML . Значение ;
КонецЕсли;
КонецЦикла;
Пока ФайлXML . Прочитать () Цикл
Если ФайлXML . ТипУзла = ТипУзлаXML . КонецЭлемента И ФайлXML . Имя = ИмяУзла Тогда
Возврат;
ИначеЕсли ФайлXML . ТипУзла = ТипУзлаXML . Текст Тогда
ТипОбъекта = ИзXMLТипа ( ИмяТипа , ПространствоИмен );
Если НЕ ТипОбъекта = Неопределено тогда
Объект = XMLЗначение ( ТипОбъекта , ФайлXML . Значение );
КонецЕсли;
ИначеЕсли ФайлXML . ТипУзла = ТипУзлаXML . НачалоЭлемента Тогда
ИмяТекУзла = ФайлXML . Имя ;
Если ФайлXML . Имя = "ЭлементКоллекции" Тогда
ЗагрузитьОбъектРекурсивно ( ФайлXML , Объект . Добавить (), ИмяТекУзла );
Иначе
Если ФайлXML . ПрочитатьАтрибут () Тогда
ЗагрузитьОбъектРекурсивно ( ФайлXML , Объект [ ФайлXML . Значение ], ИмяТекУзла );
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры

В приложенном файле демонстрационная обработка, позволяющая сохранить ссылочный объект БД в файл и заполнить объект из файла. Заполняемый объект должен быть того же типа, что и сохраненный, а также он должен быть предварительно создан, сохранен в ИБ и выбран в поле "Ссылка".

Выгрузить счет из 1С в формате xml можно при помощи специальной обработки «Выгрузка и загрузка данных XML», которая расположена в 1С: Предприятии версии 8.3 и находится в каталоге EXE/EXTREPS/UNIREPS83/UploadToXML. Так же ее можно скачать здесь .

После скачивания обработки ее необходимо запустить. Для этого воспользуемся командой Открыть

как выгрузить счет из 1с в xml (1).jpg

Указываем место, куда была сохранена обработка и нажимаем Открыть

как выгрузить счет из 1с в xml (2).jpg

В окне обработки во вкладке Выгрузка указываем:

Данные для выгрузки

Куда будут выгружены данные

как выгрузить счет из 1с в xml (3).jpg

Если не выбран период выгрузки, то будут выгружены все данные указанного типа.

На вкладке Дополнительные объекты для выгрузки можно отобрать один или несколько объектов для выгрузки

как выгрузить счет из 1с в xml (4).jpg

По кнопке Выгрузить данные происходит выгрузка в файл на сервере или клиентский компьютер (в зависимости от режима работы 1С Предприятие – файловый или клиент-серверный). Перед выгрузкой необходимо установить переключатель в соответствующее положение

как выгрузить счет из 1с в xml (5).jpg

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

Перед Вами возникла задача загрузки, выгрузки метаданных (документы, справочники, регистры. ).

Возникнуть такая задача может по разным причинам. Как правило — это бэкап и перенос из базы в базу. Сейчас нас не интересует причина, просто примем как данность: потребовалась выгрузка, а затем последующая загрузка. Ее мы и будем сегодня выполнять.

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

А у Вас ситуация: нужно срочно что-то выгрузить / загрузить и некогда разбираться c существующими инструментами, а конфигуратор открывать Вы умеете, или нужно доработать уже существующий механизм, или разработать свой для пользователя, который не хочет разбираться в Конвертации, а хочет иметь «волшебную» кнопку, которая сделает все за него.

Для начала выполнения кода по загрузке или выгрузке нам нужно 2 кнопки: по нажатии на одну будет происходить выгрузка, а по нажатии на другую будет происходить загрузка. Где они будут расположены не важно, для примера, создадим обработку, в которую добавим форму, а на форму закинем эти 2 кнопки.

Формат выгрузки выберем xml, это стандарт и будем ему следовать, да и обрабатывать такой файл легче, чем, допустим, текстовой.

Для примера, добавим возможность выгрузки за период. Так как в выгрузке у нас выгружается только то что нам нужно, то загружать будем все подряд (хотя дело Ваше, можете добавить условия и в загрузку).

В результате у Вас должна получиться форма похожая на:


Переходим в модуль формы и вставляем следующий текст:

Возвращаемся в форму. Переходим во вкладку команд формы. И указываем для команды выгрузить действие выгрузить, для команды загрузить действие загрузить:


В принципе, для моей конфигурации обработка уже рабочая. Но под Ваши задачи ее нужно переделать. А для этого разберем код.

Процедура ПриОткрытии устанавливает по умолчанию даты периода. Чтобы процедура срабатывала при открытии формы, ее следует указать в соответствующем событии формы.


Делать это не обязательно. Просто для удобства пользования.

Небольшое отступление.

Прежде всего, нам нужно понять, что наш персональный компьютер и сервер в большинстве случаев — это разные компьютеры. По крайней мере так рекомендовано. 1С и я вместе с ними будем исходить из того, что вы работаете за клиентским ПК, а исполняемый код и база данных находятся на другом — сервере.

Продолжаем исходить из того, что сервер — это отдельный компьютер (даже если это не так, но для универсальности кода придется так считать - Ваш ПК будет сервером для самого себя).

Так вот 1С решила, что добавлять/читать документы или записи в справочнике можно только на сервере.

Соответственно, код по добавлению, изменению, чтению, будет выполняться на ДРУГОМ ПК. Не на Вашем!

А так как файлы сервера — это не Ваши файлы, а Ваши файлы — это не файлы сервера. То нам нужно какое-то общее и для Вас и для сервера хранилище файлов. Вот в нем и будут происходить все операции. Такое хранилище называется временным.

Разбираем код выгрузки.

Команду выгрузки я подглядел в обработке ВыгрузкаЗагрузкаДанныхXML83.epf, о которой я говорил выше. Так что выгрузка у нас будет вполне себе типовая (правда я выкинул кучу строк ненужного кода, чем облегчил Вам труд)

Первым делом на клиенте создаем общее хранилище:

АдресФайлаВоВременномХранилище, так как мы не знаем ничего про него, то присваиваем ему пустой адрес.

Затем строчкой ВыгрузитьНаСервере(АдресФайлаВоВременномХранилище); мы заполняем наше временное хранилище данными которые хотим сохранить в виде файла.

Строкой ПолучитьФайл(АдресФайлаВоВременномХранилище, "Выгрузка.xml"); мы забираем из временного хранилища на свой компьютер данные, которые можно или посмотреть или сохранить в виде файла с названием Выгрузка.xml. Это стандартная процедура. Работает везде одинаково и разбору не подлежит.

А вот процедуру ВыгрузитьНаСервере(АдресФайлаВоВременномХранилище) разберем подробнее. Именно в ней происходит создание и заполнение временного файла обмена.

На сервере еще нет нужного нам файла, а потому первыми двумя строками мы определяем временный файл на сервере. Код выполняется на сервере, а потому временный файл тоже будет на сервере. Его мы заполним и поместим во временное хранилище из которого уже заберем себе на клиента.

Далее запросом получаем данные, которые необходимо выгружать в файл. Для примера, взят абстрактый документ, который называется ФП_Месячный, у него есть реквизиты: Дата, Номер, Период и табличная часть: Статьи.

Далее идет блок заполнения временного файла данными из запроса.

Первым делом мы объявляем новую ЗаписьXML. С помощью нее будет производиться запись во временный файл: ЗаписьXML.ОткрытьФайл(ИмяВременногоФайла,"UTF-8");

UTF-8 — это кодировка текста. Ее можно принять как стандарт для большинства случаев.

ЗаписьXML.ЗаписатьОбъявлениеXML() - записываем во временный файл служебную информацию, например, информацию о кодировке. Тут думать не надо. Метод стандартный, все что нужно сделает сам.

Далее запись информации идет по принципу скобок в тексте. Есть открывающая, есть закрывающая и что-то в середине. Можно вкладывать одни элементы в другие:

Открываем элемент: ЗаписьXML.ЗаписатьНачалоЭлемента("НазваниеЭлемента");

//что-то делаем, конкретно в нашем случае, мы делаем запись о реквизите документа либо о самом документе

Закрываем элемент: ЗаписьXML.ЗаписатьКонецЭлемента()

Во время записи активно пользуемся функцией XMLСтрока(), которая преобразует метаданные в строковой тип, понятный для записи/чтения XML.

Так как сохранять данные мы можем только простые (число, дата, строка, булево…). То ссылочный тип данных Вид (это справочник с видами статей) мы сохранить не можем. Но мы можем сохранить Код Вида из справочника видов — это строка. Когда мы будем наоборот загружать данные из ХML, то мы будем получать Код. По коду искать ссылку в справочнике. И уже эту ссылку записывать в документ.

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

Ну и последним делом, мы удаляем на сервере временный файл. Если это не сделать, то сервер быстро переполниться временными файлами.

Вообще ситуация с временными файлами мне не нравится. Если загрузка/выгрузка будет идти постоянно, то накопитель сервера быстро выйдет из строя. Но так сделано разработчиками 1С. Этот код я подсмотрел у них в стандартной обработке.

Если можете подсказать как сделать все в оперативной памяти буду благодарен.

Разбираем код загрузки.

Тут уж я не поленился не стал брать типовой механизм, обшарил все форумы и нашел как провести загрузку без использования временных файлов.

Вообще варианта 2:

1. Простой. Считать xml файл в переменную (массив) на клиенте. А после передав эту переменную на сервер, читая данные из массива записывать новые документы.

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

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

Рассмотрим вариант 2.

Помещать файл выгрузки на сервер во временное хранилище мы будем стандартной процедурой НачатьПомещениеФайла(). Так как механизм типовой, я просто скопировал код из примера 1С.

Для всех он будет одинаков. Единственно что я поменял, это фильтр (сделал xml). Стоит еще обратить внимание на размер. В моем случае он равен 4Гб. В Вашем, можете сделать меньше (больше нельзя).

Процедуру ПоместитьФайлКомандаЗавершение() переписал полностью. В ней я смотрю был ли выбран файл. Если файл был выбран, если он удовлетворяет размеру и расширению, тогда будет происходить чтение из данных указного файла в процедуре ОбработатьНаСервере(Адрес), где Адрес — это адрес временного хранилища. Ну а после того, как мы добавим данные, следует попросить систему перечитать базу, так как данные изменились. Это мы делаем процедурой ОповеститьОбИзменении(Тип("ДокументСсылка.ФП_Месячный")). Делать это не обязательно, но тогда чтобы увидеть результат нам придется закрыть и снова открыть список документов ФП_Месячный.

Рассмотрим процедуру ОбработатьНаСервере(Адрес)

Первым делом на сервере из временного хранилища нужно получить то, что мы помещали на клиенте: Данные = ПолучитьИзВременногоХранилища(Адрес);

Объявляем новую переменную с типом ЧтениеXML. В ней будет храниться весь документ XML.

Хитрая строка Парсер.УстановитьСтроку(ПолучитьСтрокуИзДвоичныхДанных(Данные,КодировкаТекста.UTF8)) преобразует двоичные данные в строку xml, которую затем записывает в объявленную ранее переменную с типом ЧтениеXML.

А далее читаем каждую строчку из XML и, в зависимости от данных, заполняем документ.

Ссылочные данные документа заполняются через их поиск по коду из xml.

Отступление.

Да возможность передачи ссылки имеется. Но я не рекомендую ее использовать, дабы данные не задвоились. То есть Документы с одинаковыми Кодами по сути будут разные так как у них разные ссылки (GUID). А если вести запись по коду документа, то документов с одинаковыми кодами Вы не получите. Будет сформировано исключительное событие и перенос данных в базу будет приостановлен. Поэтому я использую оператор попытка при записи документа. Если документ с таким кодом и датой уже есть, то запись произведена не будет, а будет переход к следующей записи.

PS. Благодаря подсказке Сергея, код преобразования данных в XML можно серьезно сократить. Просто замените функцию и процедуру. Будет менее понятно, что такое XML, как он должен заполняться и читаться, но ведь и не всем это надо:

Для выгрузки конфигурации в XML мы добавили новый формат, - Иерархический. Теперь это стандартный формат, который предлагает платформа. Чтобы выгрузить файлы в прежнем формате, нужно это указать в явном виде:


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


. новый формат выгрузки, иерархический, формирует структуру каталогов с файлами:


Иерархическая выгрузка позволяет избавиться от проблем, связанных с очень длинными именами файлов. Такие проблемы могли возникать раньше как при выгрузке, так и при переносе файлов между разными файловыми системами (FAT, NTFS, EXT).

Сам по себе иерархический формат выгрузки не гарантирует того, что в выгрузке не появится очень длинных имён, или очень длинных путей. Поэтому мы ввели ряд ограничений и рекомендаций. Например, в конфигураторе нельзя создавать имена объектов длиннее 80 символов, не рекомендуется использовать подсистемы большой вложенности, каталог выгрузки следует располагать как можно ближе к корню устройства и так далее.

Вы можете управлять форматом выгрузки при запуске конфигуратора в пакетном режиме. Для этого прежнему параметру DumpConfigToFiles мы добавили новую опцию Format. Если вы хотите выгрузить в старом, линейном формате, это нужно указать в явном виде:

"C:\Program Files (x86)\1cv8\8.3.7.1759\bin\1cv8.exe" DESIGNER /IBName "TestBase" /DumpConfigToFiles "C:\dump" -Format Plain

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

Частичная загрузка конфигурации из файлов XML

Мы реализовали возможность загружать из файлов XML не всю конфигурацию, а только её часть. В первую очередь эта возможность востребована в новой среде разработки 1C:Enterprise Development Tools. Ведь Development Tools ориентированы на работу с крупными конфигурациями, а частичная загрузка помогает ускорить процесс разработки, сократить цикл «редактирование - отладка».

Однако вы можете использовать эту возможность и независимо от Development Tools. Потому что для загрузки отдельных файлов конфигурации используется запуск конфигуратора из командной строки в пакетном режиме. А значит, используя частичную загрузку, вы можете:

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

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

Поэтому загрузить только модуль справочника Номенклатура вы можете, например, следующей командой:

"C:\Program Files (x86)\1cv8\8.3.7.1759\bin\1cv8.exe" DESIGNER /IBName "TestBase" /LoadConfigFromFiles "C:\dump" -Files "C:\dump\Catalogs\Номенклатура\Ext\ObjectModule.bsl"

Для частичной загрузки используется прежний параметр LoadConfigFromFiles, и две новых опции: Files и ListFiles. Files позволяет вам перечислить через запятую те файлы, которые нужно загрузить, если таких файлов немного. А если их много, тогда вы можете использовать опцию ListFiles. Она указывает на файл, в котором перечислены XML файлы, которые нужно загрузить.

Кроме этого, для повышения удобства работы, мы разрешили совместное использование в одной строке параметров LoadConfigFromFiles и UpdateDBCfg. Таким образом, теперь за один вызов вы можете загрузить изменения и принять их (обновить конфигурацию базы данных).

Выгрузка/загрузка внешних отчётов и обработок в/из XML

В версии 8.3.8 мы добавили возможность выгружать в XML и загружать внешние отчёты и обработки:


Более того, при работе в конфигураторе вы можете сохранять их сразу в формате XML (Файл - Сохранить как. ). То же самое относится и к открытию:


Также мы добавили возможность сравнить внешний отчёт или обработку с XML выгрузкой. Все эти изменения мы сделали в первую очередь для того, чтобы в новой среде разработки 1C:Enterprise Development Tools обеспечить полноценную работу с внешними отчётами и обработками. Однако и отдельно от Development Tools эти возможности могут быть вам полезны для любых автоматизированных изменений выгруженных XML файлов.

Выгрузить/загрузить внешние отчёты/обработки вы можете не только интерактивно, но и автоматически, запуская конфигуратор в пакетном режиме. Для этого мы добавили два новых параметра: DumpExternalDataProcessorOrReportToFiles и LoadExternalDataProcessorOrReportFromFiles.

Читайте также: