Разработчики 1С часто сталкиваются с задачей преобразования данных из внешних XML-документов во внутренние объекты платформы, такие как ТаблицаЗначений. Идеальным сценарием для многих было бы выполнение этой операции "одним хитрым заклинанием", используя механизмы XDTO платформы. Однако, как показывает практика и обсуждения на форумах, прямой и универсальный способ такой трансформации без промежуточных шагов или ручного кодирования не существует. Давайте разберем, почему так происходит, и какие рабочие подходы мы можем использовать.
Предположим, у нас есть некий произвольный XML-документ, например, содержащий список пунктов выдачи заказов (ПВЗ):
ПВЗ Октябрьская
PVZ001
Москва
ул. Октябрьская, 1
1
ПВЗ Ленина
PVZ002
Санкт-Петербург
пр-т Ленина, 5
2
Мы хотим получить из него стандартную ТаблицаЗначений 1С, например, со следующими колонками: "Название", "КодПВЗ", "Город", "Адрес", "КодГорода". Рассмотрим возможности и ограничения платформы.
Многие разработчики надеются, что, используя СериализаторXDTO, можно "скормить" ему произвольный XML и получить на выходе ТаблицуЗначений. Конструкции, подобные следующей, кажутся интуитивно понятными:
ЧтениеXMLДанных = Новый ЧтениеXML;
ЧтениеXMLДанных.УстановитьСтроку(СтрокаXML);
ТЗ = СериализаторXDTO.ПрочитатьXML(ЧтениеXMLДанных); // Ожидается ТаблицаЗначений
Однако такой подход не сработает. Важно понимать, что объект СериализаторXDTO в 1С предназначен для сериализации и десериализации объектов 1С в XML и обратно, а не для трансформации структур данных. Это означает, что для успешной десериализации XML в конкретный объект 1С, XML-документ должен уже иметь структуру, которая строго соответствует внутренней схеме сериализации этого объекта, жестко прошитой в платформе.
Для ТаблицыЗначений платформа 1С ожидает XML-структуру, которая включает определенные элементы, атрибуты и пространства имен (например, http://v8.1c.ru/8.1/data/ui/system). Произвольный XML, полученный из внешнего источника, практически никогда не будет соответствовать этой внутренней схеме. Поэтому СериализаторXDTO не сможет его корректно распознать и преобразовать в ТаблицуЗначений.
Попытки создать собственный XDTO-пакет, который бы "объяснил" платформе, как сопоставить произвольную XML-структуру с ТаблицейЗначений, также не увенчаются успехом. Механизм XDTO-пакетов служит для описания типов данных, а не для определения логики их преобразования. Мы можем описать пользовательские типы, которые будут десериализованы в объекты XDTO, но не можем заставить СериализаторXDTO десериализовать наш произвольный XML в системный тип ТаблицаЗначений на основе нашего собственного XDTO-пакета, игнорируя встроенные правила. Попытка создать "альтернативный" пакет для ТаблицыЗначений приведет к конфликту со встроенными схемами платформы, либо Сериализатор просто проигнорирует наш пакет, пытаясь применить свои жестко закодированные правила.
Таким образом, "волшебной кнопки" для прямого преобразования произвольного XML в ТаблицуЗначений средствами XDTO не существует. Нам придется выбрать один из двух рабочих подходов.
Этот подход является наиболее прямолинейным и прозрачным. Он включает в себя последовательное чтение XML-документа, создание промежуточных объектов XDTO (согласно схеме XML, если она есть, или без нее, используя "свободные" объекты XDTO), а затем ручное заполнение колонок и строк ТаблицыЗначений данными из этих объектов.
ТаблицуЗначений: Определяем необходимые колонки и их типы. Это гарантирует, что наша таблица будет иметь нужную структуру.ЧтениеXML: Устанавливаем в него нашу исходную XML-строку или файл.ФабрикаXDTO.ПрочитатьXML() для десериализации XML в объект или коллекцию объектов XDTO. Если у нас есть схема для входящего XML, мы можем предварительно загрузить её в ФабрикуXDTO. Если схемы нет, ФабрикаXDTO создаст "свободные" XDTO-объекты, структуру которых можно будет обходить.ТаблицеЗначений.ТаблицыЗначений: Присваиваем значения свойствам созданной строки, извлекая данные из соответствующих свойств объекта XDTO.Рассмотрим пример, который реализует этот подход для нашего XML с ПВЗ:
Функция ПреобразоватьXMLВТаблицуЗначенийРучнойСпособ(СтрокаXML) Экспорт
// 1. Создаем пустую ТаблицуЗначений с нужными колонками
тзПВЗ = Новый ТаблицаЗначений;
тзПВЗ.Колонки.Добавить("Название", Новый ОписаниеТипов("Строка"));
тзПВЗ.Колонки.Добавить("КодПВЗ", Новый ОписаниеТипов("Строка"));
тзПВЗ.Колонки.Добавить("Город", Новый ОписаниеТипов("Строка"));
тзПВЗ.Колонки.Добавить("Адрес", Новый ОписаниеТипов("Строка"));
тзПВЗ.Колонки.Добавить("КодГорода", Новый ОписаниеТипов("Строка"));
// 2. Инициализируем ЧтениеXML
ЧтениеXMLДанных = Новый ЧтениеXML;
ЧтениеXMLДанных.УстановитьСтроку(СтрокаXML);
// 3. Читаем XML в объект XDTO. Предполагаем, что корневой элемент - это набор данных.
// Если у нас нет XSD схемы, ФабрикаXDTO.ПрочитатьXML может вернуть "свободный" объект XDTO,
// свойства которого будут соответствовать структуре XML.
// Для более надежной работы, можно предварительно загрузить XSD-схему, описывающую структуру вашего XML,
// в ФабрикуXDTO (НаборСхемXML.Загрузить() или ФабрикаXDTO.ЗагрузитьПакет()).
// В данном случае, мы читаем корневой элемент, который является контейнером для списка ПВЗ.
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXMLДанных);
// 4. Получаем список элементов "Pvz".
// Если XML имеет такую структуру: ... ...
// то СписокПВЗ будет коллекцией XDTO-объектов.
СписокПВЗ = ОбъектXDTO.PvzList.Pvz; // или ОбъектXDTO.ПолучитьСписок("Pvz") в зависимости от структуры и XSD
// Убедимся, что СписокПВЗ является коллекцией, даже если в XML только один элемент.
// XDTO-фабрика может вернуть один объект, если элементов типа Pvz только один.
Если ТипЗнч(СписокПВЗ) = Тип("ОбъектXDTO") Тогда
ВременныйСписок = Новый Массив;
ВременныйСписок.Добавить(СписокПВЗ);
СписокПВЗ = ВременныйСписок;
КонецЕсли;
// 5. Обходим объекты XDTO и заполняем ТаблицуЗначений
Для каждого ПВЗ Из СписокПВЗ Цикл
стр = тзПВЗ.Добавить();
стр.Название = ПВЗ.Name;
стр.КодПВЗ = ПВЗ.Code;
стр.Город = ПВЗ.City;
стр.Адрес = ПВЗ.Address;
стр.КодГорода = ПВЗ.CityCode;
КонецЦикла;
Возврат тзПВЗ;
КонецФункции
// Пример использования:
СтрокаИсходногоXML = "ПВЗ Октябрьская PVZ001Москва ул. Октябрьская, 11 ПВЗ Ленина PVZ002Санкт-Петербург пр-т Ленина, 52 ";
ТЗ_Результат = ПреобразоватьXMLВТаблицуЗначенийРучнойСпособ(СтрокаИсходногоXML);
ТаблицыЗначений.ТаблицеЗначений.Этот подход является более "элегантным" с точки зрения сокращения кода 1С, но переносит сложность в XSLT-шаблон. Идея заключается в том, чтобы использовать объект ПреобразованиеXSL для трансформации исходного произвольного XML-документа в XML-документ, который по своей структуре полностью соответствует схеме сериализации ТаблицыЗначений в 1С. После такого преобразования СериализаторXDTO сможет напрямую прочитать полученный XML и вернуть готовую ТаблицуЗначений.
ТаблицыЗначений 1С. Это самый сложный и ответственный шаг, требующий знаний XSLT и понимания целевой структуры XML для ТаблицыЗначений.ПреобразованиеXSL: Загружаем наш XSLT-шаблон в объект ПреобразованиеXSL.ПреобразоватьИзСтроки() (или ПреобразоватьИзФайла()) для выполнения XSLT-трансформации. На выходе получаем новую XML-строку, соответствующую схеме ТаблицыЗначений.ЧтениеXML и СериализаторXDTO.ПрочитатьXML() для десериализации полученной XML-строки в объект ТаблицаЗначений.Для нашего примера с ПВЗ, XSLT-шаблон будет выглядеть следующим образом. Обратите внимание на использование пространств имен http://v8.1c.ru/8.1/data/ui/system, которые необходимы для корректной десериализации ТаблицыЗначений в 1С.
// XSLT-шаблон (СтрокаСхемыXSL)
Важное замечание по XSLT: в выражениях XPath для выбора дочерних элементов (например, Name, Code) следует использовать прямой путь (Name) или относительный (./Name), если контекст элемента уже установлен, а не атрибутный (@Name), если это не является атрибутом. Если у вас возникли проблемы с XSLT, проверьте корректность XPath-выражений, особенно для выбора дочерних узлов. Также в XSLT-шаблонах следует избегать вызова шаблонов внутри для простых операций, это может усложнить читаемость и отладку.
Код 1С для выполнения преобразования:
Функция ПреобразоватьXMLВТаблицуЗначенийЧерезXSLT(СтрокаXML, СтрокаСхемыXSL) Экспорт
// 1. Инициализируем ПреобразованиеXSL и загружаем шаблон
Преобразование_ПВЗ = Новый ПреобразованиеXSL;
Преобразование_ПВЗ.ЗагрузитьИзСтроки(СтрокаСхемыXSL);
// 2. Выполняем преобразование исходного XML в целевой формат ТаблицыЗначений
СтрокаXML_ПВЗ = Преобразование_ПВЗ.ПреобразоватьИзСтроки(СтрокаXML);
// 3. Десериализуем полученный XML в ТаблицуЗначений
ЧтениеXML_ПВЗ = Новый ЧтениеXML;
ЧтениеXML_ПВЗ.УстановитьСтроку(СтрокаXML_ПВЗ);
ТЗ_Результат = СериализаторXDTO.ПрочитатьXML(ЧтениеXML_ПВЗ);
Возврат ТЗ_Результат;
КонецФункции
// Пример использования:
СтрокаИсходногоXML = "ПВЗ Октябрьская PVZ001Москва ул. Октябрьская, 11 ПВЗ Ленина PVZ002Санкт-Петербург пр-т Ленина, 52 ";
СтрокаXSLTШаблона = // ... здесь должен быть ваш XSLT-шаблон из примера выше ...
ТЗ_Результат = ПреобразоватьXMLВТаблицуЗначенийЧерезXSLT(СтрокаИсходногоXML, СтрокаXSLTШаблона);
ТаблицаЗначений: Объект 1С для хранения табличных данных. Методы: Колонки.Добавить(), Добавить().ОписаниеТипов: Объект для определения типов колонок в ТаблицеЗначений.ЧтениеXML: Объект для чтения XML-документов. Методы: УстановитьСтроку(), Прочитать(), ПрочитатьЭлемент().ФабрикаXDTO: Объект для работы с XDTO-пакетами и десериализации XML в объекты XDTO. Методы: ПрочитатьXML(), ЗагрузитьПакет(), ПолучитьСписок().ОбъектXDTO: Представление XML-данных в виде объекта 1С, со свойствами, соответствующими структуре XML.СериализаторXDTO: Статический объект платформы для (де)сериализации стандартных объектов 1С (таких как ТаблицаЗначений, Структура, Массив) в XML и обратно. Методы: ПрочитатьXML(), ЗаписатьXML().ПреобразованиеXSL: Объект для выполнения XSLT-преобразований. Методы: ЗагрузитьИзСтроки(), ПреобразоватьИзСтроки().Мы выяснили, что универсального "волшебного заклинания" для прямого преобразования произвольного XML в ТаблицуЗначений средствами XDTO, без дополнительной логики или трансформаций, не существует. Механизм СериализаторXDTO требует, чтобы входящий XML соответствовал жестко определенной внутренней схеме 1С для ТаблицыЗначений.
Таким образом, мы имеем два основных рабочих подхода:
ТаблицуЗначений. Это отличный выбор для относительно простых или часто меняющихся XML-структур, где важна простота отладки и понимания логики.Выбор конкретного метода зависит от сложности исходного XML, требований к производительности, квалификации разработчика и предпочтений в читаемости и сопровождаемости кода. В большинстве случаев для типовых задач обмена данными с внешними системами оба метода успешно справляются с поставленной задачей.