При разработке прикладных решений в 1С часто возникает необходимость сохранить структурированные данные (например, содержимое табличной части формы) в реквизит справочника, а затем при необходимости считывать их обратно. Нередко для этой задачи выбирают формат 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.НачалоЭлемента И ИмяУзла = "Товар" Тогда
Наименование = ФайлXML.ПолучитьАтрибут("Наименование");
Количество = ФайлXML.ПолучитьАтрибут("Количество");
// Добавление строк в табличную часть формы
КонецЕсли;
КонецЦикла;
ФайлXML.Закрыть();
КонецПроцедуры
Если для реквизита справочника использовать тип Строка (неограниченной длины) вместо ХранилищеЗначения, код станет еще проще. Это удобно при отладке, так как содержимое XML-структуры можно сразу посмотреть в режиме «1С:Предприятие» или в отладчике без вызова метода Получить().
Запись в строковый реквизит выполняется следующим образом:
НовыйОбъект = Справочники.Тест.СоздатьЭлемент();
НовыйОбъект.Наименование = "Настройки";
НовыйОбъект.ХМЛТест = ЗаписьXML.Закрыть(); // Метод Закрыть() возвращает строку XML
НовыйОбъект.Записать();
Чтение из строкового реквизита:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СсылкаНаСправочник.ХМЛТест);
Обратите внимание: использование типа ХранилищеЗначения с включенным сжатием (Новый СжатиеДанных) предпочтительнее при хранении больших объемов данных, так как это снижает размер базы данных. Строка неограниченной длины удобнее для небольших документов и быстрой разработки.
Если вам требуется сохранять данные именно в формате XML, но вы не хотите вручную прописывать каждый тег с помощью ЗаписатьНачалоЭлемента, используйте механизм СериализаторXDTO. Он позволяет автоматически превратить таблицу значений в XML и обратно.
Пример автоматической записи табличной части в XML:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
// Выгружаем табличную часть в таблицу значений и сериализуем
ТаблицаДанных = Объект.Товары.Выгрузить();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТаблицаДанных);
СтрокаXML = ЗаписьXML.Закрыть();
НовыйОбъект.ХранилищеТест = Новый ХранилищеЗначения(СтрокаXML, Новый СжатиеДанных);
НовыйОбъект.Записать();
Пример чтения данных из XML с помощью СериализаторXDTO:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СсылкаНаСправочник.ХранилищеТест.Получить());
ТаблицаДанных = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
Объект.Товары.Загрузить(ТаблицаДанных);
ЧтениеXML.Закрыть();
Выясним важную деталь: если данные формируются и читаются исключительно внутри одной информационной базы 1С, использовать промежуточный формат XML вообще не обязательно. В ХранилищеЗначения можно записать напрямую таблицу значений, структуру или массив.
Сохранение таблицы значений напрямую:
// Запись таблицы значений в реквизит справочника
НовыйОбъект = Справочники.Тест.СоздатьЭлемент();
НовыйОбъект.Наименование = "Сохраненный список";
НовыйОбъект.ХранилищеТест = Новый ХранилищеЗначения(Объект.Товары.Выгрузить(), Новый СжатиеДанных);
НовыйОбъект.Записать();
Восстановление таблицы значений из хранилища:
// Чтение таблицы значений из справочника
ТаблицаТоваров = СсылкаНаСправочник.ХранилищеТест.Получить();
Если ТипЗнч(ТаблицаТоваров) = Тип("ТаблицаЗначений") Тогда
Объект.Товары.Загрузить(ТаблицаТоваров);
КонецЕсли;
Прямое сохранение данных в ХранилищеЗначения является наиболее эффективным способом для работы внутри одной базы: оно выполняется быстрее, не требует обхода тегов и автоматически сохраняет точные типы данных 1С.