Найти в Дзене
yaBTC ya

Чтение произвольного XML средствами XDTO

Как быстро и просто прочитать сколь угодно сложный, произвольный набор данных XML средствами XDTO? Вместо использования многократно вложенных циклов чтения XML с ручным разбором (парсингом) узлов и свойств, намного проще превратить XML в объект нового типа, причем о структуре этого нового типа объекта расскажет сам XML и никаких лишних усилий по созданию схем, написанию какого-то дополнительного программного кода не понадобится. Я бы не стал писать эту заметку, если бы смог найти в сети материал, подсказывающий, как решить поставленную задачу от начала и до конца, без лишних вопросов и проблем. Собственно, я даже не нашел постановки задачи именно в такой формулировке, но считаю, что она вполне актуальна и заслуживает внимания. Итак, имеем произвольный набор данных в виде XML. Файл, который я взял для статьи, я его не придумал. Это настоящий рабочий экспорт из Lotus Notes счетов на оплату. Что меня немного удивило сразу, так это то, что элементы <document> и <item> не объединяются о

Как быстро и просто прочитать сколь угодно сложный, произвольный набор данных XML средствами XDTO? Вместо использования многократно вложенных циклов чтения XML с ручным разбором (парсингом) узлов и свойств, намного проще превратить XML в объект нового типа, причем о структуре этого нового типа объекта расскажет сам XML и никаких лишних усилий по созданию схем, написанию какого-то дополнительного программного кода не понадобится.

Я бы не стал писать эту заметку, если бы смог найти в сети материал, подсказывающий, как решить поставленную задачу от начала и до конца, без лишних вопросов и проблем. Собственно, я даже не нашел постановки задачи именно в такой формулировке, но считаю, что она вполне актуальна и заслуживает внимания.

Итак, имеем произвольный набор данных в виде XML. Файл, который я взял для статьи, я его не придумал. Это настоящий рабочий экспорт из Lotus Notes счетов на оплату. Что меня немного удивило сразу, так это то, что элементы <document> и <item> не объединяются общим узлом, например, <documents> и <items>, и на их уровне присутствуют узлы с другими именами. Но, как оказалось позже, это вовсе не проблема.

Далее, для чтения этого XML средствами XDTO понадобится XSD-схема этого XML. И вот тут у нас первая радость! Ничего вручную делать не нужно. Документ XML вполне самодостаточен для автоматической генерации этой схемы специальными средствами. Такие средства есть, например, в Visual Studio. Просто подаете на вход этого функционала весь XML и получаете схему XSD для этого документа, в которой можно даже не разбираться. Схему сохраняем в отдельный файл с расширением xsd.

Теперь настало время превратить исходный XML в объект данных типа, которого не было, нет, и не будет в 1С. То есть, не будет, пока мы не создадим этот тип фабрикой XDTO.

Я предлагаю не рассматривать решение создания фабрики XDTO в общем виде, как это сделано во многих учебниках, где предлагается схему XSD читать из файла, расположенного на диске. Всем понятно, что такой способ в реальной жизни плохо подходит, поэтому мы сразу сделаем внешнюю обработку, в которой схема станет её неотъемлемой частью и с диска ничего читать не потребуется.

Чтобы поместить схему во внешнюю обработку, в неё нужно добавить макет типа «Двоичные данные» и на предложение выбрать файл данных, указать нашу схемуXSD. Почему я не добавляю новый пакет XDTO в конфигурацию? Да потому, что таким образом заставить её работать у меня не получилось. Оставим этот вопрос за рамками этой статьи.

Далее я все делаю на форме обработки. Первый ключевой момент – создание фабрики XDTO из схемы XDTO. Делается это путем сохранения макета во временный файл и выглядит примерно вот так:

Функция ПолучитьФабрикуИзМакета(ИмяМакета)

ОбъектОбработки = РеквизитФормыВЗначение("Объект");

ДвоичныеДанныеСхемы = ОбъектОбработки.ПолучитьМакет(ИмяМакета);

ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xsd");

ДвоичныеДанныеСхемы.Записать(ИмяВременногоФайла);

Пути = Новый Массив();

Пути.Добавить(ИмяВременногоФайла);

Попытка

Фабрика = СоздатьФабрикуXDTO(Пути);

Исключение

СообщениеПользователю = Новый СообщениеПользователю;

СообщениеПользователю.Текст = ОписаниеОшибки();

СообщениеПользователю.Сообщить();

Возврат Неопределено;

КонецПопытки;

Возврат Фабрика;

КонецФункции

Наверное, это можно написать более изящно, но тут главное понять, что фабрика создается действительно из файла схемы на диске, только мы же предварительно его туда и сохраняем.

Ну, и наконец, решение изначально поставленной задачи. Чтение XML любой сложности сводится к следующим строкам:

ЧтениеХМЛ = Новый ЧтениеXML;

ЧтениеХМЛ.ОткрытьФайл(ПолноеИмяФайла);

Фабрика = ПолучитьФабрикуИзМакета("Схема");

ДанныеХДТО = Фабрика.ПрочитатьXML(ЧтениеХМЛ);

Да. На этом исходый XML полностью прочитан и все его данные находятся в объекте "ДанныеХДТО". Вот как он будет выглядеть в табло отладчика. Элемент <document> превратился в список, то есть в коллекцию объектов XDTO и то же самое произойдет с элементами <item>.И как вы уже догадались, из этого объекта значения всех свойств можно будет легко читать как обычно, через точку, через обход коллекций циклами "Для каждого". В нашем случае, примерно так:

Для каждого Документ из ДанныеХДТО.document Цикл

Для каждого Реквизит из Документ.item Цикл

А это, согласитесь, намного проще и логичнее, чем во много раз вложенных циклах проводить чтение элементов XML, ловить начала элементов по их идентификаторам и далее искать внутри них - другие элементы.

Еще раз отметим, что элементы <document> и <item>, которые изначально вызвали у меня вопрос, самостоятельно стали контейнерами для однотипных объектов своей внутренней структуры и читаются как коллекция в цикле без проблем. Здорово, правда? Всего страница кода и достаточно сложный XML полностью прочитан, и для чтения намного более сложного XML никакого дополнительного кода не понадобится.