В процессе разработки часто возникает задача выгрузки данных из 1С в формат XML. Если с выгрузкой одного объекта (например, справочника или массива) проблем обычно не возникает, то попытка последовательно записать несколько разных объектов в один файл часто приводит к ошибкам структуры XML. Основная причина заключается в том, что по стандартам XML документ должен иметь ровно один корневой элемент, внутри которого располагаются все остальные данные.
Разберем подробно несколько эффективных способов решения этой задачи, проанализируем их преимущества и недостатки, а также изучим правильные методы последующего чтения таких файлов.
Самый простой и очевидный способ, который часто применяют для небольших объемов данных, — это помещение всех необходимых объектов в один массив. Поскольку Массив в 1С является сериализуемым объектом, платформа сама создаст необходимую структуру при записи.
Рассмотрим пример кода:
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(Справочники.Номенклатура.НайтиПоКоду("001"));
МассивОбъектов.Добавить(Справочники.Контрагенты.НайтиПоКоду("002"));
МассивОбъектов.Добавить(Документы.РеализацияТоваровУслуг.НайтиПоНомеру("123", ТекущаяДата()));
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\data.xml", "UTF-8");
ЗаписатьXML(ЗаписьXML, МассивОбъектов);
ЗаписьXML.Закрыть();
Преимущества этого метода:
Важное ограничение: Если вы планируете выгружать десятки или сотни тысяч объектов, этот метод может привести к значительному потреблению оперативной памяти. Платформа сначала сформирует в памяти весь массив объектов, а затем начнет его сериализацию. Для больших данных лучше использовать потоковую запись.
Если нам нужно записать объекты по отдельности (например, в цикле выборки из базы данных), мы должны вручную создать корневой элемент. Это позволит записывать данные порциями, не перегружая память.
Проанализируем алгоритм потоковой записи:
ЗаписьXML = Новый ЗаписьXML;
// Настраиваем параметры записи для красивого форматирования
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина);
ЗаписьXML.ОткрытьФайл("C:\data.xml", ПараметрыЗаписи);
// Записываем заголовок документа
ЗаписьXML.ЗаписатьОбъявлениеXML();
// Создаем наш собственный корневой элемент
ЗаписьXML.ЗаписатьНачалоЭлемента("RootElement");
// В цикле записываем любые сериализуемые объекты
Выборка = Справочники.Номенклатура.Выбрать();
Пока Выборка.Следующий() Цикл
ЗаписатьXML(ЗаписьXML, Выборка.Ссылка);
КонецЦикла;
// Закрываем корневой элемент
ЗаписьXML.ЗаписатьКонецЭлемента();
// Закрываем файл
ЗаписьXML.Закрыть();
В этом примере мы использовали объект ПараметрыЗаписиXML. Установка свойства Отступ = Истина делает файл читаемым для человека, добавляя переносы строк и табуляцию. Метод ЗаписатьОбъявлениеXML() добавляет стандартную строку заголовка с указанием кодировки, что является хорошим тоном при работе с XML.
Для более сложных задач обмена данными, особенно когда требуется передать информацию о типах объектов или работать в рамках определенных схем, рекомендуется использовать СериализаторXDTO. Он предоставляет более гибкие инструменты управления процессом сериализации.
Посмотрим на пример записи через XDTO:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\data_xdto.xml");
ЗаписьXML.ЗаписатьНачалоЭлемента("DataExport");
// Используем глобальный СериализаторXDTO
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Объект1);
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Объект2);
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();
Использование СериализаторXDTO позволяет корректно сохранять ссылки на объекты, учитывая их пространства имен (URI), что критически важно при обмене данными между разными информационными базами.
Записать данные — это только половина задачи. Важно правильно их извлечь. Типичная ошибка при чтении нескольких объектов заключается в неправильном позиционировании курсора чтения. Рассмотрим правильный подход к чтению файла, созданного в Способе №2.
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("C:\data.xml");
// Переходим к корневому элементу
ЧтениеXML.Прочитать();
// Заходим внутрь корневого элемента
Пока ЧтениеXML.Прочитать() Цикл
// Проверяем, что мы находимся на начале элемента объекта, а не на конце корня
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Читаем объект. Метод ПрочитатьXML сам сдвинет курсор к концу прочитанного узла
Данные = ПрочитатьXML(ЧтениеXML);
// Обрабатываем полученные данные
Сообщить("Прочитан объект: " + Данные);
ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
// Если встретили конец корневого элемента - выходим
Прервать;
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
Важный нюанс: Обратите внимание, что внутри цикла мы используем проверку ТипУзла. Это необходимо, потому что метод ПрочитатьXML() после завершения своей работы позиционирует чтение на следующем узле. Если просто вызывать ЧтениеXML.Прочитать() в заголовке цикла без проверок, можно случайно пропустить ("перепрыгнуть") через один объект в файле.
Разберем несколько важных моментов, которые помогут избежать ошибок при работе с большими XML-файлами:
ЗаписьТекста совместно с ЗаписьXML.УстановитьСтроку(). Это избыточно. Используйте метод ОткрытьФайл непосредственно у объекта ЗаписьXML. Это работает быстрее и эффективнее расходует ресурсы.ПрочитатьXML или СериализаторXDTO.ПрочитатьXML всегда проверяйте тип полученного значения через ТипЗнч(). В файле могут оказаться неожиданные данные или пустые ссылки.Выяснив причины возникновения ошибок при записи нескольких объектов, мы убедились, что ключ к успеху — это соблюдение иерархической структуры XML. Выбирайте способ с массивом для простых задач и потоковую запись с ручным формированием корневого узла для профессиональной разработки и работы с большими объемами информации.