При необходимости обмена данными между различными информационными базами 1С, особенно когда речь идет о сложных структурах, таких как объекты Структура, содержащие в себе ТабличныеДокументы, возникает вопрос о методах их передачи. Прямая передача объекта 1С по сети невозможна, так как он существует только в контексте своей базы. Вместо этого, мы должны преобразовать объект в последовательный формат (сериализовать), передать его, а затем воссоздать (десериализовать) на принимающей стороне.
В этом руководстве мы рассмотрим различные подходы к решению этой задачи, основываясь на рекомендациях и практическом опыте сообщества 1С. При необходимости настроить регулярную синхронизацию баз по расписанию вместо разовой отправки применяется программа автоматического обмена данными между базами 1С.
Прежде чем углубляться в детали, важно понять, что веб-сервисы (и HTTP-сервисы) в 1С работают с данными, которые могут быть представлены в стандартизированных форматах, таких как XML или JSON. Это означает, что любой объект 1С, который мы хотим передать, должен быть преобразован в один из этих форматов. Этот процесс называется сериализацией. Обратный процесс, когда данные из XML или JSON преобразуются обратно в объекты 1С, называется десериализацией.
Рассмотрим основные методы, которые позволяют нам эффективно передавать сложные структуры, включая ТабличныеДокументы, между базами 1С.
XDTO (XML Data Transfer Object) — это мощный механизм платформы 1С:Предприятие, предназначенный для работы с XML-схемами и сериализации объектов 1С в формат XML и обратно. Он позволяет нам сохранять не только значения данных, но и типы объектов, их структуру и даже сложные свойства.
Определение типов XDTO. Для успешной передачи структуры, содержащей табличные документы, критически важно правильно описать эти типы в XDTO-пакетах вашей конфигурации 1С. Платформа предоставляет предопределенные типы для многих стандартных объектов:
Для стандартного объекта ТабличныйДокумент платформа "1С:Предприятие" предлагает предопределенный тип XDTO: SpreadsheetDocument из пространства имен http://v8.1c.ru/8.2/data/spreadsheet. Использование этого типа позволяет нам сохранить не только содержимое ячеек, но и форматирование, параметры печати, имена областей и другие специфические свойства табличного документа.
Для 1С-объекта Структура (который создается командой Новый Структура) также существует предопределенный тип XDTO: Structure из пространства имен http://v8.1c.ru/8.1/data/core. Если же ваша структура имеет более сложный и строго определенный состав (например, всегда содержит два табличных документа и строковое поле), мы можем создать собственный составной тип XDTO в конфигурации, явно описав все его поля и их типы (например, поля типа SpreadsheetDocument).
Серверный метод веб-сервиса. На стороне-источнике (где находится передаваемая структура) мы создадим метод веб-сервиса, который будет принимать или возвращать объект, соответствующий нашему XDTO-типу. Если мы определили собственный XDTO-тип для нашей структуры, то метод веб-сервиса будет работать непосредственно с этим типом.
Сериализация и десериализация. Для преобразования объектов 1С в XML-представление и обратно мы используем методы СериализаторXDTO.ЗаписатьXML() и СериализаторXDTO.ПрочитатьXML(). Эти методы являются краеугольными камнями при работе с XDTO.
Рассмотрим гипотетический пример кода, демонстрирующий принцип работы с XDTO для передачи одного табличного документа. Если бы мы определили сложный XDTO-тип, включающий несколько табличных документов, логика была бы аналогичной, но более объемной в части описания типа.
Пример кода на стороне сервера (публикация веб-сервиса):
// В модуле веб-сервиса (серверная сторона, публикация)
// Допустим, мы определили XDTO-тип "МояСтруктураСТабличнымиДокументами",
// который содержит поля типа SpreadsheetDocument
// Функция веб-сервиса будет выглядеть так:
// Параметр "СтруктураДляПередачи" будет автоматически сериализован/десериализован платформой
Функция ПередатьДанныеСоСтруктурой(СтруктураДляПередачи) Экспорт
// СтруктураДляПередачи уже является объектом XDTO,
// который платформа автоматически десериализовала из входящего XML/SOAP.
// Если нам нужно получить объекты 1С ТабличныйДокумент из полей XDTO-структуры,
// то платформа делает это "умно", и если тип определен как SpreadsheetDocument,
// то в полях XDTO-объекта будут уже объекты 1С ТабличныйДокумент.
// Пример работы с полями структуры, содержащими ТабличныеДокументы
ТабДок1 = СтруктураДляПередачи.ПервыйТабДок; // Получаем ТабличныйДокумент 1С
ТабДок2 = СтруктураДляПередачи.ВторойТабДок; // Получаем ТабличныйДокумент 1С
// Далее мы можем работать с ТабДок1 и ТабДок2 как с обычными объектами 1С
// ...
// Если функция должна что-то вернуть, например, подтверждение или измененную структуру:
Результат = Новый XDTOОбъект(ФабрикаXDTO.Пакеты.Получить("http://v8.1c.ru/8.1/data/core").Получить("Structure"));
Результат.Вставить("Статус", "Успешно");
Возврат Результат; // Платформа сама выполнит XDTO-сериализацию возвращаемого значения
КонецФункции
Пример кода на стороне клиента (потребление веб-сервиса):
// На стороне клиента (потребитель веб-сервиса)
WSОпределение = Новый WSОпределение("http://localhost/МояБаза/ws/МойВебСервис.1cws?wsdl");
Прокси = Новый WSПрокси(WSОпределение, "http://www.example.com", "МойВебСервис", "МойВебСервисПорт");
// Создаем объект XDTO, соответствующий нашей структуре
// Предполагаем, что XDTO-тип "МояСтруктураСТабличнымиДокументами" доступен через ФабрикуXDTO
ТипСтруктуры = ФабрикаXDTO.Пакеты.Получить("http://www.example.com/xdto-пакеты/МойПакет").Получить("МояСтруктураСТабличнымиДокументами");
ПередаваемаяСтруктураXDTO = Новый XDTOОбъект(ТипСтруктуры);
// Заполняем поля, которые являются ТабличнымиДокументами
ТабДок1 = Новый ТабличныйДокумент;
ТабДок1.Область("R1C1").Текст = "Данные из первого документа";
// ... заполняем ТабДок1
ТабДок2 = Новый ТабличныйДокумент;
ТабДок2.Область("R1C1").Текст = "Данные из второго документа";
// ... заполняем ТабДок2
// Присваиваем ТабличныеДокументы полям XDTO-структуры.
// Платформа 1С "умно" понимает, что это ТабличныеДокументы
// и автоматически сериализует их в соответствующий XDTO-тип SpreadsheetDocument.
ПередаваемаяСтруктураXDTO.ПервыйТабДок = ТабДок1;
ПередаваемаяСтруктураXDTO.ВторойТабДок = ТабДок2;
ПередаваемаяСтруктураXDTO.ДопИнформация = "Это дополнительная информация";
// Вызываем метод веб-сервиса
Результат = Прокси.ПередатьДанныеСоСтруктурой(ПередаваемаяСтруктураXDTO);
Сообщить("Статус операции: " + Результат.Статус);
Использование XDTO является наиболее "правильным" и типовым способом передачи сложных, структурированных данных, когда требуется сохранить максимальную информацию об объекте и его свойствах.
Этот подход, активно обсуждаемый на форумах, является одним из наиболее гибких и рабочих вариантов, особенно когда нам нужно передать произвольную коллекцию объектов, включая табличные документы, без необходимости строгого определения одного комплексного XDTO-типа для всей структуры. Он комбинирует универсальные методы сериализации 1С для сложных объектов и специфическую XDTO-сериализацию для табличных документов.
Принцип: Мы сериализуем каждый ТабличныйДокумент в XML-строку с помощью СериализаторXDTO, затем помещаем эти XML-строки (возможно, вместе с другой вспомогательной информацией) в ТаблицаЗначений или Массив. Всю эту коллекцию мы затем сериализуем в одну большую строку с помощью функции ЗначениеВСтрокуВнутр(). Эта строка затем передается через веб-сервис.
На стороне-источнике (отправитель):
Мы собираем все данные, которые хотим передать, в объект ТаблицаЗначений. Это позволяет нам гибко добавлять любое количество табличных документов и сопутствующую информацию.
// 1. Создаем ТаблицуЗначений для сбора данных
т = Новый ТаблицаЗначений;
т.Колонки.Добавить("Объект"); // Колонка для сериализованного ТабличногоДокумента
т.Колонки.Добавить("ИмяТабДока"); // Колонка для дополнительной информации (например, имя)
т.Колонки.Добавить("НомерПоПорядку"); // Еще одна доп. колонка, если нужно
Для каждого ТабличныйДокумент, который мы хотим передать:
Создадим новую строку в нашей ТаблицаЗначений.
// Пример для первого ТабличногоДокумента
НовСтрока = т.Добавить();
Используем ЗаписьXML и СериализаторXDTO.ЗаписатьXML() для преобразования ТабличныйДокумент в XML-строку. Важно: для объекта ТабличныйДокумент нам не нужно получать объект базы данных (как ПолучитьОбъект() для ссылочных типов), его можно сразу передавать в сериализатор.
// Получаем или создаем первый ТабличныйДокумент
ТабДок1 = Новый ТабличныйДокумент;
ТабДок1.Область("R1C1").Текст = "Отчет за Январь";
ТабДок1.Область("R2C1").Текст = "Сумма:";
ТабДок1.Область("R2C2").Текст = 1234.56;
// Сериализуем ТабличныйДокумент в XML-строку
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТабДок1);
НовСтрока.Объект = ЗаписьXML.Закрыть(); // Это наша XML-строка
Добавим любую сопроводительную информацию, которая поможет нам идентифицировать или обработать этот табличный документ на принимающей стороне.
НовСтрока.ИмяТабДока = "ПродажиЯнварь";
НовСтрока.НомерПоПорядку = 1;
Повторим этот процесс для второго табличного документа (и любого последующего):
// Пример для второго ТабличногоДокумента
НовСтрока = т.Добавить();
ТабДок2 = Новый ТабличныйДокумент;
ТабДок2.Область("R1C1").Текст = "Отчет за Февраль";
ТабДок2.Область("R2C1").Текст = "Сумма:";
ТабДок2.Область("R2C2").Текст = 987.65;
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТабДок2);
НовСтрока.Объект = ЗаписьXML.Закрыть();
НовСтрока.ИмяТабДока = "ПродажиФевраль";
НовСтрока.НомерПоПорядку = 2;
Теперь, когда все табличные документы и связанные с ними данные собраны в ТаблицаЗначений, мы сериализуем всю эту таблицу в одну большую строку с помощью функции ЗначениеВСтрокуВнутр(). Эта строка и будет передаваться через веб-сервис.
Посылка = ЗначениеВСтрокуВнутр(т);
// Эту строку 'Посылка' мы передаем в качестве параметра метода веб-сервиса
// Например, WS-метод будет иметь один строковый параметр: Функция ПринятьПосылку(ДанныеПосылкиСтрокой) Экспорт
На принимающей стороне (получатель):
После получения строки от веб-сервиса нам необходимо десериализовать её и восстановить каждый ТабличныйДокумент.
Полученную строку десериализуем обратно в ТаблицаЗначений с помощью ЗначениеИзСтрокиВнутр().
// Предполагаем, что 'ПолученнаяСтрокаОтСервиса' - это строка,
// которую мы получили из веб-сервиса (параметр функции)
т = ЗначениеИзСтрокиВнутр(ПолученнаяСтрокаОтСервиса);
Теперь нам нужно пройти по каждой строке полученной ТаблицаЗначений. В каждой строке содержится XML-представление одного табличного документа, которое мы десериализуем обратно в объект ТабличныйДокумент 1С.
Для Каждого Стр Из т Цикл
// Создаем объект ЧтениеXML и устанавливаем в него XML-строку из колонки "Объект"
ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.УстановитьСтроку(Стр.Объект);
// СериализаторXDTO.ПрочитатьXML() восстановит наш ТабличныйДокумент 1С
ВосстановленныйТабДок = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
// Теперь у нас есть полностью восстановленный ТабличныйДокумент 1С.
// Мы можем с ним работать: сохранить, показать, обработать данные.
Сообщить("Получен табличный документ с именем: " + Стр.ИмяТабДока + ", порядковый номер: " + Стр.НомерПоПорядку);
// Например, можно сохранить его в файл или отобразить:
// ВосстановленныйТабДок.Записать("C:\Temp\" + Стр.ИмяТабДока + ".mxl");
// ВосстановленныйТабДок.Показать();
КонецЦикла;
Преимущества этого подхода:
Гибкость: Этот метод позволяет передавать не только табличные документы, но и любые другие сериализуемые объекты 1С (ссылки, значения, коллекции) внутри ТаблицаЗначений или Массив.
Сохранение структуры: Благодаря XDTO-сериализации каждого ТабличныйДокумент, на принимающей стороне он восстанавливается со всем форматированием, настройками и свойствами.
Дополнительные данные: Очень легко добавить любую сопроводительную информацию (имена, идентификаторы, статусы) к каждому передаваемому элементу, поместив её в отдельные колонки ТаблицаЗначений.
Универсальность: Не требует создания специфичных XDTO-пакетов для всей передаваемой структуры, если она очень динамична.
JSON является широко распространенным и популярным форматом для обмена данными, особенно в контексте HTTP-сервисов и веб-разработки. Он привлекателен благодаря своей легковесности, хорошей читаемости для человека и широкой поддержке во множестве языков программирования и систем.
Преимущества JSON:
Меньший объем данных: Для простых структур JSON часто генерирует меньший объем данных по сравнению с XML.
Читаемость: Структура JSON обычно более интуитивно понятна.
Кроссплатформенность: Очень хорошо подходит для интеграции с не-1С системами, которые предпочитают или изначально работают с JSON.
Сериализация в JSON: В 1С для работы с JSON используются объекты ЗаписьJSON и ЧтениеJSON. Однако здесь кроется одно важное отличие от XDTO: платформа 1С не имеет встроенного механизма для прямой и полной сериализации комплексных объектов, таких как ТабличныйДокумент, в JSON с автоматическим сохранением всего его содержимого, форматирования и специфических свойств.
Ручное преобразование: Если мы выбираем JSON, нам придется самостоятельно извлекать нужные данные из ТабличныйДокумент (например, значения ячеек, их координаты, возможно, базовые стили) и формировать из них более простые структуры данных 1С (массивы, структуры, соответствующие JSON-объектам и массивам), которые затем могут быть легко сериализованы в JSON. Это означает, что полное форматирование, настройки печати и некоторые специфические свойства табличного документа могут быть потеряны, если мы явно не извлечем их и не передадим в составе JSON.
Пример формирования данных из `ТабличныйДокумент` для JSON:
// Функция для извлечения содержимого ТабличногоДокумента в массив для JSON
// Этот пример извлекает только текст ячеек.
// Для сохранения форматирования потребуется гораздо более сложная логика.
Функция ТабличныйДокументВМассивДляJSON(ТабДок)
ДанныеТабДока = Новый Массив;
Для ИндексСтроки = 1 По ТабДок.ВысотаТаблицы Цикл
СтрокаДанных = Новый Массив;
Для ИндексКолонки = 1 По ТабДок.ШиринаТаблицы Цикл
Ячейка = ТабДок.Область(ИндексСтроки, ИндексКолонки);
СтрокаДанных.Добавить(Ячейка.Текст); // Извлекаем только текст ячейки
КонецЦикла;
ДанныеТабДока.Добавить(СтрокаДанных);
КонецЦикла;
Возврат ДанныеТабДока;
КонецФункции
// На стороне-источнике (отправитель)
// Создаем ТабличныеДокументы
ТабДок1 = Новый ТабличныйДокумент;
ТабДок1.Область("R1C1").Текст = "Заголовок 1";
ТабДок1.Область("R2C2").Текст = "Значение А";
ТабДок2 = Новый ТабличныйДокумент;
ТабДок2.Область("R1C1").Текст = "Заголовок 2";
ТабДок2.Область("R3C3").Текст = "Значение Б";
// Формируем структуру 1С, которая будет сериализована в JSON
МояСтруктураДляПередачи = Новый Структура;
МояСтруктураДляПередачи.Вставить("ИмяБазы", "Бухгалтерия");
МояСтруктураДляПередачи.Вставить("ПервыйТабДокДанные", ТабличныйДокументВМассивДляJSON(ТабДок1));
МояСтруктураДляПередачи.Вставить("ВторойТабДокДанные", ТабличныйДокументВМассивДляJSON(ТабДок2));
МояСтруктураДляПередачи.Вставить("ДополнительныйКомментарий", "Данные отчетов за два месяца.");
// Сериализуем структуру в JSON-строку
ЗаписьJSON = Новый ЗаписьJSON();
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МояСтруктураДляПередачи); // Используем глобальную функцию ЗаписатьJSON
СтрокаJSON = ЗаписьJSON.Закрыть();
// 'СтрокаJSON' отправляем через HTTP-сервис или веб-сервис,
// который принимает строковые параметры
На принимающей стороне (получатель):
// Получаем 'СтрокаJSON' от сервиса
ЧтениеJSON = Новый ЧтениеJSON();
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
ПолученныеДанные = ПрочитатьJSON(ЧтениеJSON); // Используем глобальную функцию ПрочитатьJSON
// ПолученныеДанные будет объектом Структура 1С
ИмяБазы = ПолученныеДанные.ИмяБазы;
ДанныеПервогоТабДока = ПолученныеДанные.ПервыйТабДокДанные; // Это массив массивов
ДанныеВторогоТабДока = ПолученныеДанные.ВторойТабДокДанные;
Комментарий = ПолученныеДанные.ДополнительныйКомментарий;
Сообщить("Данные получены из базы: " + ИмяБазы);
Сообщить("Комментарий: " + Комментарий);
// Теперь мы можем воссоздать ТабличныйДокумент из массива массивов,
// если это необходимо, или использовать данные по-другому
ВосстановленныйТабДок1 = Новый ТабличныйДокумент;
Для Каждого СтрокаМассива Из ДанныеПервогоТабДока Цикл
НоваяСтрокаТабДока = ВосстановленныйТабДок1.Область(ВосстановленныйТабДок1.ВысотаТаблицы + 1, 1, ВосстановленныйТабДок1.ВысотаТаблицы + 1, СтрокаМассива.Количество());
Для Индекс = 0 По СтрокаМассива.ВГраница() Цикл
НоваяСтрокаТабДока.Область(1, Индекс + 1).Текст = СтрокаМассива[Индекс];
КонецЦикла;
КонецЦикла;
// ВосстановленныйТабДок1.Показать();
JSON подход может быть более трудоемким для комплексных объектов, таких как ТабличныйДокумент, если требуется сохранить все детали, но он является оптимальным выбором, если нужны только сырые данные без форматирования или при интеграции с не-1С системами, предпочитающими JSON.
OData/REST-интерфейс: Платформа 1С:Предприятие позволяет автоматически публиковать REST-интерфейс (на основе протокола OData) для прикладных решений. Этот подход идеален для типовой интеграции с внешними системами, когда требуется работать с метаданными и данными объектов базы (справочниками, документами, регистрами). Он предоставляет стандартный способ чтения, создания, изменения и удаления объектов конфигурации. Однако он не предназначен для вызова произвольных процедур общих модулей или прямого манипулирования сложными объектами, как ТабличныйДокумент, в их полной объектной модели. Если нужно передать ТабличныйДокумент через OData, его придется предварительно сериализовать в строку (например, Base64 для бинарных данных или текстовое представление) и передавать как строковое поле объекта, либо как присоединенный файл.
OData идеален для интеграции на уровне бизнес-объектов, но не для передачи внутренних "служебных" объектов, таких как ТабличныйДокумент, в их полном объеме.
Размер передаваемых данных: ТабличныйДокумент может быть очень объемным, особенно если содержит много ячеек, сложное форматирование, картинки или встроенные объекты. Передача таких данных по сети может сильно повлиять на производительность и стабильность соединения. Рассмотрим следующие варианты для оптимизации:
Сжатие данных: Перед отправкой можно сжать сериализованную строку (XML или JSON) с использованием методов сжатия 1С. Для строковых данных можно использовать функции СжатьСтроку()/РазжатьСтроку(), хотя они менее эффективны для бинарных представлений. Более универсальный подход — это преобразование строки в ДвоичныеДанные и использование методов сжатия, которые поддерживает платформа 1С (например, Zip). На принимающей стороне данные разжимаются перед десериализацией.
Передача частичных данных: Всегда критически оценивайте, действительно ли вам нужен весь ТабличныйДокумент со всеми его свойствами. Возможно, достаточно передать только ключевые данные (например, только значения ячеек определенного диапазона), а форматирование и другие свойства воссоздать на принимающей стороне по заранее определенному шаблону.
Пакетная передача: Если объем данных очень большой и их можно логически разделить, рассмотрите возможность разбиения на несколько запросов. Например, вместо передачи одного огромного табличного документа, передавайте несколько меньших или данные для нескольких строк за один запрос.
Безопасность и целостность данных: При любом обмене данными между базами через веб-сервисы и HTTP-сервисы жизненно важно обеспечить безопасность и надежность соединения:
Всегда используйте защищенное соединение (HTTPS) для веб-сервисов и HTTP-сервисов, чтобы предотвратить перехват и изменение данных.
Настройте контроль доступа: используйте логин/пароль или токены аутентификации для авторизации запросов к вашим сервисам. Это гарантирует, что только авторизованные пользователи или системы могут получить доступ к данным.
Обязательно проводите проверку полученных данных на принимающей стороне. Это помогает обеспечить целостность информации, предотвратить ошибки и защититься от потенциально вредоносных данных. Например, для контроля за правильностью проведения перенесенных документов используется обработка сверки проводок между базами 1С.
Выбор конкретного метода для передачи структуры, содержащей табличные документы, зависит от ваших индивидуальных требований к проекту:
Если вам необходимо передать ТабличныйДокумент со всем его форматированием, настройками и свойствами максимально точно, и вы готовы определить строгую XDTO-схему для вашей структуры, то XDTO-сериализация является наиболее подходящим и "нативным" выбором 1С. Гибридный подход с ЗначениеВСтрокуВнутр() и XML-сериализацией каждого табличного документа также отлично подходит и предоставляет большую гибкость без строгих XDTO-схем для всей структуры.
Если для вас важна легковесность, совместимость с внешними не-1С системами, и достаточно передать только сырые данные из табличного документа без детального форматирования, то JSON-сериализация с ручным извлечением данных будет предпочтительна. Этот путь требует больше ручной работы по формированию и разбору данных.
Если требуется типовая интеграция с объектами метаданных 1С (справочниками, документами), а не передача произвольных сложных внутренних объектов, то рассмотрите OData/REST-интерфейс, помня о его ограничениях для прямой передачи ТабличныхДокументов.
Мы подробно рассмотрели различные методы, которые позволяют успешно передавать структуры, содержащие табличные документы, между базами 1С через веб-сервисы. Каждый из подходов имеет свои особенности, преимущества и недостатки, и выбор зависит от конкретных задач и требований к передаваемым данным и их детализации. Если вместо разработки веб-сервисов требуется выполнить точечную миграцию объектов вручную, для этого применяется обработка переноса данных между похожими конфигурациями 1С.