В процессе разработки на платформе 1С:Предприятие 8 программисты часто сталкиваются с архитектурным ограничением: типы данных, доступные на сервере, не всегда доступны на тонком или веб-клиенте. Одной из таких структур является ТаблицаЗначений. Если нам необходимо получить данные (например, список номенклатуры) с помощью запроса на сервере и передать их на клиент для сохранения в файл XML, мы не можем просто вернуть таблицу значений в качестве результата функции. Разберем наиболее эффективные и правильные способы решения этой задачи.
Проанализируем ситуацию: зачем передавать «сырые» данные на клиент, если конечная цель — получить файл? Самым производительным способом будет перенос всей логики формирования XML на сервер. На клиенте мы лишь инициируем процесс и получаем готовый результат. Рассмотрим по шагам, как это реализовать.
Шаг 1. Формирование данных на сервере. Используем объект ЗаписьXML для создания структуры файла непосредственно в памяти сервера (в строке) или во временном файле.
&НаСервере
Функция СформироватьXMLНаСервере()
// Создаем объект записи XML
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку(); // Будем записывать в строку
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("Root");
// Получаем данные запросом
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Ссылка, Код, Наименование ИЗ Справочник.Номенклатура";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ЗаписьXML.ЗаписатьНачалоЭлемента("Item");
ЗаписьXML.ЗаписатьАтрибут("Code", Строка(Выборка.Код));
ЗаписьXML.ЗаписатьАтрибут("Name", Выборка.Наименование);
ЗаписьXML.ЗаписатьКонецЭлемента();
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента();
СтрокаXML = ЗаписьXML.Закрыть();
// Помещаем результат во временное хранилище
// Это позволяет избежать передачи огромных строк через параметры
АдресХранилища = ПоместитьВоВременноеХранилище(СтрокаXML, ЭтаФорма.УникальныйИдентификатор);
Возврат АдресХранилища;
КонецФункции
Шаг 2. Получение и сохранение на клиенте. Проанализируем, как получить эти данные. Мы используем адрес временного хранилища, чтобы «скачать» сформированный контент.
&НаКлиенте
Процедура СохранитьФайл(Команда)
Адрес = СформироватьXMLНаСервере();
// Получаем данные из хранилища
Данные = ПолучитьИзВременногоХранилища(Адрес);
// Записываем данные в файл на диске клиента
ИмяФайла = "C:\Temp\Nomenclature.xml";
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(Данные);
ТекстовыйДокумент.Записать(ИмяФайла, КодировкаТекста.UTF8);
Сообщить("Файл успешно сохранен: " + ИмяФайла);
КонецПроцедуры
Если логика формирования XML слишком сложна для сервера или требует интерактивного взаимодействия с пользователем на клиенте, мы можем передать данные в виде коллекции, которая поддерживается на клиенте. Наилучший вариант здесь — Массив, содержащий объекты типа Структура.
Выясним причину выбора именно этой связки: Массив и Структура являются универсальными типами, которые сериализуются платформой при передаче между контекстами. Разберем пример кода:
&НаСервере
Функция ПолучитьДанныеМассивом()
Запрос = Новый Запрос("ВЫБРАТЬ Наименование, Артикул ИЗ Справочник.Номенклатура");
Таблица = Запрос.Выполнить().Выгрузить();
СписокДанных = Новый Массив;
Для Каждого СтрокаТЗ Из Таблица Цикл
НоваяСтрока = Новый Структура;
НоваяСтрока.Вставить("Наименование", СтрокаТЗ.Наименование);
НоваяСтрока.Вставить("Артикул", СтрокаТЗ.Артикул);
СписокДанных.Добавить(НоваяСтрока);
КонецЦикла;
Возврат СписокДанных;
КонецФункции
&НаКлиенте
Процедура ОбработатьНаКлиенте()
Данные = ПолучитьДанныеМассивом();
// Теперь на клиенте мы можем перебирать массив и формировать XML
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл("C:\Nomenclature.xml");
// ... логика записи ...
Запись.Закрыть();
КонецПроцедуры
Рассмотрим еще один интересный механизм. Если на управляемой форме создать реквизит с типом ТаблицаЗначений, платформа автоматически преобразует его в ДанныеФормыКоллекция на клиенте. Этот объект ведет себя почти как таблица значений и доступен в обоих контекстах.
Посмотрим на пример реализации:
ТаблицаЗначений.
&НаСервере
Процедура ЗаполнитьТаблицуНаСервере()
Запрос = Новый Запрос("ВЫБРАТЬ Код, Наименование ИЗ Справочник.Номенклатура ПЕРВЫЕ 10");
Результат = Запрос.Выполнить().Выгрузить();
// Используем метод ЗначениеВРеквизитФормы для быстрой загрузки
ЗначениеВРеквизитФормы(Результат, "ТоварыДляВыгрузки");
КонецПроцедуры
&НаКлиенте
Процедура ЗаписатьИзРеквизита(Команда)
ЗаполнитьТаблицуНаСервере();
// На клиенте обращаемся напрямую к реквизиту формы
Для Каждого Строка Из ТоварыДляВыгрузки Цикл
// Здесь можно выполнять любую логику, данные уже на клиенте
Сообщить(Строка.Наименование);
КонецЦикла;
КонецПроцедуры
Для передачи больших объемов данных между сервером и клиентом часто эффективнее использовать JSON. Проанализируем ситуацию: JSON-строка передается быстрее, чем массив структур, и занимает меньше оперативной памяти. Платформа 1С предоставляет встроенные средства для быстрой сериализации.
&НаСервере
Функция ПолучитьДанныеJSON()
Запрос = Новый Запрос("ВЫБРАТЬ Наименование ИЗ Справочник.Номенклатура");
Таблица = Запрос.Выполнить().Выгрузить();
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, Таблица); // Платформа сама умеет сериализовать ТЗ в JSON
Возврат ЗаписьJSON.Закрыть();
КонецФункции
&НаКлиенте
Процедура ПрочитатьJSONНаКлиенте()
СтрокаJSON = ПолучитьДанныеJSON();
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
Данные = ПрочитатьJSON(ЧтениеJSON); // Получаем массив структур
ЧтениеJSON.Закрыть();
КонецПроцедуры
Проанализировав все способы, можно сделать следующие выводы:
ЗаписьXML и передавайте либо готовую строку, либо ДвоичныеДанные через временное хранилище. Это избавит клиентское приложение от лишних вычислений.Важное примечание: При работе с файлами на клиенте в современных версиях (8.3.15+) рекомендуется использовать асинхронные методы, такие как ПолучитьФайлССервераАсинх(), чтобы интерфейс программы не блокировался во время передачи данных.